Code archives/3D Graphics - Maths/Wheel rolling example

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

Download source code

Wheel rolling example by Jeppe Nielsen
(Posted 23 years ago)
Shows how to roll a wheel, unlike a ball it cannot go in any direction.
;wheel rolling physics example by Jeppe Nielsen 2003
;email: nielsen_jeppe@hotmail.com

Const gravity#=-0.04;-0.02 ;gravity constant

Graphics3D 800,600,16,2

Const wheel_col=1
Const world_col=2
Collisions wheel_col,world_col,2,3


;create old amiga texture :-)
Global texture

texture=CreateTexture(16,16)

SetBuffer TextureBuffer(texture)

Color 255,255,255
Rect 0,0,16,16,1

Color 255,0,0
Rect 0,0,8,8,1
Rect 8,8,8,8,1

ScaleTexture texture,0.5,0.5

Global groundtexture=CreateTexture(32,32,1+8)

SetBuffer TextureBuffer(groundtexture)

Color 0,0,0
Rect 0,0,32,32,1

Color 0,0,255
Rect 0,0,32,32,0

ScaleTexture groundtexture,2,2

SetBuffer BackBuffer()
Color 255,255,255

plane=CreatePlane()
EntityTexture plane,groundtexture
EntityType plane,world_col
EntityAlpha plane,0.5



light=CreateLight(1)
RotateEntity light,30,20,0


obj=CreateCube()
EntityType obj,world_col
PositionEntity obj,0,-20,-175
ScaleEntity obj,10,140,40
RotateEntity obj,75,0,0
EntityTexture obj,texture


sphere=CreateSphere(32)
EntityType sphere,world_col
ScaleEntity sphere,40,40,40
EntityTexture sphere,texture


Dim VertArray(0)
sphere1=AdjustTriangles(sphere,0.5,False)
sphere2=AdjustTriangles(Sphere,0.5,True)
FlipMesh sphere2

PositionEntity sphere1,0,35,0
RotateEntity sphere1,180,0,0
ScaleEntity sphere1,40,40,40
EntityTexture sphere1,texture
EntityType sphere1,world_col
RotateEntity sphere2,180,0,0
PositionEntity sphere2,0,35,0
ScaleEntity sphere2,40,40,40
EntityTexture sphere2,texture
EntityType sphere2,world_col


camera=CreateCamera()
CameraClsColor camera,0,0,255
PositionEntity camera,0,600,-40

wheel.wheel=wheelnew(0,4,0,2)

zoom#=14

Repeat

