Worklog for puki

Worklog 1

Return to Worklogs

Mesh builder(Posted 2004-10-24)
I needed a way to construct meshes quicker and with control, so I knocked this up:
; mesh builder by "puki" - 24/10/04

Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-5

WireFrame 1

mesh = CreateMesh()
surface=CreateSurface(mesh)

; here we set the size of the mesh (in squares)
; both values must each be at least 1 - they do not have to be matching values
mwidth=8
mheight=6

; there will only be 4 vertices per square - 0 to 3
; we re-use the array cells repeatedly to save memory
Dim vert_no(3)

; the following code draws each section of the mesh from left to right
; then it starts a new row below the first and again works along left to right
For height=1 To mheight
	For width=1 To mwidth
		For addvert=0 To 3
			vert_no(0)=AddVertex(surface,curx,cury-1,curz)
			vert_no(1)=AddVertex(surface,curx,cury,curz)
			vert_no(2)=AddVertex(surface,curx+1,cury,curz)
			vert_no(3)=AddVertex(surface,curx+1,cury-1,curz)
			tri1=AddTriangle(surface,vert_no(0),vert_no(1),vert_no(2))
			tri2=AddTriangle(surface,vert_no(0),vert_no(2),vert_no(3))
		Next
	curx=curx+1
	Next
curx=0
cury=cury-1
Next

UpdateNormals mesh
PositionMesh mesh,-4,3,0

While Not KeyHit(1)
RenderWorld
Flip 
Wend
End


THE ABOVE LOOKED OKAY BUT WAS FLAWED - CREATING FAR TOO MANY VERTICES - CORRECTED VERSION IS BELOW (I THINK THAT ONE IS OKAY) - ACTUALLY, THE FOLLOWING IS STILL FLAWED - BUT MUCH BETTER

; mesh builder by "puki" - 24/10/04

Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-5


WireFrame 1

mesh = CreateMesh()
surface=CreateSurface(mesh)

; here we set the size of the mesh (in squares)
; both values must each be at least 1 - they do not have to be matching values
mwidth=8
mheight=6

; there will only be 4 vertices per square - 0 to 3
; we re-use the array cells repeatedly to save memory
Dim vert_no(3)

; the following code draws each section of the mesh from left to right
; then it starts a new row below the first and again works along left to right
For height=1 To mheight
	For width=1 To mwidth
			vert_no(0)=AddVertex(surface,curx,cury-1,curz)
			vert_no(1)=AddVertex(surface,curx,cury,curz)
			vert_no(2)=AddVertex(surface,curx+1,cury,curz)
			vert_no(3)=AddVertex(surface,curx+1,cury-1,curz)
		
			tri1=AddTriangle(surface,vert_no(0),vert_no(1),vert_no(2))
			tri2=AddTriangle(surface,vert_no(0),vert_no(2),vert_no(3))
			curx=curx+1
	Next
	curx=0
	cury=cury-1
Next

UpdateNormals mesh
PositionMesh mesh,-4,3,0

While Not KeyHit(1)
RenderWorld
Flip 
Wend
End

After playing with the code, I realise now that it can only be done with an array or, perhaps, types. I partly resolved the vertice number count with the following code:
; mesh builder by "puki" - 24/10/04

Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-5

WireFrame 1

mesh = CreateMesh()
surface=CreateSurface(mesh)

; here we set the size of the mesh (in squares)
; both values must each be at least 1 - they do not have to be matching values
mwidth=2
mheight=2

; there will only be 4 vertices per square - 0 to 3
; we re-use the array cells repeatedly to save memory
Dim vert_no(3)

; the following code draws each section of the mesh from left to right
; then it starts a new row below the first and again works along left to right
For height=1 To mheight
	For width=1 To mwidth
		If curx=0
			vert_no(0)=AddVertex(surface,curx,cury-1,curz)
			vert_no(1)=AddVertex(surface,curx,cury,curz)
			vert_no(2)=AddVertex(surface,curx+1,cury,curz)
			vert_no(3)=AddVertex(surface,curx+1,cury-1,curz)
		
			tri1=AddTriangle(surface,vert_no(0),vert_no(1),vert_no(2))
			tri2=AddTriangle(surface,vert_no(0),vert_no(2),vert_no(3))
			curx=curx+1
			
				Else
				
			vert_no(0)=AddVertex(surface,curx+1,cury,curz)
			vert_no(1)=AddVertex(surface,curx+1,cury-1,curz)
			
			tri1=AddTriangle(surface,vert_no(3),vert_no(2),vert_no(0))
			tri2=AddTriangle(surface,vert_no(3),vert_no(0),vert_no(1))
			
			vert_no(2)=vert_no(0)
			vert_no(3)=vert_no(1)
			
			curx=curx+1
				
		EndIf
		
	Next
	curx=0
	cury=cury-1
Next

UpdateNormals mesh
PositionMesh mesh,-4,3,0
vertices=CountVertices(surface)

While Not KeyHit(1)
RenderWorld
Print "Current number of vertices: "+vertices
WaitKey
Flip 
Wend
End

However, this works fine for the rows of squares (running left to right), but every time a new row is created below the one above, I cannot easily re-use any vertex data. Meaning my code is now redundant and I can use 'Mesh Plane' created by "Neo Genesis10": www.blitzbasic.com/codearcs/codearcs.php?code=382

Dim vertex(99,99)

Function CreateMeshPlane(width, height, parent=0)
	width = width - 1
	height = height - 1

	mesh = CreateMesh()
	surface = CreateSurface(mesh)

	For x = 0 To width
		For z = 0 To height
			vertex(x,z) = AddVertex(surface,x,0,z)
		Next
	Next
	
	For x = 0 To width
		For z = 0 To height
			VertexTexCoords surface, vertex(x,z), 0, 1, 0
			VertexTexCoords surface, vertex(x,z+1), 0, 0, 0
			VertexTexCoords surface, vertex(x+1,z), 1, 1, 0
			VertexTexCoords surface, vertex(x+1,z+1), 1, 0, 0
			AddTriangle(surface, vertex(x,z), vertex(x,z+1), vertex(x+1,z+1) )
			AddTriangle(surface, vertex(x+1,z+1), vertex(x+1,z), vertex(x,z) )
		Next
	Next
	
	EntityParent mesh, parent
	Return mesh
	
End Function


For me to achieve the functuality of his code, my code would grow in size - his is small and compact (like mine started out like).



Resources(Posted 2004-10-23)
Face and Vertex Normal Vectors
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_m/directx/direct3d/gettingstarted/3dcoordinatesystems/facevertexnormalvectors.asp

Vertex Normals
http://www.flipcode.org/articles/article_vertexnormals.shtml

General
http://www.fjant.se/3d_faq.htm#vertex

Not so normal?
http://chuggnut.com/tutorials/meshguide/meshguide.html


A normal is the vector perpendicular to the face.

The Normal of a polygon is a perpendicular vector from the face of the polygon. The direction of this vector is determined by the order in which the vertices were defined. The vertices have been defined in a clockwise direction. The Normal of a vertex is usually the average of each of the normals of each polygon that shares that vertex.

A vertex normal is vector (Normaly with a magnitude of 1) that points at a tangent(90 degrees) to the surface. It is primarily used in lighting calulations so that objects surfaces look smooth rather than like lots of flat triangles.

Imagine a curves surface for a moment. In a perfect world, that curved surface could be made of millions of faces to give a perfectly smooth and accurate representation of the curve. But this is not a perfect world so this is not likely to run at an acceptable rate. Now imgine the same curve, but with 3 or 4 Verticies along the curve. The normal of each verticies will be the tangent to the curve at that vertex position. Now the lighting can be calcuated to better represent the effect of the high detail curve.



Clipping(Posted 2004-10-22)
The following code is useless - I have used it to visually 'draw' an example of clipping whereby the red triangle is clipped outside of the viewing area (the grey square) and then a new triangle is created (basically, to tidy up) - the external part of the original triangle is discarded.

If the red triangle was completely outside of the viewing area then it would be 'culled'.

I'm not sure if anyone has internally done clipping with Blitz3D surface/vertex commands. I suppose it is technically possible although, possibly, not much use.

Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 
cam = CreateCamera() 
MoveEntity cam, 0,0,-10
mesh = CreateMesh()
surface=CreateSurface(mesh)
v1=AddVertex(surface,-1,-5,-0)
v2=AddVertex(surface,-1, 1,-0)
v3=AddVertex(surface, 5, 1,-0)
v4=AddVertex(surface, 5,-5,-0)
tri1=AddTriangle(surface,v1,v2,v3)
tri2=AddTriangle(surface,v1,v3,v4)
surf1 = CreateSurface(mesh)
v0 = AddVertex (surf1,-3,-2,-1)
v1 = AddVertex (surf1, 2, 0,-1) 
v2 = AddVertex (surf1, 3,-3,-1) 
tri = AddTriangle (surf1,v0,v1,v2)
VertexColor surf1,v0,255,0,0
VertexColor surf1,v1,255,0,0
VertexColor surf1,v2,255,0,0
EntityFX mesh,2 
UpdateNormals mesh
RenderWorld
Color 255,255,255 
Rect 286,280,4,4,1
Line 288,280,288,322
Rect 286,322,4,4,1
Rect 388,240,4,4,1
Line 288,322,390,240
Line 288,281,390,240
Flip 
WaitKey
End


In fact, "big10p" has done a clipping demo:
http://www.blitzbasic.com/codearcs/codearcs.php?code=1143



VertexColor(Posted 2004-10-22)
'VertexColor' does not work as one would expect it to:

Graphics3D 640,480 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-5 

mesh = CreateMesh()

surf1 = CreateSurface(mesh); left-hand triangle of square 
;                       x  y  z
v0 = AddVertex (surf1,-2, 2, 0); top left corner
v1 = AddVertex (surf1, 2, 2, 0); top right corner 
v2 = AddVertex (surf1,-2,-2, 0); bottom left corner 


tri = AddTriangle (surf1,v0,v1,v2); this is the left-hand triangle of our square

UpdateNormals mesh

VertexColor surf1,v0,255,0,0
VertexColor surf1,v1,255,0,0
VertexColor surf1,v2,255,0,0

RenderWorld 
Flip 

WaitKey 
End 


Produces nothing (in terms of red) - not a sausage. However, add in 'EntityFX mesh,2' and it works.

Graphics3D 640,480 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-5 

mesh = CreateMesh()
EntityFX mesh,2

surf1 = CreateSurface(mesh); left-hand triangle of square 
;                       x  y  z
v0 = AddVertex (surf1,-2, 2, 0); top left corner
v1 = AddVertex (surf1, 2, 2, 0); top right corner 
v2 = AddVertex (surf1,-2,-2, 0); bottom left corner 
tri = AddTriangle (surf1,v0,v1,v2); this is the left-hand triangle of our square

