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.