JV-ODE Physics Thread 4

Blitz3D Forums/Blitz3D Userlibs/JV-ODE Physics Thread 4

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

Include "JV-ODE.bb"

Graphics3D 800,600,0,2

Global WorldERP#=0.2			; ### World Error Correction
Global WorldFriction#=0			; ### World Friction

Global SpaceInfo=0

Global Pointer
Global PlaneGeom

Const MATERIAL_RUBBER=1
Const MATERIAL_ICE=2
Const MATERIAL_FLOOR=3
Const NUM_OBJECTS=3

Type ODE
	Field body
	Field geom
	Field mesh
	Field mass
	Field material
End Type

Dim objects.ODE(NUM_OBJECTS)

; ###################################################################################################

; ### Setup ODE

Global World=dWorldCreate()
Global Space=dHashSpaceCreate(0)
Global GroundSpace=dHashSpaceCreate(Space)
Global ObjSpace=dHashSpaceCreate(Space)
Global ContactGroup=dJointGroupCreate(0)

dWorldSetAutoDisableFlag(World,1)
dWorldSetGravity(World,0,-0.98,0)
dWorldSetERP(World,WorldERP)

dContactSetMode(dContactSlip1)
dContactSetMu(WorldFriction)
dContactSetBounce(0.0)

For n=1 To NUM_OBJECTS
	objects(n)=New ODE
Next

; ### Create set
Light=CreateLight() : RotateEntity Light,45,-40,0 : LightColor Light,155,155,155 : AmbientLight 128,128,128
Camera=CreateCamera() : PositionEntity Camera,-10,30,-30 : RotateEntity camera,30,-30,0; : CameraZoom camera,2

; ### Create plane as first ODE object
objects(1)\material=MATERIAL_FLOOR
objects(1)\geom=dCreatePlane(GroundSpace,0,1,0,0)
dGeomContactSetMu(objects(1)\geom,0.0)
objects(1)\mesh=CreatePlane()
PlaneTexture=CreateTexture(128,128,9)
ClsColor 140,0,20 : Cls : Color 120,40,40 : Rect 0,0,64,64,1 :Rect 64,64,64,64,1
CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(PlaneTexture)
ScaleTexture PlaneTexture,20,20
EntityTexture objects(1)\mesh,PlaneTexture,0,0
EntityAlpha objects(1)\mesh,0.9
CreateMirror

; ### Create sphere
SPHERE_SIZE#=2.0
SPHERE_MASS#=10
SPHERE_FRICTION#=100.0		; Perfect traction
gamma#=0.5

frict#=SPHERE_FRICTION/100
frict=frict^gamma
frict=frict*4
frict=4-frict
e#=Log10(SPHERE_MASS*10)
e=e-frict

x#=18
y#=27

objects(2)\material=MATERIAL_RUBBER
objects(2)\body=dBodyCreate(World)
	dBodySetRotation(objects(2)\body,0,0,0)
	dBodySetPosition(objects(2)\body,x,y,0)
	objects(2)\geom=dCreateSphere(Space,SPHERE_SIZE)
	dGeomSetBody(objects(2)\geom,objects(2)\body)
	dGeomContactSetMu(objects(2)\geom,10^e)
	objects(2)\mass=dMassCreate()
		dMassSetSphereTotal(objects(2)\mass,SPHERE_MASS,SPHERE_SIZE)
		dBodySetMass(objects(2)\body,objects(2)\mass)
	objects(2)\mesh=CreateSphere()
	ScaleMesh objects(2)\mesh,SPHERE_SIZE,SPHERE_SIZE,SPHERE_SIZE
	RotateMesh objects(2)\mesh,0,0,0
	PositionEntity objects(2)\mesh,x,y,0
SphereTexture=CreateTexture(128,128,9)
ClsColor 0,140,20 : Cls : Color 0,180,40
Rect 0,0,32,32,1 : Rect 64,0,32,32,1 : Rect 32,32,32,32,1 : Rect 96,32,32,32,1 
Rect 0,64,32,32,1 : Rect 64,64,32,32,1 : Rect 32,96,32,32,1 : Rect 96,96,32,32,1 
CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(SphereTexture)
EntityTexture objects(2)\mesh,SphereTexture,0,0
; ### Create inclined plane
x#=10
y#=20
xs#=20
ys#=1
zs#=6
r#=10

objects(3)\material=MATERIAL_ICE
objects(3)\geom=dCreateBox(Space,xs,ys,zs)
	dGeomSetPosition(objects(3)\geom,x,y,0)
	dGeomSetRotation(objects(3)\geom,0,0,r)
	dGeomContactSetMu(objects(3)\geom,0.0)				; Perfectly slippery
	objects(3)\mesh=CreateCube()
	ScaleEntity objects(3)\mesh,xs/2,ys/2,zs/2
	RotateEntity objects(3)\mesh,0,0,r
	PositionEntity objects(3)\mesh,x,y,0
	EntityColor objects(3)\mesh,30,55,128