UpdateNormals mesh

VertexColor surf1,v0,255,0,0
VertexColor surf1,v1,255,0,0
VertexColor surf1,v2,255,0,0

RenderWorld 
Flip 

WaitKey 
End 


'EntityFX mesh,2' - the value '2' dictates the use of vertex colors instead of brush color.



Creating a mesh(Posted 2004-10-22)
For this first example, I have gone for the most 'economical' method I could think of. The physical structure of the mesh (which you will see when you run the code) has 16 vertices, regardless. The mesh I have created is constructed from defining 16 vertices and linking the mesh with 18 triangles.

It seems pretty efficient:

Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-10

mesh = CreateMesh()
surface=CreateSurface(mesh)

;column 1
v1=AddVertex(surface,-1,-1,-0)
v2=AddVertex(surface,-1, 1,-0)
v3=AddVertex(surface, 1, 1,-0)
v4=AddVertex(surface, 1,-1,-0)
tri1=AddTriangle(surface,v1,v2,v3)
tri2=AddTriangle(surface,v1,v3,v4)

v5=AddVertex(surface,-1,-3,0)
v6=AddVertex(surface, 1,-3,0)
tri1=AddTriangle(surface,v5,v1,v4)
tri2=AddTriangle(surface,v5,v4,v6)

v7=AddVertex(surface,-1,-5,0)
v8=AddVertex(surface, 1,-5,0)
tri1=AddTriangle(surface,v7,v5,v6)
tri2=AddTriangle(surface,v7,v6,v8)

;column 2
v9=AddVertex(surface,3,1,0)
v10=AddVertex(surface,3,-1,0)
tri1=AddTriangle(surface,v4,v3,v9)
tri1=AddTriangle(surface,v4,v9,v10)

v11=AddVertex(surface,3,-3,0)
tri1=AddTriangle(surface,v6,v4,v10)
tri1=AddTriangle(surface,v6,v10,v11)

v12=AddVertex(surface,3,-5,0)
tri1=AddTriangle(surface,v8,v6,v11)
tri1=AddTriangle(surface,v8,v11,v12)

;column 3
v13=AddVertex(surface,5,1,0)
v14=AddVertex(surface,5,-1,0)
tri1=AddTriangle(surface,v10,v9,v13)
tri1=AddTriangle(surface,v10,v13,v14)

v15=AddVertex(surface,5,-3,0)
tri1=AddTriangle(surface,v11,v10,v14)
tri1=AddTriangle(surface,v11,v14,v15)

v16=AddVertex(surface,5,-5,0)
tri1=AddTriangle(surface,v12,v11,v15)
tri1=AddTriangle(surface,v12,v15,v16)

UpdateNormals mesh

RenderWorld
Flip 
WaitKey
End

Basically, I have exploited the fact that we can re-use as many vertices as possible:

Column 1 has 8 vertices created and 6 triangles.
Column 2 has 4 vertices created and 6 triangles.
Column 3 has 4 vertices created and 6 triangles.

Columns 2 and 3 are each re-using vertex data from each previous column.

Considering the mesh has 9 squares in it, the mesh could have been constructed from 18 unique triangles (2 triangles per square) and contained as many as 54 vertices (based on unique triangles).

I played around a bit and created the following - still needs the 2 missing triangles added back in:
Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-10

WireFrame 1

mesh = CreateMesh()
surface=CreateSurface(mesh)

;column 1
v1=AddVertex(surface,-1,-1,0)
v2=AddVertex(surface,-1, 1,0)
v3=AddVertex(surface, 1, 1,0)
v4=AddVertex(surface, 1,-1,0)
tri1=AddTriangle(surface,v1,v2,v3)
tri2=AddTriangle(surface,v1,v3,v4)

v5=AddVertex(surface,-1,-3,0)
v6=AddVertex(surface, 1,-3,0)
tri1=AddTriangle(surface,v5,v1,v4)
tri2=AddTriangle(surface,v5,v4,v6)

v7=AddVertex(surface,-1,-5,0)
v8=AddVertex(surface, 1,-5,0)
tri1=AddTriangle(surface,v7,v5,v6)
tri2=AddTriangle(surface,v7,v6,v8)

;column 2
v9=AddVertex(surface,3,1,0)
v10=AddVertex(surface,3,-1,0)
tri1=AddTriangle(surface,v4,v3,v9)
tri1=AddTriangle(surface,v4,v9,v10)

v11=AddVertex(surface,3,-3,0)
tri1=AddTriangle(surface,v6,v4,v10)
tri1=AddTriangle(surface,v6,v10,v11)

v12=AddVertex(surface,3,-5,0)
tri1=AddTriangle(surface,v8,v6,v11)
tri1=AddTriangle(surface,v8,v11,v12)

;column 3
v13=AddVertex(surface,5,1,0)
v14=AddVertex(surface,5,-1,0)
tri1=AddTriangle(surface,v10,v9,v13)
tri1=AddTriangle(surface,v10,v13,v14)

v15=AddVertex(surface,5,-3,0)
tri1=AddTriangle(surface,v11,v10,v14)
tri1=AddTriangle(surface,v11,v14,v15)

v16=AddVertex(surface,5,-5,0)
tri1=AddTriangle(surface,v12,v11,v15)
tri1=AddTriangle(surface,v12,v15,v16)

UpdateNormals mesh

PositionMesh mesh,-1.5,2,0

While Not KeyHit(1)

For a#=0 To 3 Step .1
		VertexCoords surface,v2,VertexX(surface,v2),VertexY(surface,v2),a
		VertexCoords surface,v1,VertexX(surface,v1),VertexY(surface,v1),a
		VertexCoords surface,v5,VertexX(surface,v5),VertexY(surface,v5),a
		VertexCoords surface,v7,VertexX(surface,v7),VertexY(surface,v7),a
		
		VertexCoords surface,v9,VertexX(surface,v9),VertexY(surface,v9),a
		VertexCoords surface,v10,VertexX(surface,v10),VertexY(surface,v10),a
		VertexCoords surface,v11,VertexX(surface,v11),VertexY(surface,v11),a
		VertexCoords surface,v12,VertexX(surface,v12),VertexY(surface,v12),a
TurnEntity mesh,.1,y,z
RenderWorld
Flip 
Next

For a#=3 To 0 Step-.1 
		VertexCoords surface,v2,VertexX(surface,v2),VertexY(surface,v2),a
		VertexCoords surface,v1,VertexX(surface,v1),VertexY(surface,v1),a
		VertexCoords surface,v5,VertexX(surface,v5),VertexY(surface,v5),a
		VertexCoords surface,v7,VertexX(surface,v7),VertexY(surface,v7),a
		
		VertexCoords surface,v9,VertexX(surface,v9),VertexY(surface,v9),a
		VertexCoords surface,v10,VertexX(surface,v10),VertexY(surface,v10),a
		VertexCoords surface,v11,VertexX(surface,v11),VertexY(surface,v11),a
		VertexCoords surface,v12,VertexX(surface,v12),VertexY(surface,v12),a
TurnEntity mesh,.1,y,z
RenderWorld
Flip 
Next

Wend




Wireframe mode(Posted 2004-10-22)
Whilst doing this worklog - I suddenly remembered Blitz3d has a 'WireFrame' mode.

You can insert it into any of the demos - for example after the camera has been defined, add in 'WireFrame 1'. This activates wireframe mode and lets you see the triangles in your mesh. I'll soon edit the code examples and add the command in so that you can just press the "w" key to flick in and out of wireframe whilst the code is running.

Note: Not all graphics cards may support this.

Here is an example of our pyramid:
Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-12

WireFrame 1

; just a bit of cosmetic lighting
light=CreateLight(2)
LightColor light,0,0,255
MoveEntity light,1000,1000,-1000

; a second bit of cosmetic lighting
light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-1000,1000,-1000

mesh = CreateMesh() 

surface=CreateSurface(mesh)

; This is the first triangle - the one that intially faces you
triangle1 = CreateSurface(mesh)
v1 = AddVertex (triangle1,-2,-2,-2) 
v2 = AddVertex (triangle1, 0, 2, 0) 
v3 = AddVertex (triangle1, 2,-2,-2) 
tri = AddTriangle (triangle1,v1,v2,v3)

; This is the other side of triangle 1
triangle1b = CreateSurface(mesh)
v1 = AddVertex (triangle1b,-2,-2,-2) 
v2 = AddVertex (triangle1b, 0, 2, 0) 
v3 = AddVertex (triangle1b, 2,-2,-2) 
tri = AddTriangle (triangle1b,v3,v2,v1)

; This is triangle 2 - the one that intially faces to the left
triangle2 = CreateSurface(mesh) 
v1 = AddVertex (triangle2, -2,-2, 2) 
v2 = AddVertex (triangle2,  0, 2, 0) 
v3 = AddVertex (triangle2, -2,-2,-2)  
tri = AddTriangle (triangle2,v1,v2,v3)

; This is the other side of triangle 2
triangle2b = CreateSurface(mesh) 
v1 = AddVertex (triangle2b, -2,-2, 2) 
v2 = AddVertex (triangle2b,  0, 2, 0) 
v3 = AddVertex (triangle2b, -2,-2,-2)  
tri = AddTriangle (triangle2b,v3,v2,v1)

; This is triangle 3 - the one that intially faces to the right
triangle3 = CreateSurface(mesh) 
v1 = AddVertex (triangle3, 2,-2,-2) 
v2 = AddVertex (triangle3, 0, 2, 0) 
v3 = AddVertex (triangle3, 2,-2, 2)  
tri = AddTriangle (triangle3,v1,v2,v3)

; This is the other side of triangle 3
triangle3b = CreateSurface(mesh) 
v1 = AddVertex (triangle3b, 2,-2,-2) 
v2 = AddVertex (triangle3b, 0, 2, 0) 
v3 = AddVertex (triangle3b, 2,-2, 2)  
tri = AddTriangle (triangle3b,v3,v2,v1)

; This is triangle 4 - the that intially faces to the rear
triangle4 = CreateSurface(mesh) 
v1 = AddVertex (triangle4, 2,-2, 2) 
v2 = AddVertex (triangle4, 0, 2, 0) 
v3 = AddVertex (triangle4,-2,-2, 2)  
tri = AddTriangle (triangle4,v1,v2,v3)

; This is the other side of triangle 4
triangle4b = CreateSurface(mesh) 
v1 = AddVertex (triangle4b, 2,-2, 2) 
v2 = AddVertex (triangle4b, 0, 2, 0) 
v3 = AddVertex (triangle4b,-2,-2, 2)  
tri = AddTriangle (triangle4b,v3,v2,v1)

UpdateNormals mesh; necessary for correct lighting - not required in this example

