Ooops
October 28, 2020, 06:07:45 AM

Author Topic: [bb] PickedUV / Move texture with mouse by Noobody [ 1+ years ago ]  (Read 2453 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
Title : PickedUV / Move texture with mouse
Author : Noobody
Posted : 1+ years ago

Description : Since B3D doesn't have functions for the UV coordinates at the intersection point of CameraPick/LinePick/etc. I wrote a function to do this. It works by first making a local 2D orthonormal coordinate system on the triangle and then converting the picked location to barycentric coordinates, allowing interpolation of UV coordinates within the triangle.

The sample code shows an application of this function by allowing the user to move a texture on a mesh using the mouse. The texel clicked by the user always stays at the mouse position, while the rest of the texture is moved around on the mesh (useful for editors, maybe?)


Code :
Code: BlitzBasic
  1. Graphics3D 800, 600, 0, 2
  2. SetBuffer BackBuffer()
  3.  
  4. Global PickedU#, PickedV#
  5.  
  6.  
  7. Local Cam = CreateCamera()
  8. Local Texture = CreateFunkyTexture()
  9. Local Mesh = CreateCone(64)
  10. EntityPickMode Mesh, 2
  11. EntityTexture Mesh, Texture
  12.  
  13. MoveEntity Cam, 0.0, 0.0, -3.0
  14.  
  15. Local Timer = CreateTimer(60)
  16.  
  17. Local OldPickedU#, OldPickedV#, OldPickedSurface
  18.  
  19. While Not KeyHit(1)
  20.         TurnEntity Mesh, KeyDown(200) - KeyDown(208), KeyDown(205) - KeyDown(203), 0.0, True
  21.        
  22.         If MouseDown(1) Then
  23.                 CameraPick(Cam, MouseX(), MouseY())
  24.                
  25.                 If PickedEntity() <> 0 And PickedSurface() <> 0 Then
  26.                         CalculatePickedUV()
  27.                        
  28.                         If PickedSurface() = OldPickedSurface Then
  29.                                 DU# = PickedU# - OldPickedU#
  30.                                 DV# = PickedV# - OldPickedV#
  31.                                
  32.                                 Local Surface = PickedSurface()
  33.                                 For Vertex = 0 To CountVertices(Surface) - 1
  34.                                         Local U# = VertexU(Surface, Vertex)
  35.                                         Local V# = VertexV(Surface, Vertex)
  36.                                        
  37.                                         VertexTexCoords Surface, Vertex, U# - DU#, V# - DV#
  38.                                 Next
  39.                                
  40.                                 PickedU# = PickedU# - DU#
  41.                                 PickedV# = PickedV# - DV#
  42.                         Else
  43.                                 OldPickedSurface = PickedSurface()
  44.                         EndIf
  45.                        
  46.                         OldPickedU# = PickedU#
  47.                         OldPickedV# = PickedV#
  48.                 Else
  49.                         OldPickedSurface = 0
  50.                 EndIf
  51.         Else
  52.                 OldPickedSurface = 0
  53.         EndIf
  54.        
  55.         RenderWorld
  56.        
  57.         Text 0, 0, "Click and drag the texture!"
  58.         Text 0, 15, "Use arrow keys to turn the mesh"
  59.        
  60.         Flip 0
  61.         WaitTimer Timer
  62. Wend
  63. End
  64.  
  65. Function CreateFunkyTexture()
  66.         Local Texture = CreateTexture(256, 256, 1)
  67.        
  68.         SetBuffer TextureBuffer(Texture)
  69.         LockBuffer()
  70.        
  71.         For X = 0 To 255
  72.                 For Y = 0 To 255
  73.                         WritePixelFast X, Y, (X*$010001) Xor (Y*$010101)
  74.                 Next
  75.         Next
  76.        
  77.         UnlockBuffer()
  78.         SetBuffer BackBuffer()
  79.        
  80.         Return Texture
  81. End Function
  82.  
  83. Function CalculatePickedUV()
  84.         Local Surface = PickedSurface()
  85.         If Surface Then
  86.                 Local Mesh = PickedEntity()
  87.                
  88.                 TFormPoint PickedX(), PickedY(), PickedZ(), 0, Mesh
  89.                
  90.                 Local Triangle = PickedTriangle()
  91.                
  92.                 Local V1 = TriangleVertex(Surface, Triangle, 0)
  93.                 Local V2 = TriangleVertex(Surface, Triangle, 1)
  94.                 Local V3 = TriangleVertex(Surface, Triangle, 2)
  95.                
  96.                 Local DX1# = VertexX(Surface, V2) - VertexX(Surface, V1)
  97.                 Local DY1# = VertexY(Surface, V2) - VertexY(Surface, V1)
  98.                 Local DZ1# = VertexZ(Surface, V2) - VertexZ(Surface, V1)
  99.                 Local DX2# = VertexX(Surface, V3) - VertexX(Surface, V1)
  100.                 Local DY2# = VertexY(Surface, V3) - VertexY(Surface, V1)
  101.                 Local DZ2# = VertexZ(Surface, V3) - VertexZ(Surface, V1)
  102.                
  103.                 Local NX# = DY1#*DZ2# - DY2#*DZ1#
  104.                 Local NY# = DX2#*DZ1# - DX1#*DZ2#
  105.                 Local NZ# = DX1#*DY2# - DY1#*DX2#
  106.                 Local UX# = NY #*DZ2# - DY2#*NZ #
  107.                 Local UY# = DX2#*NZ # - NX #*DZ2#
  108.                 Local UZ# = NX #*DY2# - NY #*DX2#
  109.                
  110.                 Local InvLength1# = 1.0/Sqr(UX#*UX# + UY#*UY# + UZ#*UZ#)
  111.                 Local Length2# = Sqr(DX2#*DX2# + DY2#*DY2# + DZ2#*DZ2#)
  112.                 Local InvLength2# = 1.0/Length2#
  113.                
  114.                 UX# = UX#*InvLength1#
  115.                 UY# = UY#*InvLength1#
  116.                 UZ# = UZ#*InvLength1#
  117.                 DX2# = DX2#*InvLength2#
  118.                 DY2# = DY2#*InvLength2#
  119.                 DZ2# = DZ2#*InvLength2#
  120.                
  121.                 Local T1# = 0.0
  122.                 Local S1# = 0.0
  123.                 Local T2# = DX1#*UX # + DY1#*UY # + DZ1#*UZ #
  124.                 Local S2# = DX1#*DX2# + DY1#*DY2# + DZ1#*DZ2#
  125.                 Local T3# = 0.0
  126.                 Local S3# = Length2#
  127.                 Local T4# = (TFormedX() - VertexX(Surface, V1))*UX # + (TFormedY() - VertexY(Surface, V1))*UY # + (TFormedZ() - VertexZ(Surface, V1))*UZ #
  128.                 Local S4# = (TFormedX() - VertexX(Surface, V1))*DX2# + (TFormedY() - VertexY(Surface, V1))*DY2# + (TFormedZ() - VertexZ(Surface, V1))*DZ2#
  129.  
  130.                
  131.                 Local Denominator# = 1.0/((S2# - S3#)*(T1# - T3#) + (T3# - T2#)*(S1# - S3#))
  132.                 Local Lambda1# = ((S2# - S3#)*(T4# - T3#) + (T3# - T2#)*(S4# - S3#))*Denominator#
  133.                 Local Lambda2# = ((S3# - S1#)*(T4# - T3#) + (T1# - T3#)*(S4# - S3#))*Denominator#
  134.                 Local Lambda3# = 1.0 - Lambda1# - Lambda2#
  135.                
  136.                 PickedU# = VertexU(Surface, V1)*Lambda1# + VertexU(Surface, V2)*Lambda2# + VertexU(Surface, V3)*Lambda3#
  137.                 PickedV# = VertexV(Surface, V1)*Lambda1# + VertexV(Surface, V2)*Lambda2# + VertexV(Surface, V3)*Lambda3#
  138.         EndIf
  139. End Function


Comments :


Kryzon(Posted 1+ years ago)

 Thanks for sharing, it looks great!Further references:Fredborg also wrote PickedUVW() style functions: <a href="codearcsc667.html?code=515" target="_blank">http://blitzbasic.com/codearcs/codearcs.php?code=515[/url]You can also find something similar inside Blitz3DsamplesirdieTexPaint (if I got the author's name right.)


Noobody(Posted 1+ years ago)

 Oh, I wasn't aware of either of them, thanks for mentioning :)The other PickedU/V/W functions from the codearchives take a bit more code, but seem to work great! Replacing the PickedUV in this example with the code you linked gives the exact same behaviour.The one from the birdie sample does the job as well, although it uses CameraProject, which is something I wanted to avoid; values get very inaccurate when parts of the triangle are off-screen or behind the camera.


BlitzSupport(Posted 1+ years ago)

 Nice one!


Charrua(Posted 1+ years ago)

 thank's so muchJuan


void(Posted 1+ years ago)

 Much thanks


Mikorians(Posted 1+ years ago)

 Oooh yeah...!!!


Offline RemiD

  • Hero Member
  • *****
  • Posts: 1065
Re: [bb] PickedUV / Move texture with mouse by Noobody [ 1+ years ago ]
« Reply #1 on: November 24, 2018, 04:55:12 PM »
hello,

little addon to what our friend Noobody posted, (PickedU, PickedV)
to demonstrate how to calculate the picked texel position X,Y (on the texture) ( PickedTX, PickedTY )
with a demo
Code: [Select]
;PickedU,PickedV with mouse by Noobody
;PickedTX,PickedTY addon by RemiD
;calculates the picked U,V with some math wizardry (by Noobody)
;once the U,V ( PickedU PickedV ) of the picked point is determined, we can calculate the position X,Y of the picked texel ( PickedTX, PickedTY )
Graphics3D(800,600,32,2)

SeedRnd(MilliSecs())

Global PickedU#, PickedV# ;picked U,V
Global PickedTX%, PickedTY% ;picked texel X,Y

Local Cam = CreateCamera()
CameraRange(Cam,0.1,100)
CameraClsColor(Cam,025,025,025)

Local Texture = CreateTexture(64,64,1)
SetBuffer(TextureBuffer(Texture))
ClsColor(250,250,250) : Cls()
;outline of the texture
Color(125,125,125) : Line(0,0,64-1,0)
Color(125,125,125) : Line(0,64-1,64-1,64-1)
Color(125,125,125) : Line(0,0,0,64-1)
Color(125,125,125) : Line(64-1,0,64-1,64-1)
;corner top left (red texel)
Color(255,000,000) : Plot(0,0)
;corner top right (green texel)
Color(000,255,000) : Plot(64-1,0)
;corner bottom left (blue texel)
Color(000,000,255) : Plot(0,64-1)
;corner bottom right (white texel)
Color(255,255,255) : Plot(64-1,64-1)
;some text
Color(025,025,025) : TStr$ = "Noobody" : TX% = TextureWidth(Texture)/2-StringWidth(TStr)/2 : TY% = TextureHeight(Texture)/2-StringHeight(TStr)/2 : Text(TX,TY,TStr)

Local Mesh = CreateCube()
EntityTexture(Mesh,Texture)
RotateEntity(Mesh,0,Rand(-180,180),0,True)
EntityPickMode(Mesh,2)

PositionEntity(Cam,0,1.65,-3.0)
RotateEntity(Cam,22.5,0,0)

While Not KeyDown(1)

 If( KeyDown(200)=1 )
  TurnEntity(Mesh,+1,0,0)
 Else If( KeyDown(208)=1 )
  TurnEntity(Mesh,-1,0,0)
 EndIf
 If( KeyDown(203)=1 )
  TurnEntity(Mesh,0,-1,0)
 Else If( KeyDown(205)=1 )
  TurnEntity(Mesh,0,+1,0)
 EndIf

 If( MouseDown(1)=1 )
  CameraPick(Cam, MouseX(), MouseY())
  If( PickedEntity() <> 0 And PickedSurface() <> 0 )
   CalculatePickedUVvNoobody() ;by Noobody
   PickedTX% = TextureWidth(Texture)*PickedU : PickedTY% = TextureHeight(Texture)*PickedV
   DebugLog(PickedU+","+PickedV+"->"+PickedTX+","+PickedTY)
   SetBuffer(TextureBuffer(Texture))
   Color(255,000,255) : Plot(PickedTX,PickedTY)
  EndIf
 EndIf

 SetBuffer(BackBuffer())
 RenderWorld()

 Color(255,255,255)
 Text(0,0,"Mouse Left to pick / color texels on the texture")
 Text(0,16,"Arrows to turn the shape up, down, left, right")

 Flip(True)

Wend

End()

Function CalculatePickedUVvNoobody()
;it works by first making a local 2D orthonormal coordinate system on the triangle, and then converting the picked location to barycentric coordinates, allowing interpolation of UV coordinates within the triangle.
Local Surface = PickedSurface()

If Surface Then

Local Mesh = PickedEntity()

TFormPoint PickedX(), PickedY(), PickedZ(), 0, Mesh

Local Triangle = PickedTriangle()

Local V1 = TriangleVertex(Surface, Triangle, 0)
Local V2 = TriangleVertex(Surface, Triangle, 1)
Local V3 = TriangleVertex(Surface, Triangle, 2)

Local DX1# = VertexX(Surface, V2) - VertexX(Surface, V1)
Local DY1# = VertexY(Surface, V2) - VertexY(Surface, V1)
Local DZ1# = VertexZ(Surface, V2) - VertexZ(Surface, V1)
Local DX2# = VertexX(Surface, V3) - VertexX(Surface, V1)
Local DY2# = VertexY(Surface, V3) - VertexY(Surface, V1)
Local DZ2# = VertexZ(Surface, V3) - VertexZ(Surface, V1)

Local NX# = DY1#*DZ2# - DY2#*DZ1#
Local NY# = DX2#*DZ1# - DX1#*DZ2#
Local NZ# = DX1#*DY2# - DY1#*DX2#
Local UX# = NY #*DZ2# - DY2#*NZ #
Local UY# = DX2#*NZ # - NX #*DZ2#
Local UZ# = NX #*DY2# - NY #*DX2#

Local InvLength1# = 1.0/Sqr(UX#*UX# + UY#*UY# + UZ#*UZ#)
Local Length2# = Sqr(DX2#*DX2# + DY2#*DY2# + DZ2#*DZ2#)
Local InvLength2# = 1.0/Length2#

UX# = UX#*InvLength1#
UY# = UY#*InvLength1#
UZ# = UZ#*InvLength1#
DX2# = DX2#*InvLength2#
DY2# = DY2#*InvLength2#
DZ2# = DZ2#*InvLength2#

Local T1# = 0.0
Local S1# = 0.0
Local T2# = DX1#*UX # + DY1#*UY # + DZ1#*UZ #
Local S2# = DX1#*DX2# + DY1#*DY2# + DZ1#*DZ2#
Local T3# = 0.0
Local S3# = Length2#
Local T4# = (TFormedX() - VertexX(Surface, V1))*UX# + (TFormedY() - VertexY(Surface, V1))*UY# + (TFormedZ() - VertexZ(Surface, V1))*UZ#
Local S4# = (TFormedX() - VertexX(Surface, V1))*DX2# + (TFormedY() - VertexY(Surface, V1))*DY2# + (TFormedZ() - VertexZ(Surface, V1))*DZ2#

Local Denominator# = 1.0/((S2# - S3#)*(T1# - T3#) + (T3# - T2#)*(S1# - S3#))
Local Lambda1# = ((S2# - S3#)*(T4# - T3#) + (T3# - T2#)*(S4# - S3#))*Denominator#
Local Lambda2# = ((S3# - S1#)*(T4# - T3#) + (T1# - T3#)*(S4# - S3#))*Denominator#
Local Lambda3# = 1.0 - Lambda1# - Lambda2#

PickedU# = VertexU(Surface, V1)*Lambda1# + VertexU(Surface, V2)*Lambda2# + VertexU(Surface, V3)*Lambda3#
PickedV# = VertexV(Surface, V1)*Lambda1# + VertexV(Surface, V2)*Lambda2# + VertexV(Surface, V3)*Lambda3#

EndIf

End Function
Thanks again to Noobody
DualCore AMD E-450, 1646 MHz - 6 Go DDR3 1333 SDRAM - AMD Radeon HD 6320 Graphics (384 Mo) - Windows 7 Home Premium - DirectX 11.0

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal