Phil Jones' pitch and roll example

Blitz3D Forums/Blitz3D Programming/Phil Jones' pitch and roll example

I'm using his Pitch and Roll example from the code archives and I was wondering, if instead of using a terrain if I could use a different entity?

I would like to use this technique on a plane that I have set up with waves and stuff. I'd like it to roll with the waves and etc and I really like his example.

So, I guess my question is, how can I reconfigure this small bit of code so it works with my plane instead of a terrain?

anglenew# = yaw -90  ; what must be added to yaw to calculate front of vehicle's global x,z co-ords
xnew# = x+Cos(anglenew)*carlength
znew# = z+Sin(anglenew)*carlength
frontheight# = TerrainY(terrain,xnew,y,znew); get the height at new x,y,z
PositionEntity pfront,xnew,frontheight,znew ; a visual marker only - not neccessary for calculations

anglenew# = yaw +90 ; what must be added to yaw to calculate back of vehicle's global x,z co-ords
xnew# = x+Cos(anglenew)*carlength
znew# = z+Sin(anglenew)*carlength
backheight = TerrainY(terrain,xnew,y,znew)
PositionEntity pback,xnew,backheight,znew

anglenew# = yaw  ; what must be added to yaw to calculate midleft of vehicle's global x,z co-ords
xnew# = x+Cos(anglenew)*carwidth
znew# = z+Sin(anglenew)*carwidth
Leftheight = TerrainY(terrain,xnew,y,znew)
PositionEntity pleft,xnew,leftheight,znew

anglenew# = yaw + 180 ; what must be added to yaw to calculate midright of vehicle's global x,z co-ords
xnew# = x+Cos(anglenew)*carwidth
znew# = z+Sin(anglenew)*carwidth
rightheight = TerrainY(terrain,xnew,y,znew)
PositionEntity pright,xnew,rightheight,znew

pitchx# = carlength*2 ; need complete length of car for x
pitchy# = (backheight - frontheight); the height dif between the front and rear of car
pitch = ATan2(pitchx,pitchy); atan2 will return the angle from 0,0 to x,y

rollx# = carwidth*2
rolly# = (rightheight - leftheight) ; the height dif between the left and right of car
roll# = ATan2(rollx,rolly); atan2 will return the angle from 0,0 to x,y

RotateEntity car, pitch-90,yaw,roll-90 ; rotate car with offsets to adjust Atan2's calculation

th=(frontheight+backheight+leftheight+rightheight)/4; get average of terrain heights for cars overall height
PositionEntity car,x,th,z ; adjust car height 
MoveEntity car,0,0,speed

PositionEntity pop,x,th,z ; this is just a central axis 'pole' to help see rotation angles 
RotateEntity pop,pitch-90,yaw,roll-90


Ok, first set the mesh to entitypickmode 2 and do something like this ...

anglenew# = yaw -90  						; what must be added to yaw to calculate front of vehicle's global x,z co-ords
xnew# = x+Cos(anglenew)*carlength
znew# = z+Sin(anglenew)*carlength
LinePick xnew, EntityY( car) + 10 , znew, 0,-10,0
PositionEntity pfront,xnew,PickedY(),znew ; a visual marker only - not neccessary for calculations


You'll have to play with the +-10 thing and it's just the first part so you get the idea. The same could be done with collisions and is probably faster.

Stevie