zoom#=zoom#-MouseZSpeed()
wheelcamera(camera,wheel,0,zoom#,-zoom#,0,5,0)


wheelcontrol(wheel)
wheelupdate()

RenderWorld()

Color 255,255,255

Text 10,10,"Arrow keys to control wheel"
Text 10,20,"Space to lift wheel"
Text 10,30,"Scroll on mouse to zoom"


Flip


Until KeyDown(1)
End


Type wheel

Field e ;entity

Field cylinder

Field pivot

Field x#,y#,z# ; position in 3d-space

Field vx#,vy#,vz# ; velocity

Field ax#,ay#,az# ; acceleration

Field size#

Field vel#

Field vx2#,vy2#,vz2# ; temp velocity

Field collided

End Type


Function wheelnew.wheel(x#,y#,z#,size#=1)
	
	c.wheel=New wheel
	
	c\x#=x#
	c\y#=y#
	c\z#=z#
	
	c\size=size
	
	c\e=CreatePivot()
			
	c\cylinder=CreateCylinder(64)
	RotateMesh c\cylinder,0,0,90
	
	c\pivot=CreatePivot()
	
	EntityType c\e,wheel_col
	EntityRadius c\e,c\size
	
	PositionEntity c\e,c\x,c\y,c\z
	ScaleEntity c\cylinder,c\size,c\size,c\size
	
	EntityTexture c\cylinder,texture
	
	Return c
	
End Function

Function wheelupdate()
	
	For c.wheel=Each wheel
	
			
		c\vy#=c\vy#+gravity#
		
		c\vx#=c\vx#+c\ax#
		c\vy#=c\vy#+c\ay#
		c\vz#=c\vz#+c\az#
		
		c\x#=EntityX(c\e)
		c\y#=EntityY(c\e)
		c\z#=EntityZ(c\e)
		
		TranslateEntity c\e,c\vx,c\vy,c\vz	
	
	Next
	
	UpdateWorld()
		
	For c.wheel=Each wheel
	
		;correct velocity if collided
		c\vx2=(EntityX(c\e)-c\x)
		c\vy2=(EntityY(c\e)-c\y)
		c\vz2=(EntityZ(c\e)-c\z)
		
		c\x#=EntityX(c\e)
		c\y#=EntityY(c\e)
		c\z#=EntityZ(c\e)
		
		PositionEntity c\cylinder,c\x,c\y,c\z
		PositionEntity c\pivot,c\x,c\y,c\z
		
		TFormVector 1,0,0,c\e,0
		AlignToVector c\cylinder,TFormedX(),TFormedY(),TFormedZ(),1,0.6
		
		c\collided=0
				
		If EntityCollided(c\e,world_col)
		
			c\collided=1
				
			avnx#=0
			avny#=0
			avnz#=0
				
			count=CountCollisions(c\e)	
				
			For i = 1 To count
				; Get the normal of the surface which the entity collided with. 
				Nx# = CollisionNX(c\e, i) 
				Ny# = CollisionNY(c\e, i) 
				Nz# = CollisionNZ(c\e, i) 
				
				avnx#=avnx+Nx
				avny#=avny+Ny
				avnz#=avnz+Nz
				
				; Compute the dot product of the entity's motion vector and the normal of the surface collided with. 
				VdotN# = c\vx#*Nx# + c\vy#*Ny# + c\vz#*Nz# 
				
				; Calculate the normal force. 
				NFx# = -2.0 * Nx# * VdotN# 
				NFy# = -2.0 * Ny# * VdotN# 
				NFz# = -2.0 * Nz# * VdotN# 
				
				; Add the normal force to the direction vector. 
				c\vx# = c\vx# + NFx# 
				c\vy# = c\vy# + NFy# 
				c\vz# = c\vz# + NFz# 
								
			Next
				
			If count>0 
							
				;average collision normals
				avnx#=avnx/count
				avny#=avny/count
				avnz#=avnz/count

				;align controlpivot to averaged collision normals
				AlignToVector c\e,avnx,avny,avnz,2
				
				;calculate length of motion vector, or total velocity.
				l#=Sqr(c\vx*c\vx+c\vy*c\vy+c\vz*c\vz)

				;get normalized direction of motion, the vector will have a length of one.
				;the +0.00001 is there to aviod NaN (not a number) numbers. This happens
				;if the length of the vector is 0.
				TFormNormal c\vx,c\vy+0.00001,c\vz,0,0
				vx#=TFormedX()
				vy#=TFormedY()
				vz#=TFormedZ()
											
				;get direction of wheel
				TFormNormal 0,0,1,c\e,0
				
				;calculate a dot product, a number between -1 and 1 to determine angle
				;calculate angle like this: angle#=Acos(dot#)		
				dot#=TFormedX()*vx+TFormedY()*vy+TFormedZ()*vz
			
				;correct velocities, by multiplying the controlpivot´s direction with
				;the dot product, followed by the original velocity vector length:
				c\vx=TFormedX()*dot*l
				c\vy=TFormedY()*dot*l
				c\vz=TFormedZ()*dot*l
							
				RotateEntity c\pivot,EntityPitch(c\e),EntityYaw(c\e),EntityRoll(c\e)
																					
			EndIf
						
			c\vel#=Sqr(c\vx2*c\vx2+c\vy2*c\vy2+c\vz2*c\vz2)
						
			;slow down due To friction
			c\vx#=c\vx*0.98
			c\vy#=c\vy*0.98
			c\vz#=c\vz*0.98
			
		EndIf
		
		EntityParent c\cylinder,c\pivot
		
		TFormVector c\vx,c\vy,c\vz,0,c\e
		;moving forward
		If TFormedZ()>0
		
			TurnEntity c\pivot,c\vel#*(180/Pi)/c\size#,0,0
		
		Else
		;moving backwards
		
			TurnEntity c\pivot,-c\vel#*(180/Pi)/c\size#,0,0
			
		EndIf

		EntityParent c\cylinder,0

		;reset acceleration
		c\ax#=0
		c\ay#=0
		c\az#=0	
		
	Next
	
End Function


Function wheelcontrol(c.wheel)

		If c\collided=1
		
			If KeyDown(200)
				
				TFormVector 0,0,0.05,c\e,0
				
				c\ax#=TFormedX()
				c\ay#=TFormedY()
				c\az#=TFormedZ()
				
			EndIf
		
			If KeyDown(208)
				
				c\vx=c\vx*0.94
				c\vy=c\vy*0.94
				c\vz=c\vz*0.94
				
			EndIf
		
		EndIf
		
		If KeyDown(57)
			
			c\ay#=c\ay+0.05
														
		EndIf
		
		If KeyDown(203)
			
			TurnEntity c\e,0,2,0
			
		EndIf
		
		If KeyDown(205)
			
			TurnEntity c\e,0,-2,0
			
		EndIf
		
		
	
End Function

Function wheelcamera(camera,b.wheel,camx#,camy#,camz#,aimx#=0,aimy#=0,aimz#=0,smoothcam#=0.1,roll#=0)
	
	TFormPoint camx#,camy#,camz#,b\e,0
	
	dx#=(TFormedX()-EntityX(camera))*smoothcam#
	dy#=(TFormedY()-EntityY(camera))*smoothcam#
	dz#=(TFormedZ()-EntityZ(camera))*smoothcam#
	
	TranslateEntity camera,dx,dy,dz
	
	TFormPoint aimx#,aimy#,aimz#,b\e,0
	
	dx# = EntityX(camera)-TFormedX()
	dy# = EntityY(camera)-TFormedY()
	dz# = EntityZ(camera)-TFormedZ()
	dist#=Sqr#((dx#*dx#)+(dz#*dz#))
	pitch#=ATan2(dy#,dist#)
	yaw#=ATan2(dx#,-dz#)
	
	RotateEntity camera,pitch#,yaw#,roll#
	
End Function

;function by Graythe
Function AdjustTriangles%(EntityNo%,Triangles#,FreeSource%=True,FX%=False)
Dim VertArray(2^16)
Copied=CreateMesh(GetParent(EntityNo))
For SurfLoop=1 To CountSurfaces(EntityNo)
	
	NewSurface=CreateSurface(Copied)

	OldSurface=GetSurface(EntityNo,SurfLoop)
	
	NoVertices=CountVertices(OldSurface)-1
	TotTriangles=Int(CountTriangles(OldSurface)*Triangles)-1
		
	For TriLoop=False To TotTriangles
		For CornerLoop=False To 2
			tri=TriangleVertex(OldSurface,TriLoop,CornerLoop)
			VertArray(tri)=True
		Next
	Next
	
	For VertLoop = False To NoVertices
		If VertArray(VertLoop) Then
			NewVertex=AddVertex(NewSurface,VertexX(OldSurface,VertLoop),VertexY(OldSurface,VertLoop),VertexZ(OldSurface,VertLoop),VertexU(OldSurface,VertLoop),VertexV(OldSurface,VertLoop),VertexW(OldSurface,VertLoop))
		End If
	Next		
		
	For TriLoop=False To TotTriangles
		AddTriangle NewSurface, TriangleVertex(OldSurface,TriLoop,False),TriangleVertex(OldSurface,TriLoop,1),TriangleVertex(OldSurface,TriLoop,2)
	Next
		
Next
Dim VertArray(0)
UpdateNormals Copied
If FX Then EntityFX Copied,FX
If FreeSource Then FreeEntity EntityNo
Return Copied
End Function