I've just been playing around with the idea of drawing lines. . .
So far I've just been drawing all edges on front facing triangles and so haven't needed to compile the list of edges etc. There does seem to be a perfomance hit, but only when you start drawing more than a few hundred lines.
It seems that the number of lines actually drawn is the main factor on performance, not the size of the mesh you perform the operation to (commenting out the Line statements proves this)
Here's the code:
Graphics3D 800, 600
Global mshSphere% = CreateSphere(12)
UpdateNormals mshSphere
EntityFX mshSphere, 4
Global GlobalLight% = CreateLight()
RotateEntity GlobalLight, 45, 45, 45
Global GlobalCamera% = CreateCamera()
PositionEntity GlobalCamera, 4, 2, 4
PointEntity GlobalCamera, mshSphere
CameraClsColor GlobalCamera, 180,180,180
Local fps%
Local fpscount%
Local millistop%
Local millis%
While Not KeyHit(1)
Navigate_World_With_MouseAndKeys(0.5, 0.1)
TurnEntity mshSphere, 0, 0.5, 0
SetBuffer BackBuffer()
Cls
RenderWorld()
DrawFrontFacingLines(mshSphere, GlobalCamera, 0, 0)
Color 255, 0, 0
Text 1, 1, "FPS=" + fps
Text 1, 12, "TrisRendered=" + TrisRendered()
Flip
fpscount = fpscount + 1
millis% = MilliSecs()
If millistop < millis - 1000 Then
millistop = millis
fps = fpscount
fpscount = 0
End If
Wend
End
Function DrawFrontFacingLines(m%, cam, thick%, sketchy#)
Color 30, 30, 50
Local v3X = CreateVector(3)
Local v3Y = CreateVector(3)
For is% = 1 To CountSurfaces(m)
s% = GetSurface(m, is)
For it% = 0 To CountTriangles(s) - 1
If FrontFacing(cam, s, it, m) Then
For i% = 0 To 2
vx# = VertexX(s, TriangleVertex(s, it, i))
vy# = VertexY(s, TriangleVertex(s, it, i))
vz# = VertexZ(s, TriangleVertex(s, it, i))
TFormPoint vx, vy, vz, m, 0
vx = TFormedX()
vy = TFormedY()
vz = TFormedZ()
CameraProject(cam, vx, vy, vz)
VctPut v3X, i, ProjectedX()
VctPut v3Y, i, ProjectedY()
Next
c0 = (VctGet(v3X,0)=0) And (VctGet(v3Y,0)=0)
c1 = (VctGet(v3X,1)=0) And (VctGet(v3Y,1)=0)
c2 = (VctGet(v3X,2)=0) And (VctGet(v3Y,2)=0)
For n% = -thick To thick
r# = sketchy
If Not (c0 Or c1) Then Line VctGet(v3X,0)+n+Rnd(-r, r), VctGet(v3Y,0)+Rnd(-r, r), VctGet(v3X,1)+Rnd(-r, r), VctGet(v3Y,1)+Rnd(-r, r)
If Not (c1 Or c2) Then Line VctGet(v3X,1)+n+Rnd(-r, r), VctGet(v3Y,1)+Rnd(-r, r), VctGet(v3X,2)+n+Rnd(-r, r), VctGet(v3Y,2)+Rnd(-r, r)
If Not (c0 Or c2) Then Line VctGet(v3X,0)+n+Rnd(-r, r), VctGet(v3Y,0)+Rnd(-r, r), VctGet(v3X,2)+n+Rnd(-r, r), VctGet(v3Y,2)+Rnd(-r, r)
Next
End If
Next
Next
DeleteVector v3X
DeleteVector v3Y
End Function
Function Navigate_World_With_MouseAndKeys(turnSpeed#=1, moveSpeed#=1)
Local dY# = EntityPitch(GlobalCamera)+MouseYSpeed()/2*turnSpeed
If dY > 89 Then dY = 89
If dY < -89 Then dY = -89
Local dz# = (KeyDown(200)-KeyDown(208)) * moveSpeed
Local dx# = (KeyDown(205)-KeyDown(203)) * moveSpeed
If dz <> 0 And dx <> 0 Then
dx=dx * 0.707
dz=dz * 0.707
End If
RotateEntity GlobalCamera, dY, EntityYaw(GlobalCamera)-(MouseXSpeed()/2)*turnSpeed, 0
MoveEntity GlobalCamera, dx, 0, dz
MoveMouse GraphicsWidth()/2, GraphicsHeight()/2
If KeyHit(4) Then
CameraZoom GlobalCamera, 4.0
End If
If KeyHit(5) Then
CameraZoom GlobalCamera, 1.0
End If
End Function
Function FrontFacing%(cam%, s%, t%, m%)
Local v1 = CreateVector(3)
Local v2 = CreateVector(3)
Local v3 = CreateVector(3)
x# = VertexX(s, TriangleVertex(s, t, 0))
y# = VertexY(s, TriangleVertex(s, t, 0))
z# = VertexZ(s, TriangleVertex(s, t, 0))
TFormPoint x, y, z, m, cam
VctPut v1, 0, TFormedX()
VctPut v1, 1, TFormedY()
VctPut v1, 2, TFormedZ()
x# = VertexX(s, TriangleVertex(s, t, 1))
y# = VertexY(s, TriangleVertex(s, t, 1))
z# = VertexZ(s, TriangleVertex(s, t, 1))
TFormPoint x, y, z, m, cam
VctPut v2, 0, TFormedX()
VctPut v2, 1, TFormedY()
VctPut v2, 2, TFormedZ()
x# = VertexX(s, TriangleVertex(s, t, 2))
y# = VertexY(s, TriangleVertex(s, t, 2))
z# = VertexZ(s, TriangleVertex(s, t, 2))
TFormPoint x, y, z, m, cam
VctPut v3, 0, TFormedX()
VctPut v3, 1, TFormedY()
VctPut v3, 2, TFormedZ()
Local vEdge1 = V3dSubtract(v3, v1)
Local vEdge2 = V3dSubtract(v3, v2)
Local vFNormal = V3dCross(vEdge1, vEdge2)
Local bFrontFacing% = (V3dDot(v1, vFNormal) < 0)
DeleteVector v1
DeleteVector v2
DeleteVector v3
DeleteVector vEdge1
DeleteVector vEdge2
DeleteVector vFNormal
Return bFrontFacing
End Function
Function V3dAdd(v1, v2)
Local v3 = CreateVector(3)
VctPut v3, 0, VctGet(v1,0) + VctGet(v2,0)
VctPut v3, 1, VctGet(v1,1) + VctGet(v2,1)
VctPut v3, 2, VctGet(v1,2) + VctGet(v2,2)
Return v3
End Function
Function V3dSubtract(v1, v2)
Local v3 = CreateVector(3)
VctPut v3, 0, VctGet(v1,0) - VctGet(v2,0)
VctPut v3, 1, VctGet(v1,1) - VctGet(v2,1)
VctPut v3, 2, VctGet(v1,2) - VctGet(v2,2)
Return v3
End Function
Function V3dCross(v1, v2)
Local v3 = CreateVector(3)
VctPut v3, 0, VctGet(v1,1)*VctGet(v2,2) - VctGet(v1,2)*VctGet(v2,1)
VctPut v3, 1, VctGet(v1,2)*VctGet(v2,0) - VctGet(v1,0)*VctGet(v2,2)
VctPut v3, 2, VctGet(v1,0)*VctGet(v2,1) - VctGet(v1,1)*VctGet(v2,0)
Return v3
End Function
Function V3dDot#(v1, v2)
Return VctGet(v1,0)*VctGet(v2,0) + VctGet(v1,1)*VctGet(v2,1) + VctGet(v1,2)*VctGet(v2,2)
End Function
Function VctGet#(v, i%)
Return PeekFloat(v, i Shl 2)
End Function
Function VctPut(v, i%, val#)
PokeFloat v, i Shl 2, val
End Function
Function CreateVector(nDim%)
v% = CreateBank(nDim Shl 2)
Return v
End Function
Function DeleteVector(v)
FreeBank v
End Function
There is no way that drawing lines would be quick enough.
Yup, I think after experimenting I'm inclined to agree. However, I think that some more interesting effects might be achievable with line drawing. . . for example, try modifying the code above to pass in a value of 1 or 2 to the sketchy parameter in the DrawFrontFacingLines function to see what I mean. . .
So far I'm still not sure which way is best, but I'm starting to see the pros and cons of each. Also, I still have no idea how to solve the problem of deciding whether or not to draw lines based on whether an edge is hidden behind something or not.
Thanks people. . . keep the ideas coming :O)