If your plane is a pickable polygon mesh then you can use a single linepick (much quicker than using lots of linepicks) from the centre of your entity, then obtain the picked normals (use PICKEDNX#(), PICKEDNY#() and PICKEDNZ#() ) then use 2 ALIGNTOVECTOR commands to correctly orient the object.

Like this -
ground = LinePick( EntityX#(v\bodymesh,True),EntityY#(v\bodymesh,True) + 1.0,EntityZ#(v\bodymesh,True) , 0,-2.0,0 , 0.0)
		If ground
			nx# = PickedNX#()
			ny# = PickedNY#()
			nz# = PickedNZ#()
			AlignToVector v\shadowmesh,nx#,ny#,nz#,1,1
			AlignToVector v\shadowmesh,nx#,ny#,nz#,3,1


Note that this will result in you entity pointing straight upwards along the polygon's normal so you will need to orient the entity's mesh correctly in your 3D package for it to look visually correct. If you can't do that, then make your primary object a pivot, use the above code to orient this pivot, and have your visual mesh as a child of the pivot that is correctly pre-rotated so that it faces forwards and not upwards (probably ROTATEENTITY child,90,0,0).

Thanks guys, Stevie, you said it could be done with collisions? How so? The linepick method really slows down my program and makes it very choppy. I'd really like to try this.

I'm pretty sure that the plane isn't a pickable polygon mesh, so I can't really use your suggestion Vorderman but thanks anyways. I am willing to show some of my code incase it is if your interested in seeing if it is.

Chad, look at the driver demo in the 3d samples folder - this does much the same thing but with collisions.

If this implementation isn't what you want show us the code without the need for external media and I'll see what I can do.

BTW, Vordermans method will work as you can simply set the plane to be pickable. Only issue with one linepick is that it's less accurate on more detailed uneven ground.

Stevie

Only issue with one linepick is that it's less accurate on more detailed uneven ground


That's right, it will be aligning your entity to a single normal rather than taking an average of the 4 wheels, so it will be less accurate if (for example) you put the entity over the top of a small lump or hanging over the edge of an incline.

If the entity is constantly moving or the groundmesh is reasonably smooth then it shouldn't be too much of an issue.

I use a smoothing system on mine - I use the above code to obtain the "target" normal on each program loop, and then smoothly move the actual orientation of the entity towards this target rather than using an instant snap.

I imagine for a boat on water a fairly gentle (ie. slower) smoothing would give a nice effect of mass as it cuts into the water before bobbing upright. For entities over ground you need a quicker smoothing otherwise they dig into the floor or appear to be made of jelly.

Woah, that's all way over my head.. Maybe I should just use a sin/cosine/tan equation to create what I'm looking for.

Then again, this linepick does sound interesting, so I tried what Stevie suggested, here's an external-less media code of what I'm ussing. It was in the water competition awhile back but a little different since I started toying with it. btw props to fredborg for create code.

Graphics3D 1024,768,32,1
SetBuffer BackBuffer()


;
; Prepare stuff
Cube_Init()

;
; Make a camera
Global camera=CreateCamera()
CameraClsMode camera,False,True
CameraRange camera,1,10000
CameraFogColor camera,96,140,183
CameraFogRange camera,2000,9000
CameraFogMode camera,1

;
; Make a stunning light
light=CreateLight()
RotateEntity light,25,0,0
AmbientLight 100,105,120

;
; Make a pivot which the camera points at
center=CreatePivot()

;
; Make a sky sphere
;skytex = LoadTexture("sky.png",1+8+16+32)
;sky = CreateSphere(16)
;FlipMesh sky
;ScaleEntity sky,5000,5000,5000
;EntityOrder sky,1000
;EntityFX sky,1+16
;EntityTexture sky,skytex

;
; A duck
duck=CreateCube("")
ScaleEntity duck,1000,1000,1000


;
; Some great variables
size# = 128*50.0
a#=180
storm# = 2.5
height# = 13.0
crystal# = 0.6
Animat = True
cubeupd = True
help = True

;
; And then we are ready
While KeyDown(1)=0
	
	sx# = MouseXSpeed()
	sy# = MouseYSpeed()
	
	a2# = (a2+.01) Mod 360
	
	;
	; Animate camera or control it with mouse + keys
If animat
a#=(a+.1) Mod 360
	PositionEntity camera, Sin(a)*(.5*size),500+(Sin(a)*400),Cos(a)*(.5*size)
	PointEntity camera, center
	Else
		TurnEntity camera,sy,-sx,0
		RotateEntity camera,EntityPitch(camera,True),EntityYaw(camera,True),0
		MoveEntity camera,(KeyDown(32)-KeyDown(30))*10,0,(KeyDown(17)-KeyDown(31))*10
	EndIf
	
	;
	; Move the duck
	
	
	;
	; Change fog if below water level
	If EntityY(camera,True)<0
		CameraFogColor camera,50,90,100
		CameraFogRange camera,500,3000
	Else
		CameraFogColor camera,96,140,183
		CameraFogRange camera,2000,9000
	EndIf
	
	;
	; Reposition sky
	;PositionEntity sky,EntityX(camera,1),EntityY(camera,1),EntityZ(camera,1),1

	;
	; Animate the waves
	Cube_Waves(camera,storm,height,crystal)
	
	;
	; Update reflection?
	;If cubeupd
;		Cube_Update(camera,sky)
	;EndIf

	RenderWorld()

	
	;
	; Fps counter	
	curTime = MilliSecs()
	If curTime > checkTime Then
		checkTime = curTime + 1000
		curFPS = fpscounter
		fpscounter = 0
		If currentFrame>75
			If curFPS<fps_low Then fps_low = curFPS
		EndIf
	Else
		fpscounter = fpscounter + 1
	End If
	
	Flip False
Wend

;
; We're done!
End

;
; Water 
;
; By Mikkel Fredborg
; Use as you please!

;
; A bunch of global variables
Global cubetex	
Global cubetex2
Global cubetex3
Global cubetex4
Global cubetex5
Global cubesize	
Global cubereflect
Global cuberefract
Global cubecamA[5]
Global cubewater
Global cubetile[9999]
Global cubewave#
Global cuberes
Global cubescale#
Global cubeoffset# 
Global cubebase
Global cubeinfinite
Global cubered#,cubegreen#,cubeblue#

Dim cubewavemap#(16,16,8)
Dim tempwavemap#(16,16,1)

Global slope_x#,slope_y#,slope_z#

Function Cube_Init(res=15,tres=256,soften=0,scale#=1500.0)

	cubescale = scale

	Dim cubewavemap#(res,res,8)

		Dim cubewavemap#(res,res,8)
	cubetex2 = CreateTexture(256,256,1+2)
	;cubetex2 = LoadTexture("waterfoam00.png",1+2)
	cubetex3 = CreateTexture(256,256,1+2)
	;cubetex3 = LoadTexture("waterfoam00.png",1+2)
	ScaleTexture cubetex2,0.5,0.5
	RotateTexture cubetex3,45
	ScaleTexture cubetex3,2,2
	
	
	cubetex4 = CreateTexture(256,256,1+2)
	;cubetex4 = LoadTexture("wateralpha00.png",1+2)
	cubetex5 = CreateTexture(256,256,1+2)
	;cubetex5 = LoadTexture("wateralpha00.png",1+2)
	RotateTexture cubetex4,45
	ScaleTexture cubetex4,2,2

	cubetex		= CreateTexture(tres,tres,1 + 128 + 256)
	cubesize	= TextureWidth(cubetex)
	
	cubereflect = CreatePivot()
	HideEntity cubereflect
	
	For i=0 To 5
		cubecamA[i] = CreateCamera(cubereflect)
		CameraClsMode cubecamA[i],False,True
		CameraRange cubecamA[i],1,15000
	Next

	RotateEntity cubecamA[0],0,90,0 ; right
	CameraViewport cubecamA[0],0,0,cubesize,cubesize
	RotateEntity cubecamA[1],0,0,0 ; forw
	CameraViewport cubecamA[1],cubesize,0,cubesize,cubesize
	RotateEntity cubecamA[2],0,-90,0 ; left
	CameraViewport cubecamA[2],cubesize*2,0,cubesize,cubesize
	RotateEntity cubecamA[3],0,180,0 ; back
	CameraViewport cubecamA[3],0,cubesize,cubesize,cubesize
	RotateEntity cubecamA[4],-90,0,0 ; up
	CameraViewport cubecamA[4],cubesize,cubesize,cubesize,cubesize
	RotateEntity cubecamA[5],90,0,0 ; down
	CameraViewport cubecamA[5],cubesize*2,cubesize,cubesize,cubesize

	cubewater = Cube_CreatePlane(res,True)	
	ScaleMesh cubewater,scale,1,scale

	br1 = CreateBrush()
	BrushTexture br1,cubetex4
	BrushTexture br1,cubetex5,0,1
	BrushTexture br1,cubetex,0,2
	BrushFX br1,2+32+16+1
	BrushShininess br1,1.0
	s1 = GetSurface(cubewater,2)
	PaintSurface s1,br1

	br2 = CreateBrush()
	BrushTexture br2,cubetex2
	BrushTexture br2,cubetex3,0,1
	BrushFX br2,1+2+32
	s2 = GetSurface(cubewater,1)
	PaintSurface s2,br2

	cubered		= 140 ;* 1.2
	cubegreen	= 180 ;* 1.2
	cubeblue	= 200 ;* 1.2

	br2 = CreateBrush()
	BrushFX br2,1+2+32+16
	BrushAlpha br2,0.75
	
	tcount = 5

	i = 0
	For x = -tcount To tcount
		For z = -tcount To tcount
			If x<>0 Or z<>0
				cubetile[i] = CopyEntity(cubewater)
				PositionEntity cubetile[i],x*scale,0,z*scale
				;d# = Abs(x)
				;If Abs(z)>d Then d = Abs(z)
				;If d>1
				;	ScaleEntity cubetile[i],1,1.0-(d/(tcount+0.01)),1
				;EndIf
				i = i + 1
			EndIf
		Next
	Next
	
	i = 0
	For x = -tcount To tcount
		For z = -tcount To tcount
			If x<>0 Or z<>0
				If cubetile[i]
					EntityParent cubetile[i],cubewater
				EndIf
				i = i + 1
			EndIf
		Next
	Next

	cubebase = CreatePivot()

	mmx# = 0.35

	BrushFX br2,1+2+32
	pr1 = Cube_CreatePlane(16,False)
	EntityParent pr1,cubebase
	PaintEntity pr1,br2
	;PositionEntity pr1,0,-0.5,0
	ScaleEntity pr1,scale*tcount*2,1,scale*tcount*2
	EntityOrder pr1,1
	surf = GetSurface(pr1,1)
	n_verts = CountVertices(surf)-1
	For v = 0 To n_verts
		vx# = VertexX(surf,v)*2.0
		vz# = VertexZ(surf,v)*2.0
		d# = Sqr(vx*vx + vz*vz)
		a# = 1.0-d
		VertexColor surf,v,cubered*mmx,cubegreen*mmx,cubeblue*mmx,a
	Next
	
	cuberes = res
	
	For x = 0 To res
		For z = 0 To res
			cubewavemap(x,z,0) = Rnd(-1.0,1.0)*360.0*(16.0/cuberes)
			cubewavemap(x,z,1) = Rnd(-1.0,1.0)
		Next
	Next

	For i = 1 To soften
		Cube_BlurWaveMap()
	Next
	
	For x = 0 To res
		For z = 0 To res
			xz# = ((x/Float(res)) - (z/Float(res)));/2.0
		
			cubewavemap(x,z,0) = (xz*360.0) + cubewavemap(x,z,0)
;			cubewavemap(x,z,1) = ACos(cubewavemap(x,z,1));+(z*(res/360.0))
			
			i = x
			j = z
			If i = res Then i = 0
			If j = res Then j = 0
			cubewavemap(x,z,0) = cubewavemap(i,j,0)
			cubewavemap(x,z,1) = cubewavemap(i,j,1)				
		Next
	Next
	
End Function

Function Cube_BlurWaveMap()
	
	Dim tempwavemap(cuberes,cuberes,1)
	
	For x = 0 To cuberes
		For z = 0 To cuberes
			
			For xx = -1 To 1
				For zz = -1 To 1
					x2 = xx+x
					z2 = zz+z
					If x2<0 Then x2 = cuberes
					If x2>cuberes Then x2 = 0
					If z2<0 Then z2 = cuberes
					If z2>cuberes Then z2 = 0
					tempwavemap(x,z,0) = tempwavemap(x,z,0) + (cubewavemap(x2,z2,0)/9.0)
					tempwavemap(x,z,1) = tempwavemap(x,z,1) + (cubewavemap(x2,z2,1)/9.0)
				Next
			Next
			
		Next
	Next

	For x = 0 To cuberes
		For z = 0 To cuberes
			cubewavemap(x,z,0) = tempwavemap(x,z,0)
			cubewavemap(x,z,1) = tempwavemap(x,z,1)
		Next
	Next
		
End Function

Function Cube_GetHeight#(x#,z#)

	x# = (x/cubescale)-0.5
	z# = (z/cubescale)-0.5

	basex = Floor(x)
	basez = Floor(z)

	deltax# = x-basex
	deltaz# = z-basez

	basex = basex Mod cuberes
	basey = basey Mod cuberes
	If basex<0 Then basex = basex + cuberes
	If basez<0 Then basez = basez + cuberes

	xy0#	= cubewavemap(basex,basez,  1) + (cubewavemap(basex+1,basez  ,1)-cubewavemap(basex,basez  ,1))*deltax
	xy1#	= cubewavemap(basex,basez+1,1) + (cubewavemap(basex+1,basez+1,1)-cubewavemap(basex,basez+1,1))*deltax
	cY#		= xy0 + (xy1-xy0)*deltaz
	
	Return cY
	
End Function

Function Cube_GetSlope#(x#,z#)

	x# = (x/cubescale)-0.5
	z# = (z/cubescale)-0.5

	basex = Floor(x)
	basez = Floor(z)

	deltax# = x-basex
	deltaz# = z-basez

	basex = basex Mod cuberes
	basey = basey Mod cuberes
	If basex<0 Then basex = basex + cuberes
	If basez<0 Then basez = basez + cuberes

	xy0#	 = cubewavemap(basex,basez,  2) + (cubewavemap(basex+1,basez  ,2)-cubewavemap(basex,basez  ,2))*deltax
	xy1#	 = cubewavemap(basex,basez+1,2) + (cubewavemap(basex+1,basez+1,2)-cubewavemap(basex,basez+1,2))*deltax
	slope_x# = xy0 + (xy1-xy0)*deltaz

	xy0#	 = cubewavemap(basex,basez,  3) + (cubewavemap(basex+1,basez  ,3)-cubewavemap(basex,basez  ,3))*deltax
	xy1#	 = cubewavemap(basex,basez+1,3) + (cubewavemap(basex+1,basez+1,3)-cubewavemap(basex,basez+1,3))*deltax
	slope_y# = xy0 + (xy1-xy0)*deltaz
	
	xy0#	 = cubewavemap(basex,basez,  4) + (cubewavemap(basex+1,basez  ,4)-cubewavemap(basex,basez  ,4))*deltax
	xy1#	 = cubewavemap(basex,basez+1,4) + (cubewavemap(basex+1,basez+1,4)-cubewavemap(basex,basez+1,4))*deltax
	slope_z# = xy0 + (xy1-xy0)*deltaz
		
	Return cY
	
End Function

Function Cube_Waves(cam,stormy#=0.5,waveheight#=30.0,crystal#=0.9)

	;EntityAlpha cubeinfinite,crystal

	d# = (MilliSecs()/10000.0)*stormy
	PositionTexture cubetex2,d*0.5,d
	PositionTexture cubetex3,-d*0.5,-d

	PositionTexture cubetex4, d*0.65, d*1.1
	PositionTexture cubetex5,-d*0.65,-d*1.1

    x#=EntityX(cam,True)
    z#=EntityZ(cam,True)

	PositionEntity cubebase,x,0,z

	px = x/cubescale
	pz = z/cubescale
	PositionEntity cubewater,px*cubescale,0,pz*cubescale

	surf = GetSurface(cubewater,2)
	surf2 = GetSurface(cubewater,1)
	
	vert = 0
	For x = 0 To cuberes
		
		For z = 0 To cuberes
			cubewavemap(x,z,0) = (cubewavemap(x,z,0) + stormy) ;Mod 360
			If cubewavemap(x,z,0)<0
				cubewavemap(x,z,0) = cubewavemap(x,z,0) + 360.0
			ElseIf cubewavemap(x,z,0)=>360.0
				cubewavemap(x,z,0) = cubewavemap(x,z,0) - 360.0
			EndIf
			cubewavemap(x,z,1) = (((Sin(cubewavemap(x,z,0))+1.0)*0.5)) * waveheight# 
			vert = vert+1
		Next
	Next
	
	delta# = cubescale/cuberes
	For x = 0 To cuberes-1
		For z = 0 To cuberes-1
			;Edge vector v1-v0
			Ax# = 0
			Ay# = cubewavemap(x,z+1,1)-cubewavemap(x,z,1)
			Az# = delta
	
			;Edge vector v2-v0
			Bx# = delta
			By# = cubewavemap(x+1,z,1)-cubewavemap(x,z,1)
			Bz# = 0
	
			;crossproduct = normal
			cubewavemap(x,z,2) = Ay# * Bz# - By# * Az#
		    cubewavemap(x,z,3) = Az# * Bx# - Bz# * Ax#
		    cubewavemap(x,z,4) = Ax# * By# - Bx# * Ay#
		Next
	Next
			
	exa# = 15.0
	TFormNormal 0,0,-1,cam,0
	nx# = TFormedX()
	ny# = TFormedY()
	nz# = TFormedZ()

	;alp# = 1.0-((EntityY(cam,True)-200.0)/1000.0)
	;If alp>1.0 Then alp = 1.0
	;If alp<0.0 Then alp = 0.0

	alp# = 1.0

	If waveheight<20.0
		alpmul# = 1.0/20.0
	Else
		alpmul# = 1.0/waveheight
	EndIf

	vert = 0
	For x = 0 To cuberes
		For z = 0 To cuberes
		
			If x<cuberes And z<cuberes	
				TriNormalX# = 0.0 
				TriNormalY# = 0.0
				TriNormalZ# = 0.0
				
				For xx = -1 To 1
					For zz = -1 To 1
						x2 = x+xx
						z2 = z+zz
						If x2<0 Then x2=cuberes-1
						If z2<0 Then z2=cuberes-1
						TriNormalX = TriNormalX + cubewavemap(x2,z2,2)
						TriNormalY = TriNormalY + cubewavemap(x2,z2,3)
						TriNormalZ = TriNormalZ + cubewavemap(x2,z2,4)
					Next
				Next

				d# = Sqr(TriNormalX*TriNormalX + TriNormalY*TriNormalY + TriNormalZ*TriNormalZ)
				TriNormalX = TriNormalX/d
				TriNormalY = TriNormalY/d
				TriNormalZ = TriNormalZ/d
				
				VertexCoords surf,vert,VertexX(surf,vert),cubewavemap(x,z,1),VertexZ(surf,vert)
				VertexNormal surf,vert,TriNormalX,TriNormalY,TriNormalZ
				dot# = (TriNormalY*ny + TriNormalX*exa*nx + TriNormalZ*exa*nz);*0.0001
				If dot<0 Then dot = 0
				If dot>1 Then dot = 1
				;dot = dot*dot
				;add# = (VertexY(surf,vert)-waveheight)*2.5
				;VertexColor surf,vert,cubered+add,cubegreen+add,cubeblue+add,(crystal-(dot*crystal))*alp
				VertexColor surf,vert,255,255,255,(crystal-(dot*crystal))*alp
				
				VertexCoords surf2,vert,VertexX(surf,vert),cubewavemap(x,z,1),VertexZ(surf,vert)
				
				alpha# = cubewavemap(x,z,1)*alpmul
				alpha2# = alpha * alpha * alpha
				VertexColor surf2,vert,255,255,255,(alp*alpha2*0.5)+0.05
			Else
				x2 = x
				z2 = z
				If x2 = cuberes Then x2 = 0
				If z2 = cuberes Then z2 = 0
				vert2 = x2*(cuberes+1) + z2
				VertexCoords surf,vert,VertexX(surf,vert),VertexY(surf,vert2),VertexZ(surf,vert)
				VertexColor surf,vert,VertexRed(surf,vert2),VertexGreen(surf,vert2),VertexBlue(surf,vert2),VertexAlpha(surf,vert2)
				VertexNormal surf,vert,VertexNX(surf,vert2),VertexNY(surf,vert2),VertexNZ(surf,vert2)
				
				VertexCoords surf2,vert,VertexX(surf2,vert),VertexY(surf,vert2),VertexZ(surf2,vert)
				VertexColor surf2,vert,VertexRed(surf2,vert2),VertexGreen(surf2,vert2),VertexBlue(surf2,vert2),VertexAlpha(surf2,vert2)
			EndIf
			vert = vert+1
		Next
	Next
	
	;UpdateNormals cubewater
	
	cubewave# = (cubewave#+stormy#) Mod 360
	cubeoffset# = (cubeoffset+stormy) Mod cuberes
	
End Function





Function Cube_Update(camera,sky)

	HideEntity cubewater
	HideEntity cubebase
    HideEntity camera

    x#=EntityX(camera,1)
    y#=EntityY(cubewater,1)-EntityY(camera,1)
    z#=EntityZ(camera,1)

	ox# = EntityX(sky,True)
	oy# = EntityY(sky,True)
	oz# = EntityZ(sky,True)
	
	ShowEntity cubereflect
	If y<0
		ScaleEntity cubereflect,1,1,1
		PositionEntity cubereflect,x,y,z
	Else
		y = -y
		ScaleEntity cubereflect,1,-1,1
		PositionEntity cubereflect,x,y,z
	EndIf

	PositionEntity sky,x,y,z,True
	
	RenderWorld()
	
	SetCubeFace cubetex,0
	CopyRect 0,0,cubesize,cubesize,0,0,BackBuffer(),TextureBuffer(cubetex)
	
	SetCubeFace cubetex,1
	CopyRect cubesize,0,cubesize,cubesize,0,0,BackBuffer(),TextureBuffer(cubetex)
	
	SetCubeFace cubetex,2
	CopyRect cubesize*2,0,cubesize,cubesize,0,0,BackBuffer(),TextureBuffer(cubetex)
	
	SetCubeFace cubetex,3
	CopyRect 0,cubesize,cubesize,cubesize,0,0,BackBuffer(),TextureBuffer(cubetex)
	
	SetCubeFace cubetex,4
	CopyRect cubesize,cubesize,cubesize,cubesize,0,0,BackBuffer(),TextureBuffer(cubetex)
	
	SetCubeFace cubetex,5
	CopyRect cubesize*2,cubesize,cubesize,cubesize,0,0,BackBuffer(),TextureBuffer(cubetex)
	
	ShowEntity cubebase
	ShowEntity cubewater
	HideEntity cubereflect
    ShowEntity camera

	PositionEntity sky,ox,oy,oz,True

End Function

;Creates a single sided face
;segmented
Function Cube_CreatePlane(segs=1,dual=True,double=False,parent=0,uvscale#=8.0)
	mesh=CreateMesh( parent )
	surf=CreateSurface( mesh )
	If dual
		surf2 = CreateSurface( mesh )
	EndIf
	stx#=-0.5
	sty#=stx
	stp#=Float(1)/Float(segs)
	y#=sty
	
	For a=0 To segs
		x#=stx
		v#=a/Float(segs)
		For b=0 To segs
			u#=b/Float(segs)
			i = AddVertex(surf,x,0,y,u*uvscale,v*uvscale) ; swap these for a different start orientation
			If dual
				i = AddVertex(surf2,x,0,y,u*uvscale,v*uvscale)
			EndIf
;			VertexTexCoords surf,i,u*uvscale,(1.0-v)*uvscale,1.0,1
			x=x+stp
		Next
		y=y+stp
	Next
	
	For a=0 To segs-1
		For b=0 To segs-1
			v0=a*(segs+1)+b:v1=v0+1
			v2=(a+1)*(segs+1)+b+1:v3=v2-1
			AddTriangle( surf,v0,v2,v1 )
			AddTriangle( surf,v0,v3,v2 )
			If dual
				AddTriangle( surf2,v0,v2,v1 )
				AddTriangle( surf2,v0,v3,v2 )
			EndIf
		Next
	Next
	
	UpdateNormals mesh
	If double=True Then EntityFX mesh,16
	Return mesh
End Function