x#=.5
y#=.5
z#=.5 
While Not KeyHit(1)
c=c+1
If c=200
	y=Rnd(2)/10
	z=Rnd(2)/10
	c=0
EndIf
TurnEntity mesh,1,y,z
RenderWorld
Flip 
Wend




VertexCoords(Posted 2004-10-21)
The 'VertexCoords' command allows you to alter the 3D space position (x,y,z) of a triangle's vertice. This would be used to deform a mesh or perhaps for a water wave/ripple effect.

Graphics3D 640,480,16,2
SetBuffer BackBuffer()

cam = CreateCamera()
MoveEntity cam, 0,0,-12

light=CreateLight(2)
LightColor light,0,0,255
MoveEntity light,1000,1000,-1000

light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-1000,1000,-1000

mesh = CreateMesh()

triangle1 = CreateSurface(mesh)
v1 = AddVertex (triangle1,-2,-2,-2)
v2 = AddVertex (triangle1, 0, 2,-2)
v3 = AddVertex (triangle1, 2,-2,-2)
tri = AddTriangle (triangle1,v1,v2,v3)

triangle2 = CreateSurface(mesh)
v1 = AddVertex (triangle2,-2,-2,-2)
v2 = AddVertex (triangle2, 0, 2,-2)
v3 = AddVertex (triangle2, 2,-2,-2)

tri = AddTriangle (triangle2,v3,v2,v1)
UpdateNormals mesh

c=0

While Not KeyHit(1)

c=c+1
If c>20; change this to alter speed of transformation
	cv1=Rnd(5)
	cv2=Rnd(5)
	cv3=Rnd(5)
	VertexCoords triangle1,v2,cv1,cv2,cv3
	VertexCoords triangle2,v2,cv1,cv2,cv3
	c=0
EndIf

TurnEntity mesh,0,1,0

RenderWorld
Flip
Wend
End


One thing to mention is that when using a double-sided surface (as above), you need to also move the relevent vertices for the adjoining side or else the two sides will split open. Of course you may want to split a double-sided triangle.

After the 'UpdateNormals' command change the remainder of the code to:
TurnEntity mesh,0,90,0

VertexCoords triangle1,v2,5,0,5
VertexCoords triangle2,v2,-5,0,-5

While Not KeyHit(1)
TurnEntity mesh,0,0,1
RenderWorld
Flip
Wend

The the backs of both triangles are not there. We have 2 separate triangles that form a double-sided triangle but, in fact, individually they are single-surface.



Double-sided surfaces(Posted 2004-10-18)
With regard to double sided surfaces:

Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-12

light=CreateLight(2)
LightColor light,0,0,255
MoveEntity light,1000,1000,-1000

light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-1000,1000,-1000

mesh = CreateMesh() 

surface=CreateSurface(mesh)

triangle1 = CreateSurface(mesh)
v1 = AddVertex (triangle1,-2,-2,-2) 
v2 = AddVertex (triangle1, 0, 2, -2) 
v3 = AddVertex (triangle1, 2,-2,-2)
tri = AddTriangle (triangle1,v1,v2,v3)
tri = AddTriangle (triangle1,v3,v2,v1)

UpdateNormals mesh

While Not KeyHit(1)
TurnEntity mesh,0,1,0
RenderWorld
Flip 
Wend
End


Let’s look at a single-sided triangle – rotating:
Graphics3D 640,480,16,2
SetBuffer BackBuffer()

cam = CreateCamera()
MoveEntity cam, 0,0,-12

mesh = CreateMesh()

triangle1 = CreateSurface(mesh)
v1 = AddVertex (triangle1,-2,-2,-2)
v2 = AddVertex (triangle1, 0, 2, -2)
v3 = AddVertex (triangle1, 2,-2,-2)
tri = AddTriangle (triangle1,v1,v2,v3)

UpdateNormals mesh

While Not KeyHit(1)
TurnEntity mesh,0,1,0

RenderWorld
Flip
Wend
End

Making the above triangle double-sided is easy – you just add another ‘AddTriangle’ command and then link the vertices in the reverse order.

After the ‘AddTriangle’ command add a second one as follows:

tri = AddTriangle (triangle1,v3,v2,v1)

What is happening is we have defined a second side that connects the original vertices in reverse.

In the first ‘AddTriangle’ command the vertices are connected as v1, v2, v3 – or, bottom left corner, top corner (the peak) and bottom right corner.

The second side is facing the opposite way so the bottom left corners are switched – the bottom left corner (v1) in triangle one is, in fact, now the bottom right corner on the second triangle (the second side).

When you run the program, you will note that the triangle doesn’t disappear from view like it previously did.

So, double-siding a surface is not that hard at all. Lighting it is not as straightforward.

Let’s add our two familiar lights into the code:
Graphics3D 640,480,16,2
SetBuffer BackBuffer()

cam = CreateCamera()
MoveEntity cam, 0,0,-12

light=CreateLight(2) 
LightColor light,0,0,255 
MoveEntity light,1000,1000,-1000 

light2=CreateLight(2) 
LightColor light2,255,0,0 
MoveEntity light2,-1000,1000,-1000 

mesh = CreateMesh()

triangle1 = CreateSurface(mesh)
v1 = AddVertex (triangle1,-2,-2,-2)
v2 = AddVertex (triangle1, 0, 2, -2)
v3 = AddVertex (triangle1, 2,-2,-2)
tri = AddTriangle (triangle1,v1,v2,v3)
tri = AddTriangle (triangle1,v3,v2,v1)

UpdateNormals mesh

While Not KeyHit(1)
TurnEntity mesh,0,1,0

RenderWorld
Flip
Wend
End


When you run the program, you will see that the triangle is not lit by either light.

Pick any one of the ‘AddTriangle’ commands and ‘comment’ it out (add ‘;’ to the start of the line). Re-run the program – notice how the triangle is lit. Uncomment the ‘AddTriangle’ command and repeat with the other ‘AddTriangle’ command.

The end result is the two triangles will light correctly when on their own, but not when both are on screen at the same time. The problem is that the triangles are sharing the same vertex data. When shown together, Blitz cannot light the two sides separately and at once.

If you edit the code and, after ‘UpdateNormals mesh’, add in the following:

VertexNormal triangle1, v1,0,0,-1
VertexNormal triangle1, v2,0,0,-1
VertexNormal triangle1, v3,0,0,-1

This looks a bit more like what we want, however, both triangles are lit using the first triangle's normals - this is because they share the same vertex data (both triangles are formed from the values of v1, v2 and v3). One thing to note, and you will see this when the triangle rotates, the light shining on one side is also lighting the opposite side – i.e., the triangle will be lit while facing the red light and the second triangle, which is facing the blue light, will be lit by the red light. This is the same when being lit by the blue light.

In some circumstances this may not be a problem.

To independently light the 2 sides, we need to create 2 sides:
Graphics3D 640,480,16,2
SetBuffer BackBuffer()

cam = CreateCamera()
MoveEntity cam, 0,0,-12

light=CreateLight(2)
LightColor light,0,0,255
MoveEntity light,1000,1000,-1000

light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-1000,1000,-1000

mesh = CreateMesh()

triangle1 = CreateSurface(mesh)

v1 = AddVertex (triangle1,-2,-2,-2)
v2 = AddVertex (triangle1, 0, 2,-2)
v3 = AddVertex (triangle1, 2,-2,-2)
tri = AddTriangle (triangle1,v1,v2,v3)

triangle2 = CreateSurface(mesh)
v1 = AddVertex (triangle2,-2,-2,-2)
v2 = AddVertex (triangle2, 0, 2,-2)
v3 = AddVertex (triangle2, 2,-2,-2)

tri = AddTriangle (triangle2,v3,v2,v1)

UpdateNormals mesh

While Not KeyHit(1)
TurnEntity mesh,0,1,0
RenderWorld
Flip
Wend
End  

This works very nicely – pay attention to the individual sides, in relation to the lights, as they rotate – looks good.

However, let’s prove the lighting works with a new program. We are going to set the triangle so that it faces the red and blue light – it will be side on. Instead of rotating the triangle, we will rotate the camera, so you will see the lighting on both sides of the triangle. In a nutshell, we want one side to be red and the other to be blue – let’s take a look:
Graphics3D 640,480,16,2
SetBuffer BackBuffer()

c_pivot=CreatePivot()
cam = CreateCamera(c_pivot)
MoveEntity cam, 0,0,-12

light=CreateLight(2)
LightColor light,0,0,255
MoveEntity light,1000,1000,-1000

light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-1000,1000,-1000

mesh = CreateMesh()

triangle1 = CreateSurface(mesh)
v1 = AddVertex (triangle1,-2,-2,-2)
v2 = AddVertex (triangle1, 0, 2,-2)
v3 = AddVertex (triangle1, 2,-2,-2)
tri = AddTriangle (triangle1,v1,v2,v3)

triangle2 = CreateSurface(mesh)
v1 = AddVertex (triangle2,-2,-2,-2)
v2 = AddVertex (triangle2, 0, 2,-2)
v3 = AddVertex (triangle2, 2,-2,-2)
tri = AddTriangle (triangle2,v3,v2,v1)

UpdateNormals mesh

; this would normally be at 90 degrees (0,90,0) but our triangle's centre
; point is slightly off - we have to set the triangle to be side on
TurnEntity mesh, 0,80,0

While Not KeyHit(1)

	If KeyDown(203) Then TurnEntity c_pivot,0,1,0
	If KeyDown(205) Then TurnEntity c_pivot,0,-1,0

RenderWorld
Flip
Wend
End

Use the left and right cursor keys to orbit the triangle – the triangle does not move – the camera orbits on a pivot. You will see that the lighting works – one side is red and the other side is blue.

Let's have a look at a pyramid/cone version:

Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-12

; just a bit of cosmetic lighting
light=CreateLight(2)
LightColor light,0,0,255
MoveEntity light,1000,1000,-1000

; a second bit of cosmetic lighting
light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-1000,1000,-1000

mesh = CreateMesh() 

surface=CreateSurface(mesh)

; This is the first triangle - the one that intially faces you
triangle1 = CreateSurface(mesh)
v1 = AddVertex (triangle1,-2,-2,-2) 
v2 = AddVertex (triangle1, 0, 2, 0) 
v3 = AddVertex (triangle1, 2,-2,-2) 
tri = AddTriangle (triangle1,v1,v2,v3)

; This is the other side of triangle 1
triangle1b = CreateSurface(mesh)
v1 = AddVertex (triangle1b,-2,-2,-2) 
v2 = AddVertex (triangle1b, 0, 2, 0) 
v3 = AddVertex (triangle1b, 2,-2,-2) 
tri = AddTriangle (triangle1b,v3,v2,v1)

