Ooops
November 25, 2020, 06:12:59 AM

Author Topic: [bb] 3D line function by Yasha [ 1+ years ago ]  (Read 486 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bb] 3D line function by Yasha [ 1+ years ago ]
« on: June 29, 2017, 12:28:39 AM »
Title : 3D line function
Author : Yasha
Posted : 1+ years ago

Description : This function lets you specify two points in 3D space and draw a line of apparently (ie. from the camera's point of view) constant thickness between them. It works by creating a quad aligned towards the camera, and scaling the ends according to their distance from it. You could use this to simplify any 3D drawing operation that currently uses CameraProject. I find its biggest use to be replicating the GL_LINE functionality (which we don't get in DX) to allow for black outlines on cel-shaded characters, to avoid having to detect obstructions (demo of "cel" outlines will be following shortly. Yay for no more hideous inverted mesh rubbish!).

There can be some minor distortion near the edge of the screen (hopefully not noticeable) due to the camera lens effect. More importantly, these lines do not work properly if one of the points is behind the camera. There is also not currently any provision for checking whether the surface is going to run out of vertices, so try not to go over 16000 lines per frame or so!

The function makes two calls to TFormPoint, but is still reasonably fast. Very loosely based on the Line3D function from Hectic's wonderful Draw3D library.


Code :
Code: BlitzBasic
  1. Global appheight=768
  2. Global appwidth=1024
  3. Global appdepth=32
  4.  
  5. AppTitle "";,"Are you sure you want to quit?"
  6.  
  7. Local SC_FPS=60 ;Desired framerate
  8. Local rtime=Floor(1000.0/SC_FPS)
  9. Local ctime,limited=True
  10. Local FPScount,FPStime,FPSframes
  11.  
  12. Graphics3D appwidth,appheight,appdepth,6
  13. SetBuffer BackBuffer()
  14.  
  15. ;Create an empty scene
  16. Local centrecam=CreatePivot()
  17. PositionEntity centrecam,0,25,0
  18. Local camera=CreateCamera(centrecam)
  19. PositionEntity camera,0,20,-50,1
  20.  
  21. Local sun=CreateLight()
  22. PositionEntity sun,-100,400,0
  23. PointEntity sun,centrecam
  24.  
  25. Local ground=CreateMesh(),tiles=CreateSurface(ground)
  26. Local v1=AddVertex(tiles,-125,0,150),v2=AddVertex(tiles,125,0,150),v3=AddVertex(tiles,125,0,-100)
  27. AddTriangle(tiles,v1,v2,v3):v2=AddVertex(tiles,-125,0,-100):AddTriangle(tiles,v1,v3,v2)
  28. EntityColor ground,0,0,255
  29. Local block=CreateCube():ScaleMesh block,20,5,20
  30.  
  31. Local linemesh=CreateMesh(camera),linesurf=CreateSurface(linemesh)      ;The surface to use to draw the lines - single surface is always faster
  32. ;Adjust the surface's colour here, or add vertex colours to the drawing function as necessary
  33.  
  34. Local marker1=CreateSphere():PositionEntity marker1,-5,15,-5:EntityAlpha marker1,0.3    ;Mark the ends of the line in 3D space
  35. Local marker2=CreateSphere():PositionEntity marker2,5,25,5:EntityAlpha marker2,0.3
  36.  
  37. While Not KeyDown(1)
  38.         ctime=MilliSecs()
  39.        
  40.         MoveEntity camera,0,KeyDown(200)-KeyDown(208),KeyDown(30)-KeyDown(44)
  41.         TurnEntity centrecam,0,KeyDown(203)-KeyDown(205),0
  42.         PointEntity camera,centrecam
  43.         RenderWorld
  44.        
  45.         ClearSurface linesurf   ;If you redraw each frame as with standard drawing commands
  46.         Draw3DLine(camera,linesurf,-5,15,-5,5,25,5,4)
  47.        
  48.         If MilliSecs()-FPStime=>1000 Then FPScount=FPSframes:FPSframes=0:FPStime=MilliSecs():Else FPSframes=FPSframes+1
  49.         Text 0,30,"FPS: "+FPScount
  50.         Text 0,60,"Arrow keys to turn camera, A and Z to zoom"
  51.        
  52.         Delay (rtime-(MilliSecs()-ctime))-(limited+1)           ;Free spare CPU time
  53.         Flip limited
  54. Wend
  55.  
  56. End
  57.  
  58.  
  59. Function Draw3DLine(camera,surf,x1#,y1#,z1#,x2#,y2#,z2#,thickness#=1,entity=0)  ;If entity is not 0, points refer to an entity's local space
  60.         TFormPoint x1,y1,z1,entity,camera
  61.         x1=TFormedX()
  62.         y1=TFormedY()
  63.         z1=TFormedZ()
  64.         Local d1#=Sqr(x1*x1+y1*y1+z1*z1)/GraphicsWidth()
  65.         TFormPoint x2,y2,z2,entity,camera
  66.         x2=TFormedX()
  67.         y2=TFormedY()
  68.         z2=TFormedZ()
  69.         Local d2#=Sqr(x2*x2+y2*y2+z2*z2)/GraphicsWidth()
  70.        
  71.         Local theta#=ATan2(y2*(d1/d2)-y1,x2*(d1/d2)-x1)
  72.         Local xTForm#=Cos(theta)*thickness
  73.         Local yTForm#=Sin(theta)*thickness
  74.        
  75.         Local V0=AddVertex(surf,x1+yTForm*d1,y1-xTForm*d1,z1)
  76.         Local V1=AddVertex(surf,x1-yTForm*d1,y1+xTForm*d1,z1)
  77.         Local V2=AddVertex(surf,x2-yTForm*d2,y2+xTForm*d2,z2)
  78.         Local V3=AddVertex(surf,x2+yTForm*d2,y2-xTForm*d2,z2)
  79.        
  80.         AddTriangle(surf,V0,V1,V2)
  81.         AddTriangle(surf,V2,V3,V0)
  82. End Function


Comments :


ZJP(Posted 1+ years ago)

 Nice works ;)But, how to change the color of the line?JP


