Nice one Andy.
Rui, to get your engine perfect maybe you should think about representing your data in a different format, at least until its working right, then change the format to what ever you wish. By format I mean you have a bunch of vetices in 3d space, then a bunch of polygons which will have each corner of the polygon point to the vertex. This way you can seperate polygon normal from vertex normal data. I did a quick example but using a simple cube although I'm sure this is not 100% technically correct ( I haven't tested it thoroughly ) it is only to show an outline of what I mean by means of representing your data.
[CODE]
Graphics 800,600,32,1
Dim Vertex#(8,3) ;Vertex Position BEFORE any transformation or rotation
Dim RVertex#(8,3) ;Vertex Position AFTER any transformation or rotation
Dim VNormal#(8,3) ;Vertex Normal BEFORE any transformation or rotation
Dim RVNormal#(8,3) ;Vertex Normal AFTER any transformation or rotation
Dim PNormal#(6,3) ;Polygon Normal BEFORE any transformation or rotation
Dim RPNormal#(6,3) ;Polygon Normal AFTER any transformation or rotation
Dim polygon(6,4) ;1 quad per face * 6 faces, 4 vertices per quad
CreateObject
While Not KeyDown(1)
Cls
alpha=alpha+1
beta=beta+1
gamma=gamma+1
RotateObject(alpha,beta,gamma)
TransformObject(0,0,0)
DrawObjectSolid
;DrawObjectWireFrame
Flip
Wend
End
Function CreateObject()
;Setup cube vertices
; X Y Z
Vertex(1,1)=-1.0 Vertex(1,2)=1.0 Vertex(1,3)=-1.0
Vertex(2,1)=1.0 Vertex(2,2)=1.0 Vertex(2,3)=-1.0
Vertex(3,1)=1.0 Vertex(3,2)=-1.0 Vertex(3,3)=-1.0
Vertex(4,1)=-1.0 Vertex(4,2)=-1.0 Vertex(4,3)=-1.0
Vertex(5,1)=-1.0 Vertex(5,2)=1.0 Vertex(5,3)=1.0
Vertex(6,1)=1.0 Vertex(6,2)=1.0 Vertex(6,3)=1.0
Vertex(7,1)=1.0 Vertex(7,2)=-1.0 Vertex(7,3)=1.0
Vertex(8,1)=-1.0 Vertex(8,2)=-1.0 Vertex(8,3)=1.0
;Define the polygon vertices
polygon(1,1)=1 polygon(1,2)=2 polygon(1,3)=3 polygon(1,4)=4
polygon(2,1)=2 polygon(2,2)=6 polygon(2,3)=7 polygon(2,4)=3
polygon(3,1)=6 polygon(3,2)=5 polygon(3,3)=8 polygon(3,4)=7
polygon(4,1)=5 polygon(4,2)=1 polygon(4,3)=4 polygon(4,4)=8
polygon(5,1)=5 polygon(5,2)=6 polygon(5,3)=2 polygon(5,4)=1
polygon(6,1)=4 polygon(6,2)=3 polygon(6,3)=7 polygon(6,4)=8
;Scale the object solely for this demo
ScaleObject(100)
CreatePolygonNormals
End Function
Function CreatePolygonNormals()
For poly=1 To 6
;Get three vertices from each poly
v1=polygon(poly,1)
v2=polygon(poly,2)
v3=polygon(poly,3)
;now we the x,y,z position of each vertice
vx1#=Vertex(v1,1)
vy1#=Vertex(v1,2)
vz1#=Vertex(v1,3)
vx2#=Vertex(v2,1)
vy2#=Vertex(v2,2)
vz2#=Vertex(v2,3)
vx3#=Vertex(v3,1)
vy3#=Vertex(v3,2)
vz3#=Vertex(v3,3)
;Find v1-v2 and v1-v3 then place into u and v:
ux#=vx1-vx2
uy#=vy1-vy2
uz#=vz1-vz2
vx#=vx1-vx3
vy#=vy1-vy3
vz#=vz1-vz3
;Create the Normal by finding the cross product
Cx# = uy*vz - uz*vy
Cy# = uz*vx - ux*vz
Cz# = ux*vy - uy*vx
;Normalize the normal
If Cx<>0.0 Cx=Cx/Sqr(cx*cx)
If Cy<>0.0 Cy=Cy/Sqr(cy*cy)
If Cz<>0.0 Cz=Cz/Sqr(cz*cz)
PNormal(poly,1)=Cx
PNormal(poly,2)=Cy
PNormal(poly,3)=Cz
Next
End Function
Function ScaleObject(scale#)
For vert=1 To 8
Vertex(vert,1)=Vertex(vert,1)*Scale
Vertex(vert,2)=Vertex(vert,2)*Scale
Vertex(vert,3)=Vertex(vert,3)*Scale
Next
End Function
Function RotateObject(alpha#,beta#,gamma#)
;Rotate the Vertices
For vert=1 To 8
x0#=Vertex(vert,1)
y0#=Vertex(vert,2)
z0#=Vertex(vert,3)
;Rotate around Y axis
x1#=(Cos(beta) * z0) + (Sin(beta) * x0)
y1#=y0
z1#=-(Sin(beta) * z0) + (Cos(beta) * x0)
;Rotate around X axis
x2#=x1
y2#=(y1 * Cos(alpha)) - (z1 * Sin(alpha))
z2#=(y1 * Sin(alpha)) + (z1 * Cos(alpha))
;Rotate around Z axis
x3#=(x2 * Cos(gamma)) - (y2 * Sin(gamma))
y3#=(x2 * Sin(gamma)) + (y2 * Cos(gamma))
z3#=z2
;Store in Rotated Vertex array
RVertex(vert,1)=x3
RVertex(vert,2)=y3
RVertex(vert,3)=z3
Next
;Rotate the Normals
For poly=1 To 6
nx#=PNormal(poly,1)
ny#=PNormal(poly,2)
nz#=PNormal(poly,3)
;Rotate around Y axis
nx1#=(Cos(beta) * nz) + (Sin(beta) * nx)
ny1#=ny
nz1#=-(Sin(beta) * nz) + (Cos(beta) * nx)
;Rotate around X axis
nx2#=nx1
ny2#=(ny1 * Cos(alpha)) - (nz1 * Sin(alpha))
nz2#=(ny1 * Sin(alpha)) + (nz1 * Cos(alpha))
;Rotate around Z axis
nx3#=(nx2 * Cos(gamma)) - (ny2 * Sin(gamma))
ny3#=(nx2 * Sin(gamma)) + (ny2 * Cos(gamma))
nz3#=nz2
RPNormal(poly,1)=nx3
RPNormal(poly,2)=ny3
RPNormal(poly,3)=nz3
Next
End Function
Function TransformObject(Tx#,Ty#,Tz#)
For vert=1 To 8
x#=RVertex(vert,1)
y#=RVertex(vert,2)
z#=RVertex(vert,3)
RVertex(vert,1)=x+Tx
RVertex(vert,2)=y+Ty
RVertex(vert,3)=z+Tz
Next
End Function
Function DrawObjectSolid()
;For back face removal we test the dot product
;between our view vector and the polygon normal
;Our View vector
ViewX#=0.0
ViewY#=0.0
ViewZ#=1.0
For poly=1 To 6
Nx#=RPNormal(poly,1)
Ny#=RPNormal(poly,2)
Nz#=RPNormal(poly,3)
;If View.Normal > 0 then render ( ignore back facing polys )
If ViewX*NX + ViewY*Ny + ViewZ*Nz > 0.0
RenderPolygon(poly)
EndIf
Next
End Function
Function DrawObjectWireFrame()
For poly=1 To 6
RenderPolygon(poly)
Next
End Function
Function RenderPolygon(poly)
v1=polygon(poly,1)
v2=polygon(poly,2)
v3=polygon(poly,3)
v4=polygon(poly,4)
vx1#=RVertex(v1,1) vy1#=RVertex(v1,2) vz1#=RVertex(v1,3)
vx2#=RVertex(v2,1) vy2#=RVertex(v2,2) vz2#=RVertex(v2,3)
vx3#=RVertex(v3,1) vy3#=RVertex(v3,2) vz3#=RVertex(v3,3)
vx4#=RVertex(v4,1) vy4#=RVertex(v4,2) vz4#=RVertex(v4,3)
sx1#=400+vx1
sy1#=300+vy1
sx2#=400+vx2
sy2#=300+vy2
sx3#=400+vx3
sy3#=300+vy3
sx4#=400+vx4
sy4#=300+vy4
Line sx1,sy1,sx2,sy2
Line sx2,sy2,sx3,sy3
Line sx3,sy3,sx4,sy4
Line sx4,sy4,sx1,sy1
End Function
[/CODE]
I feel this is a step in the right direction, simply because we need to eliminate as many errors as early as possible, especially before they introduce new errors that are nearly impossible to find. The only reason the previous code seems to work is because the object in at world origin ( 0,0,0 ) as soon as your move away from that position, the algo will fail badly along with all the lighting.
Rui, to get your engine perfect maybe you should think about representing your data in a different format, at least until its working right, then change the format to what ever you wish. By format I mean you have a bunch of vetices in 3d space, then a bunch of polygons which will have each corner of the polygon point to the vertex. This way you can seperate polygon normal from vertex normal data. I did a quick example but using a simple cube although I'm sure this is not 100% technically correct ( I haven't tested it thoroughly ) it is only to show an outline of what I mean by means of representing your data.
[CODE]
Graphics 800,600,32,1
Dim Vertex#(8,3) ;Vertex Position BEFORE any transformation or rotation
Dim RVertex#(8,3) ;Vertex Position AFTER any transformation or rotation
Dim VNormal#(8,3) ;Vertex Normal BEFORE any transformation or rotation
Dim RVNormal#(8,3) ;Vertex Normal AFTER any transformation or rotation
Dim PNormal#(6,3) ;Polygon Normal BEFORE any transformation or rotation
Dim RPNormal#(6,3) ;Polygon Normal AFTER any transformation or rotation
Dim polygon(6,4) ;1 quad per face * 6 faces, 4 vertices per quad
CreateObject
While Not KeyDown(1)
Cls
alpha=alpha+1
beta=beta+1
gamma=gamma+1
RotateObject(alpha,beta,gamma)
TransformObject(0,0,0)
DrawObjectSolid
;DrawObjectWireFrame
Flip
Wend
End
Function CreateObject()
;Setup cube vertices
; X Y Z
Vertex(1,1)=-1.0 Vertex(1,2)=1.0 Vertex(1,3)=-1.0
Vertex(2,1)=1.0 Vertex(2,2)=1.0 Vertex(2,3)=-1.0
Vertex(3,1)=1.0 Vertex(3,2)=-1.0 Vertex(3,3)=-1.0
Vertex(4,1)=-1.0 Vertex(4,2)=-1.0 Vertex(4,3)=-1.0
Vertex(5,1)=-1.0 Vertex(5,2)=1.0 Vertex(5,3)=1.0
Vertex(6,1)=1.0 Vertex(6,2)=1.0 Vertex(6,3)=1.0
Vertex(7,1)=1.0 Vertex(7,2)=-1.0 Vertex(7,3)=1.0
Vertex(8,1)=-1.0 Vertex(8,2)=-1.0 Vertex(8,3)=1.0
;Define the polygon vertices
polygon(1,1)=1 polygon(1,2)=2 polygon(1,3)=3 polygon(1,4)=4
polygon(2,1)=2 polygon(2,2)=6 polygon(2,3)=7 polygon(2,4)=3
polygon(3,1)=6 polygon(3,2)=5 polygon(3,3)=8 polygon(3,4)=7
polygon(4,1)=5 polygon(4,2)=1 polygon(4,3)=4 polygon(4,4)=8
polygon(5,1)=5 polygon(5,2)=6 polygon(5,3)=2 polygon(5,4)=1
polygon(6,1)=4 polygon(6,2)=3 polygon(6,3)=7 polygon(6,4)=8
;Scale the object solely for this demo
ScaleObject(100)
CreatePolygonNormals
End Function
Function CreatePolygonNormals()
For poly=1 To 6
;Get three vertices from each poly
v1=polygon(poly,1)
v2=polygon(poly,2)
v3=polygon(poly,3)
;now we the x,y,z position of each vertice
vx1#=Vertex(v1,1)
vy1#=Vertex(v1,2)
vz1#=Vertex(v1,3)
vx2#=Vertex(v2,1)
vy2#=Vertex(v2,2)
vz2#=Vertex(v2,3)
vx3#=Vertex(v3,1)
vy3#=Vertex(v3,2)
vz3#=Vertex(v3,3)
;Find v1-v2 and v1-v3 then place into u and v:
ux#=vx1-vx2
uy#=vy1-vy2
uz#=vz1-vz2
vx#=vx1-vx3
vy#=vy1-vy3
vz#=vz1-vz3
;Create the Normal by finding the cross product
Cx# = uy*vz - uz*vy
Cy# = uz*vx - ux*vz
Cz# = ux*vy - uy*vx
;Normalize the normal
If Cx<>0.0 Cx=Cx/Sqr(cx*cx)
If Cy<>0.0 Cy=Cy/Sqr(cy*cy)
If Cz<>0.0 Cz=Cz/Sqr(cz*cz)
PNormal(poly,1)=Cx
PNormal(poly,2)=Cy
PNormal(poly,3)=Cz
Next
End Function
Function ScaleObject(scale#)
For vert=1 To 8
Vertex(vert,1)=Vertex(vert,1)*Scale
Vertex(vert,2)=Vertex(vert,2)*Scale
Vertex(vert,3)=Vertex(vert,3)*Scale
Next
End Function
Function RotateObject(alpha#,beta#,gamma#)
;Rotate the Vertices
For vert=1 To 8
x0#=Vertex(vert,1)
y0#=Vertex(vert,2)
z0#=Vertex(vert,3)
;Rotate around Y axis
x1#=(Cos(beta) * z0) + (Sin(beta) * x0)
y1#=y0
z1#=-(Sin(beta) * z0) + (Cos(beta) * x0)
;Rotate around X axis
x2#=x1
y2#=(y1 * Cos(alpha)) - (z1 * Sin(alpha))
z2#=(y1 * Sin(alpha)) + (z1 * Cos(alpha))
;Rotate around Z axis
x3#=(x2 * Cos(gamma)) - (y2 * Sin(gamma))
y3#=(x2 * Sin(gamma)) + (y2 * Cos(gamma))
z3#=z2
;Store in Rotated Vertex array
RVertex(vert,1)=x3
RVertex(vert,2)=y3
RVertex(vert,3)=z3
Next
;Rotate the Normals
For poly=1 To 6
nx#=PNormal(poly,1)
ny#=PNormal(poly,2)
nz#=PNormal(poly,3)
;Rotate around Y axis
nx1#=(Cos(beta) * nz) + (Sin(beta) * nx)
ny1#=ny
nz1#=-(Sin(beta) * nz) + (Cos(beta) * nx)
;Rotate around X axis
nx2#=nx1
ny2#=(ny1 * Cos(alpha)) - (nz1 * Sin(alpha))
nz2#=(ny1 * Sin(alpha)) + (nz1 * Cos(alpha))
;Rotate around Z axis
nx3#=(nx2 * Cos(gamma)) - (ny2 * Sin(gamma))
ny3#=(nx2 * Sin(gamma)) + (ny2 * Cos(gamma))
nz3#=nz2
RPNormal(poly,1)=nx3
RPNormal(poly,2)=ny3
RPNormal(poly,3)=nz3
Next
End Function
Function TransformObject(Tx#,Ty#,Tz#)
For vert=1 To 8
x#=RVertex(vert,1)
y#=RVertex(vert,2)
z#=RVertex(vert,3)
RVertex(vert,1)=x+Tx
RVertex(vert,2)=y+Ty
RVertex(vert,3)=z+Tz
Next
End Function
Function DrawObjectSolid()
;For back face removal we test the dot product
;between our view vector and the polygon normal
;Our View vector
ViewX#=0.0
ViewY#=0.0
ViewZ#=1.0
For poly=1 To 6
Nx#=RPNormal(poly,1)
Ny#=RPNormal(poly,2)
Nz#=RPNormal(poly,3)
;If View.Normal > 0 then render ( ignore back facing polys )
If ViewX*NX + ViewY*Ny + ViewZ*Nz > 0.0
RenderPolygon(poly)
EndIf
Next
End Function
Function DrawObjectWireFrame()
For poly=1 To 6
RenderPolygon(poly)
Next
End Function
Function RenderPolygon(poly)
v1=polygon(poly,1)
v2=polygon(poly,2)
v3=polygon(poly,3)
v4=polygon(poly,4)
vx1#=RVertex(v1,1) vy1#=RVertex(v1,2) vz1#=RVertex(v1,3)
vx2#=RVertex(v2,1) vy2#=RVertex(v2,2) vz2#=RVertex(v2,3)
vx3#=RVertex(v3,1) vy3#=RVertex(v3,2) vz3#=RVertex(v3,3)
vx4#=RVertex(v4,1) vy4#=RVertex(v4,2) vz4#=RVertex(v4,3)
sx1#=400+vx1
sy1#=300+vy1
sx2#=400+vx2
sy2#=300+vy2
sx3#=400+vx3
sy3#=300+vy3
sx4#=400+vx4
sy4#=300+vy4
Line sx1,sy1,sx2,sy2
Line sx2,sy2,sx3,sy3
Line sx3,sy3,sx4,sy4
Line sx4,sy4,sx1,sy1
End Function
[/CODE]
I feel this is a step in the right direction, simply because we need to eliminate as many errors as early as possible, especially before they introduce new errors that are nearly impossible to find. The only reason the previous code seems to work is because the object in at world origin ( 0,0,0 ) as soon as your move away from that position, the algo will fail badly along with all the lighting.