; This is triangle 2 - the one that intially faces to the left
triangle2 = CreateSurface(mesh) 
v1 = AddVertex (triangle2, -2,-2, 2) 
v2 = AddVertex (triangle2,  0, 2, 0) 
v3 = AddVertex (triangle2, -2,-2,-2)  
tri = AddTriangle (triangle2,v1,v2,v3)

; This is the other side of triangle 2
triangle2b = CreateSurface(mesh) 
v1 = AddVertex (triangle2b, -2,-2, 2) 
v2 = AddVertex (triangle2b,  0, 2, 0) 
v3 = AddVertex (triangle2b, -2,-2,-2)  
tri = AddTriangle (triangle2b,v3,v2,v1)

; This is triangle 3 - the one that intially faces to the right
triangle3 = CreateSurface(mesh) 
v1 = AddVertex (triangle3, 2,-2,-2) 
v2 = AddVertex (triangle3, 0, 2, 0) 
v3 = AddVertex (triangle3, 2,-2, 2)  
tri = AddTriangle (triangle3,v1,v2,v3)

; This is the other side of triangle 3
triangle3b = CreateSurface(mesh) 
v1 = AddVertex (triangle3b, 2,-2,-2) 
v2 = AddVertex (triangle3b, 0, 2, 0) 
v3 = AddVertex (triangle3b, 2,-2, 2)  
tri = AddTriangle (triangle3b,v3,v2,v1)

; This is triangle 4 - the that intially faces to the rear
triangle4 = CreateSurface(mesh) 
v1 = AddVertex (triangle4, 2,-2, 2) 
v2 = AddVertex (triangle4, 0, 2, 0) 
v3 = AddVertex (triangle4,-2,-2, 2)  
tri = AddTriangle (triangle4,v1,v2,v3)

; This is the other side of triangle 4
triangle4b = CreateSurface(mesh) 
v1 = AddVertex (triangle4b, 2,-2, 2) 
v2 = AddVertex (triangle4b, 0, 2, 0) 
v3 = AddVertex (triangle4b,-2,-2, 2)  
tri = AddTriangle (triangle4b,v3,v2,v1)

UpdateNormals mesh; necessary for correct lighting - not required in this example

x#=.5
y#=.5
z#=.5 
While Not KeyHit(1)
c=c+1
If c=200
	y=Rnd(2)/10
	z=Rnd(2)/10
	c=0
EndIf
TurnEntity mesh,1,y,z
RenderWorld
Flip 
Wend


To better see the double-sided lit effect, edit the end of the code (after 'UpdateNormals mesh') to:
TurnEntity mesh,45,0,0

While Not KeyHit(1)
TurnEntity mesh,0,1,0
RenderWorld
Flip 
Wend



Thanks to "Goober" and "big10p" for giving me code to look at with regard to double-sided surfaces.



The cone - second version - 4 sides(Posted 2004-10-18)
Here is our cone again - this time with 4, not 3, sides (it's now more of a pyramid):
Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-12

; just a bit of cosmetic lighting
light=CreateLight(2)
LightColor light,0,0,255
MoveEntity light,1000,1000,-1000

; a second bit of cosmetic lighting
light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-1000,1000,-1000

mesh = CreateMesh() 

surface=CreateSurface(mesh)

; This is the first triangle - the one that intially faces you
triangle1 = CreateSurface(mesh)
v1 = AddVertex (triangle1,-2,-2,-2) 
v2 = AddVertex (triangle1, 0, 2, 0) 
v3 = AddVertex (triangle1, 2,-2,-2) 
tri = AddTriangle (triangle1,v1,v2,v3)

; This is triangle 2 - the one that intially faces to the left
triangle2 = CreateSurface(mesh) 
v1 = AddVertex (triangle2, -2,-2, 2) 
v2 = AddVertex (triangle2,  0, 2, 0) 
v3 = AddVertex (triangle2, -2,-2,-2)  
tri = AddTriangle (triangle2,v1,v2,v3)

; This is triangle 3 - the one that intially faces to the right
triangle3 = CreateSurface(mesh) 
v1 = AddVertex (triangle3, 2,-2,-2) 
v2 = AddVertex (triangle3, 0, 2, 0) 
v3 = AddVertex (triangle3, 2,-2, 2)  
tri = AddTriangle (triangle3,v1,v2,v3)

; This is triangle 4 - the that intially faces to the rear
triangle4 = CreateSurface(mesh) 
v1 = AddVertex (triangle4, 2,-2, 2) 
v2 = AddVertex (triangle4, 0, 2, 0) 
v3 = AddVertex (triangle4,-2,-2, 2)  
tri = AddTriangle (triangle4,v1,v2,v3)

UpdateNormals mesh; necessary for correct lighting - not required in this example

x#=.5
y#=.5
z#=.5 
While Not KeyHit(1)
c=c+1
If c=200
	x=Rnd(5)/10
	y=Rnd(5)/10
	z=Rnd(5)/10
	c=0
EndIf
TurnEntity mesh,x,y,z
RenderWorld
Flip 
Wend




The cube - second version(Posted 2004-10-18)
With 'The cube - the long way', we created a cube whereby each one of the six faces of the cube had 6 vertices (3 per triangle - 2 triangles). Our new cube is going to be constructed out of 4 vertices per side, but still using 2 triangles per face. So, instead of the 36 vertices of the original, we will have 24 vertices (a saving of 12 vertices).

Let's look at the first surface:
Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-10

mesh = CreateMesh() 

surface=CreateSurface(mesh)

v1=AddVertex(surface,-2,-2,-2); bottom left corner
v2=AddVertex(surface,-2, 2,-2); top left corner
v3=AddVertex(surface, 2, 2,-2); top right corner
v4=AddVertex(surface, 2,-2,-2); bottom right corner

tri1=AddTriangle(surface,v1,v2,v3); the left triangle
tri2=AddTriangle(surface,v1,v3,v4); the right triangle

UpdateNormals mesh; necessary for correct lighting - not required in this example

RenderWorld
Flip 
WaitKey
End


Let's compare it to the original:
Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-10

mesh = CreateMesh()

surface=CreateSurface(mesh)

; This is the left-hand first triangle - the one that intially faces you
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2,-2); bottom left corner
v1 = AddVertex (triangle1,-2, 2,-2); top left corner
v2 = AddVertex (triangle1, 2, 2,-2); top right corner

tri = AddTriangle (triangle1,v0,v1,v2)

; This is the right-hand first triangle - the one that intially faces you
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2,-2); bottom left corner - this is now the correct comment
v1 = AddVertex (triangle1, 2, 2,-2); top right corner - this is now the correct comment
v2 = AddVertex (triangle1, 2,-2,-2); bottom right corner - this is now the correct comment

tri = AddTriangle (triangle1,v0,v1,v2)

UpdateNormals mesh; necessary for correct lighting - not required in this example

RenderWorld
Flip 
WaitKey
End

In the new code, I cannot really use 'AddVertex (triangle1, etc)' as there now isn't a triangle defined by the vertices - it is a square. So, I have used 'AddVertex(surface,etc)'.

The other main difference is that we are now using two 'AddTriangle' commands straight after we set up the 4 vertices, rather than one per triangle defined.
Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-12

; just a bit of cosmetic lighting
light=CreateLight(2)
LightColor light,0,0,255
MoveEntity light,1000,1000,-1000

; a second bit of cosmetic lighting
light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-1000,1000,-1000

mesh = CreateMesh() 

surface=CreateSurface(mesh)

; this is the front face of the cube - the one initially facing you
v1=AddVertex(surface,-2,-2,-2); bottom left corner
v2=AddVertex(surface,-2, 2,-2); top left corner
v3=AddVertex(surface, 2, 2,-2); top right corner
v4=AddVertex(surface, 2,-2,-2); bottom right corner

tri1=AddTriangle(surface,v1,v2,v3); the left triangle
tri2=AddTriangle(surface,v1,v3,v4); the right triangle

; this is the left face of the cube - the one initially facing left
v1=AddVertex(surface,-2,-2, 2); bottom left corner
v2=AddVertex(surface,-2, 2, 2); top left corner
v3=AddVertex(surface,-2, 2,-2); top right corner
v4=AddVertex(surface,-2,-2,-2); bottom right corner

tri1=AddTriangle(surface,v1,v2,v3); the left triangle
tri2=AddTriangle(surface,v1,v3,v4); the right triangle

; this is the right face of the cube - the one initially facing right
v1=AddVertex(surface, 2,-2,-2); bottom left corner
v2=AddVertex(surface, 2, 2,-2); top left corner
v3=AddVertex(surface, 2, 2, 2); top right corner
v4=AddVertex(surface, 2,-2, 2); bottom right corner

tri1=AddTriangle(surface,v1,v2,v3); the left triangle
tri2=AddTriangle(surface,v1,v3,v4); the right triangle

; this is the rear face of the cube - the one initially facing the rear
v1=AddVertex(surface, 2,-2, 2); bottom left corner
v2=AddVertex(surface, 2, 2, 2); top left corner
v3=AddVertex(surface,-2, 2, 2); top right corner
v4=AddVertex(surface,-2,-2, 2); bottom right corner

tri1=AddTriangle(surface,v1,v2,v3); the left triangle
tri2=AddTriangle(surface,v1,v3,v4); the right triangle

; this is the top face of the cube - the one initially facing the up
v1=AddVertex(surface,-2, 2,-2); bottom left corner
v2=AddVertex(surface,-2, 2, 2); top left corner
v3=AddVertex(surface, 2, 2, 2); top right corner
v4=AddVertex(surface, 2, 2,-2); bottom right corner

tri1=AddTriangle(surface,v1,v2,v3); the left triangle
tri2=AddTriangle(surface,v1,v3,v4); the right triangle

; this is the bottom face of the cube - the one initially facing the down
v1=AddVertex(surface,-2,-2, 2); bottom left corner
v2=AddVertex(surface,-2,-2,-2); top left corner
v3=AddVertex(surface, 2,-2,-2); top right corner
v4=AddVertex(surface, 2,-2, 2); bottom right corner

tri1=AddTriangle(surface,v1,v2,v3); the left triangle
tri2=AddTriangle(surface,v1,v3,v4); the right triangle

UpdateNormals mesh; necessary for correct lighting - not required in this example

x#=.5
y#=.5
z#=.5 
While Not KeyHit(1)
c=c+1
If c=200
	x=Rnd(5)/10
	y=Rnd(5)/10
	z=Rnd(5)/10
	c=0
EndIf
TurnEntity mesh,x,y,z
RenderWorld
Flip 
Wend
End



Thanks to "Cygnus" and "TomToad" for persevering and answering questions, and also supplying code, to my intial questions regarding Blitz3D's capability to use 4 vertices at once.