Yasha(Posted 1+ years ago)

 Personally I'm just using EntityColor linemesh,r,g,b after creating the mesh. If you want the different segments to be different colours, you could pass the colour as extra parameters to Draw3DLine, then apply VertexColor to the four verts that are created. For this the linemesh entity needs to have EntityFX set to 2.


ZJP(Posted 1+ years ago)

 Sorry. I have only black lines. :(


Yasha(Posted 1+ years ago)

 This (altered line 32):
Code: [Select]
Global appheight=768
Global appwidth=1024
Global appdepth=32

AppTitle "";,"Are you sure you want to quit?"

Local SC_FPS=60 ;Desired framerate
Local rtime=Floor(1000.0/SC_FPS)
Local ctime,limited=True
Local FPScount,FPStime,FPSframes

Graphics3D appwidth,appheight,appdepth,6
SetBuffer BackBuffer()

;Create an empty scene
Local centrecam=CreatePivot()
PositionEntity centrecam,0,25,0
Local camera=CreateCamera(centrecam)
PositionEntity camera,0,20,-50,1

Local sun=CreateLight()
PositionEntity sun,-100,400,0
PointEntity sun,centrecam

Local ground=CreateMesh(),tiles=CreateSurface(ground)
Local v1=AddVertex(tiles,-125,0,150),v2=AddVertex(tiles,125,0,150),v3=AddVertex(tiles,125,0,-100)
AddTriangle(tiles,v1,v2,v3):v2=AddVertex(tiles,-125,0,-100):AddTriangle(tiles,v1,v3,v2)
EntityColor ground,0,0,255
Local block=CreateCube():ScaleMesh block,20,5,20

Local linemesh=CreateMesh(camera),linesurf=CreateSurface(linemesh) ;The surface to use to draw the lines - single surface is always faster
EntityColor linemesh,255,0,0:EntityFX linemesh,1

Local marker1=CreateSphere():PositionEntity marker1,-5,15,-5:EntityAlpha marker1,0.3 ;Mark the ends of the line in 3D space
Local marker2=CreateSphere():PositionEntity marker2,5,25,5:EntityAlpha marker2,0.3

While Not KeyDown(1)
ctime=MilliSecs()

MoveEntity camera,0,KeyDown(200)-KeyDown(208),KeyDown(30)-KeyDown(44)
TurnEntity centrecam,0,KeyDown(203)-KeyDown(205),0
PointEntity camera,centrecam
RenderWorld

ClearSurface linesurf ;If you redraw each frame as with standard drawing commands
Draw3DLine(camera,linesurf,-5,15,-5,5,25,5,4)

If MilliSecs()-FPStime=>1000 Then FPScount=FPSframes:FPSframes=0:FPStime=MilliSecs():Else FPSframes=FPSframes+1
Text 0,30,"FPS: "+FPScount
Text 0,60,"Arrow keys to turn camera, A and Z to zoom"

Delay (rtime-(MilliSecs()-ctime))-(limited+1) ;Free spare CPU time
Flip limited
Wend

End


Function Draw3DLine(camera,surf,x1#,y1#,z1#,x2#,y2#,z2#,thickness#=1,entity=0) ;If entity is not 0, points refer to an entity's local space
TFormPoint x1,y1,z1,entity,camera
x1=TFormedX()
y1=TFormedY()
z1=TFormedZ()
Local d1#=Sqr(x1*x1+y1*y1+z1*z1)/GraphicsWidth()
TFormPoint x2,y2,z2,entity,camera
x2=TFormedX()
y2=TFormedY()
z2=TFormedZ()
Local d2#=Sqr(x2*x2+y2*y2+z2*z2)/GraphicsWidth()

Local theta#=ATan2(y2*(d1/d2)-y1,x2*(d1/d2)-x1)
Local xTForm#=Cos(theta)*thickness
Local yTForm#=Sin(theta)*thickness

Local V0=AddVertex(surf,x1+yTForm*d1,y1-xTForm*d1,z1)
Local V1=AddVertex(surf,x1-yTForm*d1,y1+xTForm*d1,z1)
Local V2=AddVertex(surf,x2-yTForm*d2,y2+xTForm*d2,z2)
Local V3=AddVertex(surf,x2+yTForm*d2,y2-xTForm*d2,z2)

AddTriangle(surf,V0,V1,V2)
AddTriangle(surf,V2,V3,V0)
End Function
...gives me a red line.This (different, altering line 32 and function parameters):
Code: [Select]
Global appheight=768
Global appwidth=1024
Global appdepth=32

AppTitle "";,"Are you sure you want to quit?"

Local SC_FPS=60 ;Desired framerate
Local rtime=Floor(1000.0/SC_FPS)
Local ctime,limited=True
Local FPScount,FPStime,FPSframes

Graphics3D appwidth,appheight,appdepth,6
SetBuffer BackBuffer()

;Create an empty scene
Local centrecam=CreatePivot()
PositionEntity centrecam,0,25,0
Local camera=CreateCamera(centrecam)
PositionEntity camera,0,20,-50,1

Local sun=CreateLight()
PositionEntity sun,-100,400,0
PointEntity sun,centrecam

Local ground=CreateMesh(),tiles=CreateSurface(ground)
Local v1=AddVertex(tiles,-125,0,150),v2=AddVertex(tiles,125,0,150),v3=AddVertex(tiles,125,0,-100)
AddTriangle(tiles,v1,v2,v3):v2=AddVertex(tiles,-125,0,-100):AddTriangle(tiles,v1,v3,v2)
EntityColor ground,0,0,255
Local block=CreateCube():ScaleMesh block,20,5,20

Local linemesh=CreateMesh(camera),linesurf=CreateSurface(linemesh) ;The surface to use to draw the lines - single surface is always faster
EntityFX linemesh,1+2

Local marker1=CreateSphere():PositionEntity marker1,-5,15,-5:EntityAlpha marker1,0.3 ;Mark the ends of the line in 3D space
Local marker2=CreateSphere():PositionEntity marker2,5,25,5:EntityAlpha marker2,0.3

While Not KeyDown(1)
ctime=MilliSecs()

MoveEntity camera,0,KeyDown(200)-KeyDown(208),KeyDown(30)-KeyDown(44)
TurnEntity centrecam,0,KeyDown(203)-KeyDown(205),0
PointEntity camera,centrecam
RenderWorld

ClearSurface linesurf ;If you redraw each frame as with standard drawing commands
Draw3DLine(camera,linesurf,-5,15,-5,5,25,5,4,0,255,0,0)
Draw3DLine(camera,linesurf,5,15,5,-5,25,-5,4,0,0,0,255)
Draw3DLine(camera,linesurf,-5,15,5,5,25,-5,4,0,0,255,0)
Draw3DLine(camera,linesurf,5,15,-5,-5,25,5,4,0,0,0,0)

If MilliSecs()-FPStime=>1000 Then FPScount=FPSframes:FPSframes=0:FPStime=MilliSecs():Else FPSframes=FPSframes+1
Text 0,30,"FPS: "+FPScount
Text 0,60,"Arrow keys to turn camera, A and Z to zoom"

Delay (rtime-(MilliSecs()-ctime))-(limited+1) ;Free spare CPU time
Flip limited
Wend

End


Function Draw3DLine(camera,surf,x1#,y1#,z1#,x2#,y2#,z2#,thickness#=1,entity=0,colR=0,colG=0,colB=0) ;If entity is not 0, points refer to an entity's local space
TFormPoint x1,y1,z1,entity,camera
x1=TFormedX()
y1=TFormedY()
z1=TFormedZ()
Local d1#=Sqr(x1*x1+y1*y1+z1*z1)/GraphicsWidth()
TFormPoint x2,y2,z2,entity,camera
x2=TFormedX()
y2=TFormedY()
z2=TFormedZ()
Local d2#=Sqr(x2*x2+y2*y2+z2*z2)/GraphicsWidth()

Local theta#=ATan2(y2*(d1/d2)-y1,x2*(d1/d2)-x1)
Local xTForm#=Cos(theta)*thickness
Local yTForm#=Sin(theta)*thickness

Local V0=AddVertex(surf,x1+yTForm*d1,y1-xTForm*d1,z1)
Local V1=AddVertex(surf,x1-yTForm*d1,y1+xTForm*d1,z1)
Local V2=AddVertex(surf,x2-yTForm*d2,y2+xTForm*d2,z2)
Local V3=AddVertex(surf,x2+yTForm*d2,y2-xTForm*d2,z2)

VertexColor surf,V0,colR,colG,colB
VertexColor surf,V1,colR,colG,colB
VertexColor surf,V2,colR,colG,colB
VertexColor surf,V3,colR,colG,colB

AddTriangle(surf,V0,V1,V2)
AddTriangle(surf,V2,V3,V0)
End Function
...gives me multi-coloured lines.Do these work on your machine?


ZJP(Posted 1+ years ago)

 Oh Yesssss !!!!!.ThxJP


Blitzplotter(Posted 1+ years ago)

 This I Like lots....made a slight attempt at evolving that (obviously) requires more work:-
Code: [Select]

;list where from originally, its only right!
;http://www.blitzbasic.com/codearcs/codearcs.php?code=2590#comments


Global appheight=768
Global appwidth=1024
Global appdepth=32

AppTitle "";,"Are you sure you want to quit?"

Local SC_FPS=60 ;Desired framerate
Local rtime=Floor(1000.0/SC_FPS)
Local ctime,limited=True
Local FPScount,FPStime,FPSframes

Graphics3D appwidth,appheight,appdepth,6
SetBuffer BackBuffer()

;Create an empty scene
Local centrecam=CreatePivot()
PositionEntity centrecam,0,25,0
Local camera=CreateCamera(centrecam)
PositionEntity camera,0,20,-50,1

Local sun=CreateLight()
PositionEntity sun,-100,400,0
PointEntity sun,centrecam

Local ground=CreateMesh(),tiles=CreateSurface(ground)
Local v1=AddVertex(tiles,-125,0,150),v2=AddVertex(tiles,125,0,150),v3=AddVertex(tiles,125,0,-100)
AddTriangle(tiles,v1,v2,v3):v2=AddVertex(tiles,-125,0,-100):AddTriangle(tiles,v1,v3,v2)
EntityColor ground,0,0,255
Local block=CreateCube():ScaleMesh block,20,5,20

Local linemesh=CreateMesh(camera),linesurf=CreateSurface(linemesh) ;The surface to use to draw the lines - single surface is always faster
;Adjust the surface's colour here, or add vertex colours to the drawing function as necessary

Local marker1=CreateSphere():PositionEntity marker1,-5,15,-5:EntityAlpha marker1,0.3 ;Mark the ends of the line in 3D space
Local marker2=CreateSphere():PositionEntity marker2,5,25,5:EntityAlpha marker2,0.3

;my marker

Local marker3=CreateSphere():PositionEntity marker3,5,35,15:EntityAlpha marker3,0.3

;three markers in a loop

Global extrapoints=10
Global threedgap = 9
Dim marker(4)

For create3 = 1 To extrapoints

Local how_far_apart = 5

theNew=(threedgap*create3)

;theNew=create3

;Local marker(create3)=CreateSphere()
Local marker4=CreateSphere():PositionEntity marker4,5+theNew,35+theNew,15+theNew:EntityAlpha marker4,0.3

;Local marker5=CreateSphere():PositionEntity marker4,5+theNew,35+theNew,15+theNew:EntityAlpha marker4,0.3

;Local marker6=CreateSphere():PositionEntity marker4,5+theNew,35+theNew,15+theNew:EntityAlpha marker4,0.3

;### following was an attempt....

;PositionEntity marker(create3),5,35,15:EntityAlpha marker(create3),0.3
;Local marker4=CreateSphere():PositionEntity marker4,5,35,15:EntityAlpha marker4,0.3

Next

extrapints=9

For create4 = 1 To extrapints

Local threedgap2 = -7

theNew=(threedgap2*create4)

;theNew=create3

;Local marker(create3)=CreateSphere()
Local marker5=CreateSphere():PositionEntity marker5,5+theNew,35+theNew,15:EntityAlpha marker4,0.3

;Local marker5=CreateSphere():PositionEntity marker4,5+theNew,35+theNew,15+theNew:EntityAlpha marker4,0.3

;Local marker6=CreateSphere():PositionEntity marker4,5+theNew,35+theNew,15+theNew:EntityAlpha marker4,0.3

;### following was an attempt....

;PositionEntity marker(create3),5,35,15:EntityAlpha marker(create3),0.3
;Local marker4=CreateSphere():PositionEntity marker4,5,35,15:EntityAlpha marker4,0.3

Next




While Not KeyDown(1)
ctime=MilliSecs()

MoveEntity camera,0,KeyDown(200)-KeyDown(208),KeyDown(30)-KeyDown(44)
TurnEntity centrecam,0,KeyDown(203)-KeyDown(205),0
PointEntity camera,centrecam
RenderWorld

ClearSurface linesurf ;If you redraw each frame as with standard drawing commands
Draw3DLine(camera,linesurf,-5,15,-5,5,25,5,4)

;introducing the third point
Draw3DLine(camera,linesurf,5,25,5,5,35,15,4)

;;iterating through the others:-
For only3 = 1 To extrapoints
theLast=(threedgap*(only3-1))
theNew=(threedgap*only3)
;unfortunately this produces a linear thing at the mo, nevertheless - it works

Draw3DLine(camera,linesurf,5+theLast,35+theLast,15+theLast,5+theNew,35+theNew,15+theNew,4)
Next


If MilliSecs()-FPStime=>1000 Then FPScount=FPSframes:FPSframes=0:FPStime=MilliSecs():Else FPSframes=FPSframes+1
Text 0,30,"FPS: "+FPScount
Text 0,60,"Arrow keys to turn camera, A and Z to zoom"

Delay (rtime-(MilliSecs()-ctime))-(limited+1) ;Free spare CPU time
Flip limited
Wend

End


Function Draw3DLine(camera,surf,x1#,y1#,z1#,x2#,y2#,z2#,thickness#=1,entity=0) ;If entity is not 0, points refer to an entity's local space
TFormPoint x1,y1,z1,entity,camera
x1=TFormedX()
y1=TFormedY()
z1=TFormedZ()
Local d1#=Sqr(x1*x1+y1*y1+z1*z1)/GraphicsWidth()
TFormPoint x2,y2,z2,entity,camera
x2=TFormedX()
y2=TFormedY()
z2=TFormedZ()
Local d2#=Sqr(x2*x2+y2*y2+z2*z2)/GraphicsWidth()

Local theta#=ATan2(y2*(d1/d2)-y1,x2*(d1/d2)-x1)
Local xTForm#=Cos(theta)*thickness
Local yTForm#=Sin(theta)*thickness

Local V0=AddVertex(surf,x1+yTForm*d1,y1-xTForm*d1,z1)
Local V1=AddVertex(surf,x1-yTForm*d1,y1+xTForm*d1,z1)
Local V2=AddVertex(surf,x2-yTForm*d2,y2+xTForm*d2,z2)
Local V3=AddVertex(surf,x2+yTForm*d2,y2-xTForm*d2,z2)

AddTriangle(surf,V0,V1,V2)
AddTriangle(surf,V2,V3,V0)
End Function



 

SimplePortal 2.3.6 © 2008-2014, SimplePortal