Color 255,255,255

While Not KeyHit(1)
;	PointEntity Camera,objects(2)\mesh
	If KeyHit(210)	; Hit insert key
		dBodyEnable (objects(2)\body)
		dBodySetAngularVel(objects(2)\body,0,0,-4)
	EndIf
	
	; CODE FOR FRICTION RESPONSE
;	For n=1 To NUM_OBJECTS
;		If objects(n)\body
;			numCollisions=dGeom1CountCollisions(objects(n)\geom)
;			If numCollisions>0
;				For o=1 To numCollisions
;					collision_geom=dGeom1CollisionGeom(objects(n)\geom,o)
;					p = 0
;					Repeat
;						p=p+1
;						If p>NUM_OBJECTS
;							Exit
;						EndIf
;						If objects(p)\geom = collision_geom
;							Exit
;						EndIf
;					Forever
;					If p<=NUM_OBJECTS	; We've found a valid collision object
;						Select objects(p)\material
;							Case MATERIAL_ICE
;								; Use lowest value for friction
;								; dGeomSetContactMu(geom, index, val)
;								; geom = geometry parent to collision
;								; index = collision index
;								; val = value to set the contacts friction to
;								;dGeomSetContactMu(objects(n)\geom, o, dgeomcontactgetmu(objects(o)\geom))
;								dGeomContactSetMu(objects(n)\geom, 0.0)
;							Default
;								; Use default settings for friction
;								dGeomContactSetMu(objects(n)\geom, 10^e)
;						End Select
;					EndIf
;				Next ; collision
;			EndIf
;			numCollisions=dGeom2CountCollisions(objects(n)\geom)
;			If numCollisions>0
;				For o=1 To numCollisions
;					collision_geom=dGeom2CollisionGeom(objects(n)\geom,o)
;					p = 0
;					Repeat
;						p=p+1
;						If p>NUM_OBJECTS
;							Exit
;						EndIf
;						If objects(p)\geom = collision_geom
;							Exit
;						EndIf
;					Forever
;					If p<=NUM_OBJECTS	; We've found a valid collision object
;						Select objects(p)\material
;							Case MATERIAL_ICE
;								; Use lowest value for friction
;								; dGeomSetContactMu(geom, index, val)
;								; geom = geometry parent to collision
;								; index = collision index
;								; val = value to set the contacts friction to
;								;dGeomSetContactMu(objects(n)\geom, o, dgeomcontactgetmu(objects(o)\geom))
;								dGeomContactSetMu(objects(n)\geom, 0.0)
;							Default
;								; Use default settings for friction
;								dGeomContactSetMu(objects(n)\geom, 10^e)
;						End Select
;					EndIf
;				Next ; collision
;			EndIf
;		EndIf
;	Next ; object
	; END CODE FOR FRICTION RESPONSE

	For n=1 To NUM_OBJECTS
		If objects(n)\body
			RotateEntity objects(n)\mesh,dGeomGetPitch#(objects(n)\geom),dGeomGetYaw#(objects(n)\geom),dGeomGetRoll#(objects(n)\geom)
			PositionEntity objects(n)\mesh,dGeomGetPositionX#(objects(n)\geom),dGeomGetPositionY#(objects(n)\geom),dGeomGetPositionZ#(objects(n)\geom)			
		EndIf
	Next

	dSpaceCollide(Space,World,ContactGroup)
	dWorldQuickStep(World,0.1)
	dJointGroupEmpty(ContactGroup)

	RenderWorld
	
	y=15
	Text 10,y,objects(1)\geom : y=y+15
	Text 10,y,objects(2)\geom : y=y+15
	Text 10,y,objects(3)\geom : y=y+15
	Text 10,y,collision_geom : y=y+15
	Flip

Wend

dJointGroupDestroy(ContactGroup)
dSpaceDestroy(Space)
dWorldDestroy(World)
dCloseODE()

End

Here's an example with a commented out routine that could deal with friction on a per-object basis. Hit 'INSERT' to add spin to the ball.

The plank and floor have mu=0.0, and the sphere has 100% friction derived from my algorithm posted earlier. The idea is to be able to apply spin to the ball while it's on the plank and watch it slide down. The commented out VIRTUAL CODE shows code to select a collision and decide on the frictional value to use. I've invented a function name dGeomSetContactMu(geom, index, val) which would do this. Run this sim as it is and you see the moment you apply rotation to the ball it rolls up the slope, despite the plank having zero friction, which we don't want. Whereas it rolls on the floor when we apply rotation which we do want.

If you uncomment the FRICTION CODE you'll see I've included a dGeomContactSetMu() function depending on which object is hit. This creates the correct wanted response - slides over plank of friction 0 but grips on floor of friction 0. however this is setting the object's entire mu for all collisions. Two similar spheres of high friction should grip with each other even when slipping down the slide, so changing the whole object's mu is incorrect. That's where a function to set per contact properties would open up all sorts of fun things.