The cube - the long way(Posted 2004-10-17)
Here is the cube - done the long way - also while doing this, I spotted that the 'surface' name ('triangle1') is re-usable. I hadn't meant to do that - I will re-write them to be more specific. However, at least we now know you can call every surface the same.

Again, when running the code, you have to press a key to 'unpause' it.

Need to correct the comments in the code to show the correct corners - serves me right for pasting and then editing the values but not the comments.

Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 

; just a bit of cosmetic lighting
light=CreateLight(2)
LightColor light,0,0,255
MoveEntity light,1000,1000,-1000

; a second bit of cosmetic lighting
light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-1000,1000,-1000

; I prefer having the camera initiated at the top of the code
cam = CreateCamera() 
MoveEntity cam, 0,0,-10

mesh = CreateMesh() 

; This is the left-hand first triangle - the one that intially faces you
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2,-2); botom left corner
v1 = AddVertex (triangle1,-2, 2,-2); top left corner
v2 = AddVertex (triangle1, 2, 2,-2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the right-hand first triangle - the one that intially faces you
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2,-2); botom left corner
v1 = AddVertex (triangle1, 2, 2,-2); top left corner
v2 = AddVertex (triangle1, 2,-2,-2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the left-hand second triangle - the one that intially faces left
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2, 2); botom left corner
v1 = AddVertex (triangle1,-2, 2, 2); top left corner
v2 = AddVertex (triangle1,-2, 2,-2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the right-hand second triangle - the one that intially faces left
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2, 2); botom left corner
v1 = AddVertex (triangle1,-2, 2,-2); top left corner
v2 = AddVertex (triangle1,-2,-2,-2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the left-hand third triangle - the one that intially faces right
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1, 2,-2,-2); botom left corner
v1 = AddVertex (triangle1, 2, 2,-2); top left corner
v2 = AddVertex (triangle1, 2, 2, 2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the right-hand third triangle - the one that intially faces right
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1, 2,-2,-2); botom left corner
v1 = AddVertex (triangle1, 2, 2, 2); top left corner
v2 = AddVertex (triangle1, 2,-2, 2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the left-hand fourth triangle - the one that intially faces the rear
; the left-hand triangle is the left one as you face the *visible* surface
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1, 2,-2, 2); botom left corner
v1 = AddVertex (triangle1, 2, 2, 2); top left corner
v2 = AddVertex (triangle1,-2, 2, 2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the right-hand fourth triangle - the one that intially faces the rear
; the right-hand triangle is the right one as you face the *visible* surface
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1, 2,-2, 2); botom left corner
v1 = AddVertex (triangle1,-2, 2, 2); top left corner
v2 = AddVertex (triangle1,-2,-2, 2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the left-hand fifth triangle - the one that intially faces up
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2, 2,-2); botom left corner
v1 = AddVertex (triangle1,-2, 2, 2); top left corner
v2 = AddVertex (triangle1, 2, 2, 2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the right-hand fifth triangle - the one that intially faces up
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2, 2,-2); botom left corner
v1 = AddVertex (triangle1, 2, 2, 2); top left corner
v2 = AddVertex (triangle1, 2, 2,-2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the left-hand sixth triangle - the one that intially faces down
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2, 2); botom left corner
v1 = AddVertex (triangle1,-2,-2,-2); top left corner
v2 = AddVertex (triangle1, 2,-2,-2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

; This is the right-hand sixth triangle - the one that intially faces down
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2, 2); botom left corner
v1 = AddVertex (triangle1, 2,-2,-2); top left corner
v2 = AddVertex (triangle1, 2,-2, 2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)

UpdateNormals mesh; necessary for correct lighting

RenderWorld
Flip
WaitKey
 
While Not KeyHit(1)
TurnEntity mesh,.5,.5,.5
RenderWorld
Flip 
Wend


The cube was easy - once I had worked out the first face (the front one), I did the others virtually in my head. I got stuck with the final (downards facing one) and had to work it out on paper.

The single-sided basis of our cube is great for this example as you never see the inside of it (or at least not intentially). Ever noticed in a FPS game that when you cheat and deactivate clipping (ghost mode) you can walk inside a building, etc. and it appears transparent? Same thing, you were not meant to be in there (or at least not while in 'ghost' mode) - it is single-sided.

The reason why the cube was easy is because it only has 8 unique vertices. I speeded up design by drawing a 3D cube on a piece of paper - starting with a square, then making it a 3D cube. I then marked the coordinates in 3D space of each of the 8 corners - each corner is used 3 times by 3 different triangles which are on 3 different faces of the cube. Having drawn the 3D cube on paper and pre-calculated the 8 corners, it was easy.

Each left-hand triangle drawn is from the relevent bottom left corner, straight up to the next corner, straight along to the right corner and then diagonally down and to the left (back to the start point) - example below:

Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 
cam = CreateCamera() 
MoveEntity cam, 0,0,-10
mesh = CreateMesh() 
; This is the left-hand first triangle
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2,-2); bottom left corner
v1 = AddVertex (triangle1,-2, 2,-2); top left corner
v2 = AddVertex (triangle1, 2, 2,-2); top right corner
tri = AddTriangle (triangle1,v0,v1,v2)
RenderWorld
Flip
WaitKey
End


The right-hand triangles are drawn from the relevent bottom left corner (as with the left-hand version), diagonally up and to the right corner, then straight down to the bottom left corner and then straight left to the starting point - example below:
Graphics3D 640,480,16,2 
SetBuffer BackBuffer() 
cam = CreateCamera() 
MoveEntity cam, 0,0,-10
mesh = CreateMesh() 
; This is the left-hand first triangle
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2,-2); bottom left corner
v1 = AddVertex (triangle1, 2, 2,-2); top right corner
v2 = AddVertex (triangle1, 2,-2,-2); bottom right corner
tri = AddTriangle (triangle1,v0,v1,v2)
RenderWorld
Flip
WaitKey
End

To give a bit more variety to the rotations amend the final block of code (after 'UpdateNormals mesh; necessary for correct lighting') to:
x#=.5
y#=.5
z#=.5 
While Not KeyHit(1)
c=c+1
If c=200
	x=Rnd(5)/10
	y=Rnd(5)/10
	z=Rnd(5)/10
	c=0
EndIf
TurnEntity mesh,x,y,z
RenderWorld
Flip 
Wend
End

Conclusion: Our cube looks good, but it is not as efficiently constructed as it could be - too much re-using vertices. There are always going to be 12 triangles (6 sides having 2 each), but they can be formed more efficiently.



Centering the cone(Posted 2004-10-17)
We know the cone was rotating oddly because, of the way I had plotted the cone's vertices which meant the centre point (0,0,0 in 3D space) was not the centre of the cone. Blitz3D was rotating around what it saw as the centre of the cone.

The following code shows the new cone - centred in 3D space. Note the slight changes in the vertices:

Graphics3D 640,480 
SetBuffer BackBuffer() 


; just a bit of cosmetic lighting
light=CreateLight()
MoveEntity light,0,0,-50

; I prefer having the camera initiated at the top of the code
cam = CreateCamera() 
MoveEntity cam, 0,0,-10; I have moved the camera in a bit

mesh = CreateMesh() 

; This is the first triangle - the one that initially faces you
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2,-2) 
v1 = AddVertex (triangle1, 2,-2,-2) 
v2 = AddVertex (triangle1, 0, 2, 0) 
tri = AddTriangle (triangle1,v0,v2,v1)

UpdateNormals mesh; necessary for correct lighting

; This is triangle 2 - the one on the left of the first triangle and the one that faces to the left
triangle2 = CreateSurface(mesh) 
v0 = AddVertex (triangle2,  0,-2, 2) ;*********
v1 = AddVertex (triangle2, -2,-2,-2) 
v2 = AddVertex (triangle2,  0, 2, 0)  
tri = AddTriangle (triangle2,v0,v2,v1)

UpdateNormals mesh; necessary for correct lighting

; This is triangle 3 - the one on the right of the first triangle and the one that faces to the right
triangle3 = CreateSurface(mesh) 
v0 = AddVertex (triangle3, 2,-2,-2) 
v1 = AddVertex (triangle3, 0,-2, 2) ;*********
v2 = AddVertex (triangle3, 0, 2, 0)  
tri = AddTriangle (triangle3,v0,v2,v1)

UpdateNormals mesh; necessary for correct lighting

RenderWorld
Flip
WaitKey
 
While Not KeyHit(1)
TurnEntity mesh,0,.5,0


RenderWorld
Flip 
Wend
End


When running this code - take a good look at the triangle on screen - then press a key - notice how something does not appear right - the cone is sort of leaning.

The problem is with 'v1' of triangle 3 (the right-hand one) and 'v0' of the triangle 2 (the left-hand one). Technically, the values might seem logical but, if you were to plot the points on graph paper (in plan view - looking down from above) and measure the distance of 'v0' and 'v1' of triangle 1 and then compare the measurement of 'v0' and 'v1' of triangles 2 and 3, you'll spot a slight difference in length.

It is possible to correct this - the reason why this happened is because we are using 3 surfaces. You could design the cone out of 4 triangles and not have to worry about this sort of thing. To test that - draw a square on a piece of paper now diagonally connect the corners - you have an 'x' inside a square - or, a plan view from above the peak of a pyramid/cone.

The 4 sided pyramid/cone is obviously going to be easier to design, but the trade off here is that you are creating a fourth triangle to make it easier.

Let's just take a quick look at the 'UpdateNormals mesh' that I added in 3 times in the above code. Comment out the last 2 - add a ';' to the start of the lines. The only active 'UpdateNormals mesh' should be the one after Triangle 1. Now re-run the program.

Notice how only the first triangle is lit. Right, let's make the second 'UpdateNormals mesh' active and then re-run the program.

Notice not only are both lit, but you can also clearly see the light shading as the mesh rotates. The third triangle is neither lit nor shaded.

You can now comment out or remove the fist two 'UpdateNormals mesh' and just leave the final one active. A quick check of the Blitz3D docs for 'UpdateNormals' will reveal:

Recalculates all normals in a mesh. This is necessary for correct lighting if you have not set surface normals using 'VertexNormals' commands.

Forget about 'VertexNormals' for now.

Okay, let's change the lighting:

; just a bit of cosmetic lighting
light=CreateLight(2)
MoveEntity light,10,0,0

We have changed the light from the default directional light to point lighting. Plus, we have moved the light source to the right of the cone. You'll note the lighting here is a bit too aggressively applied to the entire surface of each triangle.

Let's add a second light - a red light - and position that to the left of the cone:

; just a bit of cosmetic lighting
light=CreateLight(2)
MoveEntity light,10,0,0

; a second bit of cosmetic lighting
light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-10,0,0

Now we are seeing the lighting becoming 'confused'.

