Code archives/3D Graphics - Effects/3D line function

This code has been declared by its author to be Public Domain code.

Download source code

3D line function by Yasha2009
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.
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

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

Comments

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

JP


Yasha2009
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.


ZJP2009
Sorry. I have only black lines. :(


Yasha2009
This (altered line 32):


...gives me a red line.

This (different, altering line 32 and function parameters):

...gives me multi-coloured lines.

Do these work on your machine?


ZJP2009
Oh Yesssss !!!!!.
Thx

JP


Blitzplotter2010
This I Like lots....

made a slight attempt at evolving that (obviously) requires more work:-







Code Archives Forum