Note: Just in case you are not seeing it clearly, or want to see it clearer then you can change the speed of rotation whenever you feel like it by altering 'TurnEntity mesh,0,.5,0' to whatever values you want.

The main issue we have here is the surfaces are being lit equally by the light across the entire surface of each triangle instead of being more subtly shaded.

Let's now look at something weird - really weird. Change both lights back to the default directional light:

; just a bit of cosmetic lighting
light=CreateLight(1)
MoveEntity light,10,0,0

; a second bit of cosmetic lighting
light2=CreateLight(1)
LightColor light2,255,0,0
MoveEntity light2,-10,0,0

Can you spot the weird thing? Remember, the red light source is on the left of the cone.

Also, the red light is very light in colour (almost pink) - the white light is more dominant.

Alright then, let's make the first light blue instead of the default white. Amend the first light to:

; just a bit of cosmetic lighting
light=CreateLight(1)
LightColor light,0,0,255
MoveEntity light,10,0,0

When you run the program you now see a pink cone.

If you comment out (by adding ';') to the block of second light code, you'll see that the light is actually blue.

Maybe another light - a third light - is interfering with our cone? But, we only have two lights in the code.

The third light is ambient light - this one can drastically effect the results. After the blocks of lighting add in:

AmbientLight 0,0,0

Run the program - alter ambient light to various levels (100,100,1000 and 200,200,200) to see the difference.

If you, as well as changing ambient light, also change the types of light 1, 2 or 3 - you'll see differing effects created by various lights with ambient light.

Back to the original - the problem is our light source(s) are too near - change the lighting block of code to:

; just a bit of cosmetic lighting
light=CreateLight(2)
LightColor light,0,0,255
MoveEntity light,1000,1000,-1000

; a second bit of cosmetic lighting
light2=CreateLight(2)
LightColor light2,255,0,0
MoveEntity light2,-1000,1000,-1000

AmbientLight 0,0,0

That's more like it, now our cone is rotating and the light is nicely shading subtly across the surface of each triangle.



The cube - probably the final version(Posted 2004-10-16)
The base cube has 6 faces (sides) and, potentially, 24 vertices. However, a cube can be defined by 8 points.

With 24 vertices, each point is being defined three times - 3 x 8 = 24.



Vertices 8 - polys 6

-2, 2, 2
-2, 2, -2
2, 2, -2
2, 2, 2
-2, -2, 2
2, -2, 2
2, -2, -2
-2, -2, -2

Dreamora (Posted 2004-10-14 18:41:02)
I would not use 6 surfaces normally.

6 indipendent quads ( 24 vertices ) are enough as the texturing problem only happens if the cube is created out of 8 vertices in which case 1 UV should hold for 3 different quads which is impossible.



Can get a pyramid from vertex data with index

0, 4, 0
6, -2, 6
6, -2, -6
-6, -2, -6
-6, -2, 6



To do(Posted 2004-10-16)
THIS WORKLOG IS IN REVERSE - YOU HAVE TO READ FROM THE BOTTOM UP - sniff. EVEN WORSE, I AM NOW DOING IT IN NO PARTICULAR ORDER - I MIGHT JUMP FROM TOPIC TO TOPIC OVER TIME OR CREATE NEW ONES BEFORE I FINISH OTHERS

Re-introduce the square as a 4 vertice, 2 triangle example.

Use the original Blitz Research triangle x3 to cone - introduce rotation and colour shade the 3 - the fact that this will be hollow will nicely introduce double-siding.

Do a cube - again, with various vertex structures - lift a lid - colour shade and re-cover double-siding.

Vertex Piglet



The cone(Posted 2004-10-16)
Right, let’s use Blitz3D’s built-in example and resize the triangle – just paste in the following as a new program:

Graphics3D 640,480 
SetBuffer BackBuffer() 

mesh = CreateMesh() 
surf = CreateSurface(mesh) 

v0 = AddVertex (surf,-2,-2,0) 
v1 = AddVertex (surf, 2,-2,0) 
v2 = AddVertex (surf, 0, 2,0) 

tri = AddTriangle (surf,v0,v2,v1) 

cam = CreateCamera() 
MoveEntity cam, 0,0,-7 

RenderWorld 
Flip 

WaitKey 
End


What we want to do is create another two of the triangles and position them to make a pyramid. However, because there will be no base to the pyramid, we’ll actually end up with a cone. Again, we are going to do this the long way (not the most efficient way) – i.e. create an additional 2 triangles in the same way the first one has been created.

This is going to introduce all 3 planes (x,y,z) – modelling in 3D is more difficult and, as of yet, I have no clear way of guiding you – still use graph paper as much as possible though.

The initial triangle in the above program is fine where it is. However, the top of it will have to lean into the screen, when the two other triangles are added they will also lean – all three will meet each other and form a cone.

The easiest way of creating the second triangle will be by adding it in with the first triangle, rather than creating it separately – this way you can work out where to position it. For the time being we will not make any of the triangles lean – let’s just add them one at a time into their correct positions for their base, then lean them into their final positions.

From the code that you have on the screen (the above program listing), highlight and copy the following section:

surf = CreateSurface(mesh)

v0 = AddVertex (surf,-2,-2,0)
v1 = AddVertex (surf, 2,-2,0)
v2 = AddVertex (surf, 0, 2,0)

tri = AddTriangle (surf,v0,v2,v1)


Paste the copy below ‘tri = AddTriangle (surf,v0,v2,v1)’. You should now have the following on screen:
Graphics3D 640,480 
SetBuffer BackBuffer() 

mesh = CreateMesh() 
surf = CreateSurface(mesh) 

v0 = AddVertex (surf,-2,-2,0) 
v1 = AddVertex (surf, 2,-2,0) 
v2 = AddVertex (surf, 0, 2,0) 

tri = AddTriangle (surf,v0,v2,v1)

surf = CreateSurface(mesh) 

v0 = AddVertex (surf,-2,-2,0) 
v1 = AddVertex (surf, 2,-2,0) 
v2 = AddVertex (surf, 0, 2,0) 

tri = AddTriangle (surf,v0,v2,v1) 
 

cam = CreateCamera() 
MoveEntity cam, 0,0,-7 

RenderWorld 
Flip 

WaitKey 
End


Now amend the block that you just pasted in to:

Surf2 = CreateSurface(mesh)

v0 = AddVertex (surf2,-2,-2,0)
v1 = AddVertex (surf2, 2,-2,0)
v2 = AddVertex (surf2, 0, 2,0)

tri = AddTriangle (surf2,v0,v2,v1)


Basically, we just changed ‘Surf’ to ‘Surf2’ for the second block of ‘AddVertex’ (including ‘AddTriangle’).

Perchance you run the program, you will see one triangle (as before) – this is because the new triangle is being displayed in the same 3 dimensional place as the first triangle.

Moving the second triangle into place is very fiddly and (for a beginner) is initially going to be a lot of trial and error and messing about.

The second triangle will be placed on the left-hand side of the first one – if you imagine the one on your screen currently (the first one) as facing south (towards you), then the second one is going to be facing west (facing to the left) – so, it will be virtually invisible as it will be completely side-on to your view of it.

The second triangle is going to make extensive use of the ‘z’ (depth) plane. It is the same size and shape as the first triangle and the vertices are exactly the same scale and distance as regard the first triangle.

Let’s take a look at the first triangle’s vertices again:

v0 = AddVertex (surf,-2,-2,0)
v1 = AddVertex (surf, 2,-2,0)
v2 = AddVertex (surf, 0, 2,0)


Notice how the third parameter (‘z’) are all set to 0 – well they won’t be in the second triangle. The ‘x’ values move left/right on your screen – remember your second triangle is going to be side-on so its width is going to be in the 'z' (depth) plane - in/out of the screen.

v0 = AddVertex (surf2, -2,-2,4)
v1 = AddVertex (surf2, -2,-2,0)
v2 = AddVertex (surf2, -2, 2,2)


If you edit your second block with the new values and run the program, you will still only see the initial triangle – that is because the second triangle is side-on to your viewpoint – it is there, but not visible – yet.

Right, let’s create a new program – it is the same as the one you have created – I just modified it and added in a cheap rotation to show you the second triangle (in motion):
Graphics3D 640,480 
SetBuffer BackBuffer() 

; I prefer having the camera initiated at the top of the code
c_pivot=CreatePivot()
cam = CreateCamera(c_pivot) 
MoveEntity cam, 0,0,-10; I have moved the camera out a bit

mesh = CreateMesh() 

; This is the first triangle - the one that initially faces you
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2,0) 
v1 = AddVertex (triangle1, 2,-2,0) 
v2 = AddVertex (triangle1, 0, 2,0) 
tri = AddTriangle (triangle1,v0,v2,v1)

; This is triangle 2 - the one on the left of the first triangle and the one that faces to the left
triangle2 = CreateSurface(mesh) 
v0 = AddVertex (triangle2, -2,-2,4) 
v1 = AddVertex (triangle2, -2,-2,0) 
v2 = AddVertex (triangle2, -2, 2,2)  
tri = AddTriangle (triangle2,v0,v2,v1) 
 
While Not KeyHit(1)
TurnEntity c_pivot,0,.5,0; technically this is a cheap rotation
RenderWorld 
Flip 
Wend
End


When you run this, you will see the first triangle rotate out of view – you’ll have to wait for the second triangle to rotate into view – this is because the triangles are all single-sided – so you cannot see the back of them when they rotate. Once you have watched the rotation a few times, you’ll see this factor.

We now need to look at how the second triangle was positioned. Well, one clue is the right hand corner of the second triangle would have had to touch the left-hand corner of the first triangle – this means ‘v0’ of the first triangle and ‘v1’ of the second triangle will have the same values – because they are in the same position in 3D space.

Take a piece of paper – cut out a square – cut the square diagonally – you now have two triangles – you can now position the paper versions where you want. How about on a piece of graph paper? Have the graph paper horizontal (like a mouse mat) and stand the two triangles upright on it - you are now positioning them in the ‘x’ and ‘z’ planes.

Let's move onto the third triangle. This one is a bit easier to position on the basis that we have positioned the second triangle - it's just the third triangle is a little further along the 'x' plane:

; This is triangle 3 - the one on the right of the first triangle and the one that faces to the right
triangle3 = CreateSurface(mesh)
v0 = AddVertex (triangle3, 2,-2,0)
v1 = AddVertex (triangle3, 2,-2,4)
v2 = AddVertex (triangle3, 2, 2,2)
tri = AddTriangle (triangle3,v0,v2,v1)

This one was a doddle (having already done the second triangle). This time ‘v1’ of the first triangle and ‘v0’ of the third triangle have the same values.

Getting them to lean so that their 'peaks' meet is now easy - in each case only 'v2' (the peak) for each triangle needs altering:

v2 = AddVertex (triangle1, 0, 2,2)
v2 = AddVertex (triangle2, 0, 2,2)
v2 = AddVertex (triangle3, 0, 2,2)


We now know that 'v0' of triangle 2 (the left one) and 'v1' of triangle 3 (the right one) have to be the same (touching). It's just a case of moving them by 2 units along their 'x' plane towards each other (to meet). Each one has to move the same distance along the 'x' plane.

v0 = AddVertex (triangle2, 0,-2,4)
v1 = AddVertex (triangle3, 0,-2,4)


If you cut out a second paper triangle, you can position them on your graph paper and see their positions in the 'x' and 'z' planes.

The cone is now complete:
; This is the first triangle - the one that initially faces you
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2,0) 
v1 = AddVertex (triangle1, 2,-2,0) 
v2 = AddVertex (triangle1, 0, 2,2) 
tri = AddTriangle (triangle1,v0,v2,v1)

; This is triangle 2 - the one on the left of the first triangle and the one that faces to the left
triangle2 = CreateSurface(mesh) 
v0 = AddVertex (triangle2,  0,-2,4) 
v1 = AddVertex (triangle2, -2,-2,0) 
v2 = AddVertex (triangle2,  0, 2,2)  
tri = AddTriangle (triangle2,v0,v2,v1)

; This is triangle 3 - the one on the right of the first triangle and the one that faces to the right
triangle3 = CreateSurface(mesh) 
v0 = AddVertex (triangle3, 2,-2,0) 
v1 = AddVertex (triangle3, 0,-2,4) 
v2 = AddVertex (triangle3, 0, 2,2)  
tri = AddTriangle (triangle3,v0,v2,v1)


Right, let's now take a look at the fact that our cone is hollow (it is basically a pyramid with no base) and also taking into account that the surfaces are single-sided (you can only see them from one side):

Graphics3D 640,480 
SetBuffer BackBuffer() 

; just a bit of cosmetic lighting
light=CreateLight()
MoveEntity light,0,0,-50

; I prefer having the camera initiated at the top of the code
cam = CreateCamera() 
MoveEntity cam, 0,0,-20; I have moved the camera out a bit

mesh = CreateMesh() 

; This is the first triangle - the one that initially faces you
triangle1 = CreateSurface(mesh)
v0 = AddVertex (triangle1,-2,-2,0) 
v1 = AddVertex (triangle1, 2,-2,0) 
v2 = AddVertex (triangle1, 0, 2,2) 
tri = AddTriangle (triangle1,v0,v2,v1)

UpdateNormals mesh; necessary for correct lighting

; This is triangle 2 - the one on the left of the first triangle and the one that faces to the left
triangle2 = CreateSurface(mesh) 
v0 = AddVertex (triangle2,  0,-2,4) 
v1 = AddVertex (triangle2, -2,-2,0) 
v2 = AddVertex (triangle2,  0, 2,2)  
tri = AddTriangle (triangle2,v0,v2,v1)

UpdateNormals mesh; necessary for correct lighting

; This is triangle 3 - the one on the right of the first triangle and the one that faces to the right
triangle3 = CreateSurface(mesh) 
v0 = AddVertex (triangle3, 2,-2,0) 
v1 = AddVertex (triangle3, 0,-2,4) 
v2 = AddVertex (triangle3, 0, 2,2)  
tri = AddTriangle (triangle3,v0,v2,v1)

UpdateNormals mesh; necessary for correct lighting
 
While Not KeyHit(1)
TurnEntity mesh,.5,0,0; this different rotation - we are now turning the mesh, not the camera

RenderWorld
Flip 
Wend
End


You'll note that this code is modified and has had lighting added.


The perspective is a bit weird, but that is probably the camera - the positioning of the triangles is correct. In fact, it is because of the centre point of our newly created mesh - technically, this can be fixed on-the-fly, but I will re-design the cone instead. It will probably be good practice to always consider and plan the centre point of any mesh as you created it.

I don't like Blitz's built-in example which utilises 'tri = AddTriangle (surf,v0,v2,v1)'. A beginner would expect v0,v1,v2.




Part one(Posted 2004-10-15)
THIS DRAFT (Part one) is not complete and I may start on a new section prior to completing it - I am making it up as I go and may drift all over the place.

Part one is aimed to discuss 'AddVertex' and 'AddTriangle' - these two commands form the basis of actually creating something interesting.

Designing vertex stuff is initially very fiddly and time consuming (especially for a beginner – like me). Ideally, plot you vertices on graph-type paper - or just draw horizontal and vertical lines on a piece of paper - this is mainly of use if you are working with only 2 dimensions. The values in the AddVertex command are purely points in 3D space in the same way you would position an entity in x,y,z. Remember that the x, y and z values can be positive and negative. Initially, it is probably best to just work in x and y coordinates – save z (depth) to later.

Using graph paper certainly seems to be beneficial for me to work out where I want to place the vertex coordinates. You can also use this method to ‘decode’ other peoples vertex coordinates.

Also, remember you can copy and paste – no need to type stuff in – you can just copy and paste

Also, to help you learn the coordinates of the vertices, you can strip out the use of the 'u' and 'v' parameters:

--------------------------X..Y..Z..U..V
v0 = AddVertex (surf,-5,-5, 0, 0 , 0)
v1 = AddVertex (surf, 5,-5, 0, 1 , 0)
v2 = AddVertex (surf, 0, 5, 0, 0.5, 1)

Becomes:

--------------------------X..Y..Z
v0 = AddVertex (surf,-5,-5, 0)
v1 = AddVertex (surf, 5,-5, 0)
v2 = AddVertex (surf, 0, 5, 0)


The above is initially easier to read as you are now just seeing your familiar x,y,z values. Until you start texturing you don't need to worry too much about the 'u' and 'v' texture coordinates of the vertex.

To get quick access to the built-in example in Blitz3D, start Blitz3D and create a new program - type 'AddVertex', select it with the mouse (left-click on it), then press 'F1' twice. To run the built-in Blitz3D example program, left-click on the word ‘Example’ (the one in yellow coloured text).

One thing I would advise when using the built-in Blitz3D example code is that you can accidentally overwrite the example code – this is not a huge problem as you can re-copy the hard-code from the help screen and paste it back. So, to avoid accidents, when you go to the help screen, instead of clicking on the word ‘Example’ just copy the code example from the current screen (the code block that appears under the word ‘Example’ and then paste it in as new program code.

The built-in Blitz3D example draws a simple triangle on the screen. Let’s suppose we want a square - two triangles make a square - but the one on your screen is the wrong shape. So, we need to create a new triangle:

Instead of:

v0 = AddVertex (surf, -5,-5,0, 0 ,0)
v1 = AddVertex (surf, 5,-5,0, 1 ,0)
v2 = AddVertex (surf, 0, 5,0, 0.5,1)


Take note that the built-in Blitz3D example is a bit scruffily typed - it's best to space your values so that you can clearly see them in columns (as below):

We want:

v0 = AddVertex (surf2,-5,-5, 0)
v1 = AddVertex (surf2, 5,-5, 0)
v2 = AddVertex (surf2, 0, 5, 0)

You'll note that the triangle is a bit large, so let's scale it down – just amend all of the values of 5 to 2:

v0 = AddVertex (surf1,-2, 2, 0); top left corner
v1 = AddVertex (surf1, 2, 2, 0); top right corner
v2 = AddVertex (surf1,-2,-2, 0); bottom left corner

Floating point values (not whole numbers) are perfectly legal:

v0# = AddVertex (surf1,-2.5, 2.5, 0); top left corner
v1# = AddVertex (surf1, 2.5, 2.5, 0); top right corner
v2# = AddVertex (surf1,-2.5,-2.5, 0); bottom left corner

Let's look at something interesting:

v0# = AddVertex (surf1,-0.5, 0.5, 0); top left corner
v1# = AddVertex (surf1, 0.5, 0.5, 0); top right corner
v2# = AddVertex (surf1,-0.5,-0.5, 0); bottom left corner

Change the 'x' parameter of 'v0' to '1.5'

....................................***
v0# = AddVertex (surf1,-1.5, 0.5, 0); top left corner
....................................***
v1# = AddVertex (surf1, 0.5, 0.5, 0); top right corner
v2# = AddVertex (surf1,-0.5,-0.5, 0); bottom left corner


You should see another triangle - the new triangle is NOT a rotation, it is a completely different triangle that was created by altering just one value.

Anyway, back to our square - we already have the left side of the square:

v0 = AddVertex (surf2,-5,-5, 0); top left corner
v1 = AddVertex (surf2, 5,-5, 0); top right corner
v2 = AddVertex (surf2, 0, 5, 0); bottom left corner

tri = AddTriangle (surf1,v0,v1,v2); this is the left-hand triangle of our square


Let's now add in the right side of the square.

Note: this is not the most efficient way, but it is a logical way for a beginner:

Draw a square on a piece of paper - put a little circle around each corner - draw a diagonal line from any one corner to another – you now have a square made of two triangles and 4 circled corners (vertices). However, let's suppose that the 2 triangles can come apart - you'd now have 6 vertices (3 on each triangle).

Let’s create a second triangle:

v0 = AddVertex (surf2, 2, 2, 0); top right corner
v1 = AddVertex (surf2, 2,-2, 0); bottom right corner
v2 = AddVertex (surf2,-2,-2, 0); bottom left corner

tri = AddTriangle (surf2,v0,v1,v2)


The complete code to show them both on screen together is:
Graphics3D 640,480 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-5 


mesh = CreateMesh()
 
surf1 = CreateSurface(mesh); left-hand triangle of square 
;                       x  y  z
v0# = AddVertex (surf1,-2, 2, 0); top left corner
v1# = AddVertex (surf1, 2, 2, 0); top right corner 
v2# = AddVertex (surf1,-2,-2, 0); bottom left corner 
tri = AddTriangle (surf1,v0,v1,v2); this is the left-hand triangle of our square

surf2 = CreateSurface(mesh); right-hand triangle of square 
;                      x, y, z
v0 = AddVertex (surf2, 2, 2, 0); top right corner 
v1 = AddVertex (surf2, 2,-2, 0); bottom right corner
v2 = AddVertex (surf2,-2,-2, 0); bottom left corner 
tri = AddTriangle (surf2,v0,v1,v2) 

RenderWorld 
Flip 

WaitKey 
End 

Before proceeding - let's take a look at 'AddTriangle':

Reset your program to:
Graphics3D 640,480 
SetBuffer BackBuffer() 

cam = CreateCamera() 
MoveEntity cam, 0,0,-5 

mesh = CreateMesh()
 
surf1 = CreateSurface(mesh); left-hand triangle of square 
;                       x  y  z
v0# = AddVertex (surf1,-2, 2, 0); top left corner
v1# = AddVertex (surf1, 2, 2, 0); top right corner 
v2# = AddVertex (surf1,-2,-2, 0); bottom left corner 
tri = AddTriangle (surf1,v0,v1,v2); this is the left-hand triangle of our square

RenderWorld 
Flip 

WaitKey 
End 

The 'AddTriangle' command does not technically have to be in the order shown (tri = AddTriangle
(surf1,v0,v1,v2))

You can copy and paste the following in to take a look at the results:

tri = AddTriangle (surf1,v1,v2,v0)
tri = AddTriangle (surf1,v2,v1,v0)
tri = AddTriangle (surf1,v1,v0,v2)
tri = AddTriangle (surf1,v2,v0,v1)
tri = AddTriangle (surf1,v0,v2,v1)


Just to save you the time:

These three (including the original) show the triangle (the same triangle)

tri = AddTriangle (surf1,v0,v1,v2)
tri = AddTriangle (surf1,v1,v2,v0)
tri = AddTriangle (surf1,v2,v0,v1)


These three do not produce a visible result - you get a blank, black, screen:

tri = AddTriangle (surf1,v2,v1,v0)
tri = AddTriangle (surf1,v1,v0,v2)
tri = AddTriangle (surf1,v0,v2,v1)


Right, let's study this:

v0# is the top left corner
v1# is the top right corner
v2# is the bottom left corner

On paper, draw a line to the right, now draw a diagonal line down towards the left and then draw a line straight up to meet the start - this is the triangle and those corners apply when you use 'AddTriangle'.

v0,v1,v2 connects the triangle's vertices the way you just did on paper.

On paper, draw a diagonal line down towards the left and then draw a line straight up (to the same level), now draw a line to the right to meet the start.

v1,v2,v0 connects the triangle's vertices the way you just did on paper.

As for v2,v0,v1, I think you can guess the answer to that.

Basically, all three versions draw the same triangle but starting and finishing at a different corner - but all move CLOCKWISE through the triangle.

Right, let's take a look at the 3 that didn't work:

v2,v1,v0 is basically the first example in reverse - ANTICLOCKWISE

In fact, the remaining two (v1,v0,v2 and v0,v2,v1) are both going from a different corner (vertice) to a different corner (vertice) in an ANTICLOCKWISE route.

The triangle created with the above three examples is actually there - after the 'AddTriangle' command - add in on a new line 'FlipMesh mesh'. Make sure you are using one of the ANTICLOCKWISE 'AddTriangle' versions.

Your triangle is back and it is in the same position and rotation (it's identical to the original)

So, in general you will probably want to connect your vertices in a CLOCKWISE fashion.



INTRODUCTION(Posted 2004-10-15)
'Surface' stuff - by "puki"

I have only ever seen one tutorial related to the 'Surface' commands of Blitz3D:

http://www.blitzcoder.com/cgi-bin/articles/show_article2.pl?f=gamearray12142001.html

Credit to "Storm" for this. Read his tutorial first as it is a complete tutorial.

Baring in mind Blitz3D actually does come with a built-in vertices tutorial - on the start-up screen - click on '3D Tutorials' - scroll to the bottom of the page and select 'Vertexes'. I have both this and the printed manual and forgot they were there (although, I didn't know about the built-in one). I noticed this after I started. Still, I will continue my little project.

Personally, I think Blitz3D is lacking in this area - not in programming, but in tutorials and clarity. The 'Surface' commands in Blitz3D are the holy-grail to some of the eye-candy you see in commercial games (particle effects, realistic water, real-time cloth effects, terrain deformation, shadow effects, etc, etc). However, my intended tutorial is not going to go down those routes as other Blitzers have already gone down those roads and produced code archives. My aim is to cover the basics better than the Blitz3D manual so that you can hopefully understand their code better because you will have a background knowledge of all those ‘AddVertex’ and ‘AddTriangle’ commands that litter their code.

What I am intending to do is to plod along and eventually create a tutorial for the 'Surface' commands designed for a beginner/novice. I am doing this for people who have never used the 'Surface' commands, those who want to and those who have tried and given up. The idea is to hopefully avoid a situation whereby someone skips these commands because they look a bit complicated.

The surface commands are very, very powerful and I think they really should be promoted more by Blitz Research - I think the way to do this is with some kind of clear, easy to follow, examples/tutorials. BAD "puki", THERE IS A BUILT-IN DEMO - OPEN YOUR EYES YOU IDIOT!

THE FOLLOWING (which is currently above) IS *NOT* MY TUTORIAL - IT IS THE WORK-IN-PROGRESS OF MY TUTORIAL. When I decided to do a basic tutorial for beginners I realised this was going to take a long time - I have been using Blitz3D since 2001 and never bothered using the 'Surface' commands. What changed my mind was when I was recently looking at several particle engines and thought ‘I really ought to take the bull by the horns and finally use and understand the ‘Surface’ stuff'.

Rather then take a couple of months and then produce a tutorial for the 'Tutorials' section, I thought 'Why not do it as a work-log then people can see it as it is created?'. The advantage here is there might be people who are already itching to get their hands dirty with this stuff.

What I would say is the content of this work-log may contain errors - it is purely my draft of the intended tutorial that I am typing - it may change slightly - it will grow over time - there may be periods of time whereby nothing new is added. Also, the content in this work-log may not be typed in the eventual order – currently, I am just making it up as I go.

I have to stress though that it has to be accepted that the content may not be always correct or factual - I too am learning as I go. Prior to finalising the tutorial, it is my intention that it will be checked and corrected where necessary. So, this tutorial is not deemed complete until it eventually finds its way into the correct Tutorials section of the site.

The official Blitz3D 'Surface' commands documentation can be found here:
http://www.blitzbasic.com/b3ddocs/command_list_3d_cat.php?show=Surface



Tweaking team creation(Posted 2004-06-27)
Although the players are make-believe, randomally generated ones, the teams are based on real Premiership teams. I have started tweaking the game to generate players realistically in relation to the teams. All of the teams are graded - this affects the size and quality of their squads - currently set to generate between 20 and 40 players per team (baring in mind I am not faffing about with reserve and youth teams, although reserve teams will be sort of accounted for, you won't pick squads or play matches as such with them - it will just be a background thing)

I still need to finish the various screens before trying to advance further.

Still, got off to a good start, baring in mind I have applied very little time to it.



Interface working and database coming along(Posted 2004-06-27)
I decided to knock up a quick interface - works well. It is purely a highlight box that you can move around with the cursor/arrow keys. I assume this sort of system is used with console football managment games. Will worry about mouse support much further down the line.

The database is working well. When accessing a club screen to see the list of players (as per Championship Manager), initially I thought I'd have to create arrays for each club - not so. I just create an array to hold the global position of the player - simple as that. The array is re-used each time you click on a club, so there is no wastage - and the array is unique (don't have to have one per club, just one unique one).

To explain the above:

There are currently 1,000 players (for development) - numbered 1 - 1000 (obviously). So when you click on a club, say 'Man Utd' - a loop goes through all the players in the database and shunts the global index of a player, who's current team is equal to the club, into a 'squad array'. Once in that array, all the stats of that player never need to be searched.

It's a smart system - it is easy on resources as I don't need to create arrays for clubs, therefore wasting memory by duplicating it. To test it, I increased the database to 100,000 players (baring in mind I can create them-on-the fly).

Hope the above makes sense.



Progress(Posted 2004-06-24)
Setting up the players, stats and teams seems to be easy enough (but then it was going to be).

Not going to bother with the hyperlinking interface yet - too much else to do.

Going to concentrate on setting up the screens (player profile/club screens/league table/player search, etc., etc.). Actually, this will be probably be a fair amount of work in itself.

Also, going to find something on the internet that shows the top UK first names and surnames so that I can increase the occurances of certain names, rather than just simply randomly creating them. Probably by entering a certain first name or surname into the data more than once.

All-in-all, this first Worklog project of mine is going okay. Maybe it will become a serious project. I'm using my some of my adventure game programming skills within this project - mainly 'string' stuff, to achieve what I want simply and efficiently.

However, there is a long, lonely, road ahead before this is even remotely worth looking at. Euro 2004 isn't helping development.



The plan:(Posted 2004-06-23)
This is my first worklog and it isn't really a serious project - it's just something to do until I get run-over or something.

'Blitz Football Manager' is just a title off the top of my head so it isn't a problem if it clashes with anything else.

I've not done any serious programming for many years. I've never done a football managment type game - haven't got a clue - so I am just going to make it up as I go along - in fact, I've not done anything in PC Blitz - in fact, I am going to have to learn the language as I go along.

I think this type of game will be in part easy, yet also very challenging. I think the challenge will be in creating the AI for the computer controlled managers - I've a feeling that will not be easy, or at least will be difficult to vary it realistically.

Initially, to get the ball rolling a bit quicker, I am only going to create a Premiership league with no cup competitions. Not going to bother with reserve or youth teams.

I'm going to cut down on the number of individual player stats that Championship manager uses and work on the basis that I can calculate stats off each other for example an 'Experience' stat for a player will be a smart move for calculating many things in the game (on and off the pitch). I want to visually display stats in terms of (awful/poor/average/good/very good/excellent/world class), as I think this is more realistic than a numerical figure between 1 and 20 that Championship Manager uses. I think Championship Manager would look more realistic if they did this:

1-5 = awful
6-9 = poor
10-13 = average
14-15 = good
16-17 = very good
18-19 = excellent
20 = world class

Instead of displaying numerical stats, I will display the corresponding word - to me it seems more realistic than numeric or 'star' systems.

I'm not going to faff around with real players - so the first bit is easy:



Task 1 (in no particular logical order - I just thought of it first)

Store a load of first names and surnames then randomally call them to create my player database whilst assigning random stats (such as age, etc.) and assigning them into teams - all on the fly. Should be easy enough - but I'm watching the football so I'll do it later.



Task 2:

Design an interface (for clicking on players/viewing stats/histories, etc.)

Not actually sure how I am going to do this - I want it to work like Championship Manager's hyperlinked-type text. As I think about it, this might be my first challenge. Anyway, I can initially kludge it by zoning the screen display and arraying, on the fly, the contents of the zones as they appear - then I can know what has been clicked (i.e. in a transfer list screen whether it is a player's name, or a club's name and which particular item was clicked - in fact, this system would detect the item prior to a click - might be handy as I could highlight the item which Championship Manager doesn't do - this could be handy especially when you consider some of the problems with CM's finger pointer). This system is workable, but might end up being cumbersome - there is only one way I will know and that is to try it.

I have a feeling Task 2 is probably going to take me ages to get right - but there is more than one option to try. I'm starting to think I should have just done an adventure game. Anyway, I can always do it the 8-bit way (typing a value in) if it starts becoming a pain to do.