JV-ODE Physics Thread 11

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

Current JV-ODE Version: 1.32

Now available for Blitz3D & BlitzMax (Win32)

The JV-ODE Physics Wrapper is an advanced user library supporting almost all of the Open Dynamics Engine functions wrapped inside a DLL (Dynamic Link Library).

The library can be used with any programming language that supports DLL's, including Blitz3D and BlitzMax (Win32). The Euler rotation system in JV-ODE has been adapted to match the left-handed Euler rotation used in Blitz3D, however functions for accessing Quaternion and Axis Angle rotation systems are also included. The full versions contain all of the necessary files to get you started, including over 40 demos showing the various features found in ODE and a complete Function Reference document.

The BlitzMax (Win32) version also features a built-in 'bare-bones' OpenGL 3D engine module and B3D mesh loader module for demo purposes.

To view more information and screenshots click here.

Options are now available to purchase the wrapper using either PayPal or Share*it.

The Blitz3D restricted demo version is now available for download here (207KB)

The BlitzMax (Win32) restricted demo version is now available for download here (292KB)

The JV-ODE Leadwerks Engine Demo Pack is now available for download here (60KB)

Have Fun :)

Previous JV-ODE Blitz3D Threads: 1 2 3 4 5 6 7 8 9 10

Useful Links: ODE.org Website - ODE Wiki - ODE User Guide (PDF) - ODE User Guide (HTML)

Thanks for the new update, my 3d Rigs over a network around fort block isn't abandoned... just waiting for my work to back off a bit so I can spend more time hobby coding.

Regards, BP.

You're welcome BP :)

Just fired up my rigs, computer 1's rig does move on computer 2 via network control, however am now using your 2 car demo to optimize my 2 player (or more...) TCP server client blah within the twin car demo. Cheers.

thanks for the updates best thing to hit my inbox in years.

Here's a little thing I tacked onto the ragdoll demo as an experiment. The shadows don't look quite right somehow though, perhaps they should fade with distance or something.

' ###################################################################################################
' #									   JV-ODE - RagDoll Demo										#
' #									Code by Jim Williams (VIP3R)									#
' ###################################################################################################

SuperStrict

Framework BRL.GLMax2D
Import BRL.Random
Import DevCode.JVODE
Import DevCode.JVODEOpenGL

AppTitle:String="JV-ODE - RagDoll Demo"

SetGraphicsDriver GLMax2DDriver()

Graphics 800,600,0,0

Global CamX:Float
Global CamZ:Float
Global numrags:Int = 10
Global RagDollMax:Int=numrags+1
Global ODEJointMax:Int=15
Global I:Int
Global WorldERP:Float=0.1	
Global RDBody:Int[RagDollMax,ODEJointMax]
Global RDJoint:Int[RagDollMax,ODEJointMax]

Type ODEGeom
	Field body:Int
	Field geom:Int
	Field mesh:Int
	Field rgb:Int[]
	Field scale:Float[]
End Type

Global ODEGeomList:TList=CreateList()

' ###################################################################################################

' ### Setup ODE

Global World:Int=dWorldCreate()
Global Space:Int=dHashSpaceCreate(0)
Global ContactGroup:Int=dJointGroupCreate(0)

dWorldSetAutoDisableFlag(World,1)
dWorldSetGravity(World,0,-2.8,0)
dWorldSetERP(World,WorldERP)
dContactSetMode(dContactSlip1+dContactBounce)
dContactSetBounce(0.75)
dContactSetMu(48)

' ### Setup Scene

InitOpenGL(GL_SMOOTH)	' ### GL_SMOOTH - GL_FLAT

InitLight(-40,80,100)	' ### xpos - ypos - zpos

' ### Create plane

dCreatePlane(Space,0,1,0,0)

' ###################################################################################################

' ### Create RagDolls

Local Count:Int

For Count=1 To numrags
	CreateRagDoll(Count)
Next

' ###################################################################################################

Local PTime:Int
Local PhysicsTime:Float

While Not AppTerminate() And Not KeyDown(KEY_ESCAPE)

	UpdateControls()

	ClearScene()

	UpdateCamera(-30+CamX,9,-25+CamZ,30,1,0,0)	' ### xpos - ypos - zpos - angle - rx - ry - rz

	DrawPlanarShadow()'UpdateGeoms()

	PTime=MilliSecs()

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

	PhysicsTime=MilliSecs()-PTime

	EnableGLText(255,255,255)		' ### red - green - blue
	GLDrawText "JV-ODE Version "+FixFloat(dGetVersion()),0,0
	GLDrawText "Physics Time:"+FixFloat(PhysicsTime),0,15
	GLDrawText "F1 - Drop RagDolls",300,0
	GLDrawText "Space - Throw RagDolls",300,15
	GLDrawText "Arrow Keys - Move Camera",300,30
	GLDrawText "F2 - Attach RagDolls",580,0
	GLDrawText "L Mouse Button - Push Body",580,15
	GLDrawText "R Mouse Button - Pull Body",580,30

	Flip

Wend

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

End

' ###################################################################################################

Function CreateRagDoll(rd:Int)

Local ode:ODEGeom
Local xp:Float=8+(rd*4)
Local yp:Float=6
Local zp:Float=4

' ### RagDoll Dimensions

Local HeadRad:Float=0.4
Local BodyUX:Float=1.0
Local BodyUY:Float=1.5
Local BodyUZ:Float=0.4
Local BodyLX:Float=1.4
Local BodyLY:Float=0.75
Local BodyLZ:Float=0.5
Local ArmURad:Float=0.08
Local ArmULen:Float=1.1
Local ArmLRad:Float=0.08
Local ArmLLen:Float=1.1
Local LegURad:Float=0.125
Local LegULen:Float=1.3
Local LegLRad:Float=0.125
Local LegLLen:Float=1.3
Local FeetX:Float=0.5
Local FeetY:Float=0.25
Local FeetZ:Float=1.0
Local HandX:Float=0.1
Local HandY:Float=0.4
Local HandZ:Float=0.28

' ### Create Head

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,0]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp,yp,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateSphere(Space,HeadRad)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dSphereClass
ode.rgb=[255,255,255]
ode.scale=[HeadRad]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Body (Upper)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,1]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp,yp-1.25,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateBox(Space,BodyUX,BodyUY,BodyUZ)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dBoxClass
ode.rgb=[0,200,200]
ode.scale=[BodyUX,BodyUY,BodyUZ]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Body (Lower)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,2]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp,yp-2.5,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateBox(Space,BodyLX,BodyLY,BodyLZ)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dBoxClass
ode.rgb=[0,100,100]
ode.scale=[BodyLX,BodyLY,BodyLZ]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Left Arm (Upper)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,3]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp+0.9,yp-1.25,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateCylinder(Space,ArmURad,ArmULen)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dCylinderClass
ode.rgb=[255,0,0]
ode.scale=[ArmURad,ArmURad,ArmULen]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Left Arm (Lower)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,4]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp+0.9,yp-2.35,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateCylinder(Space,ArmLRad,ArmLLen)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dCylinderClass
ode.rgb=[125,0,0]
ode.scale=[ArmLRad,ArmLRad,ArmLLen]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Left Hand

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,5]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp+0.9,yp-3.05,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateBox(Space,HandX,HandY,HandZ)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dBoxClass
ode.rgb=[255,255,255]
ode.scale=[HandX,HandY,HandZ]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Right Arm (Upper)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,6]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp-0.9,yp-1.25,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateCylinder(Space,ArmURad,ArmULen)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dCylinderClass
ode.rgb=[0,255,0]
ode.scale=[ArmURad,ArmURad,ArmULen]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Right Arm (Lower)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,7]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp-0.9,yp-2.35,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateCylinder(Space,ArmLRad,ArmLLen)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dCylinderClass
ode.rgb=[0,125,0]
ode.scale=[ArmLRad,ArmLRad,ArmLLen]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Right Hand

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,8]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp-0.9,yp-3.05,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateBox(Space,HandX,HandY,HandZ)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dBoxClass
ode.rgb=[255,255,255]
ode.scale=[HandX,HandY,HandZ]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Left Leg (Upper)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,9]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp+0.5,yp-3.6,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateCylinder(Space,LegURad,LegULen)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dCylinderClass
ode.rgb=[255,0,0]
ode.scale=[LegURad,LegURad,LegULen]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Left Leg (Lower)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,10]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp+0.5,yp-4.9,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateCylinder(Space,LegLRad,LegLLen)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dCylinderClass
ode.rgb=[125,0,0]
ode.scale=[LegLRad,LegLRad,LegLLen]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Left Foot

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,11]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp+0.5,yp-5.7,zp-0.25)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateBox(Space,FeetX,FeetY,FeetZ)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dBoxClass
ode.rgb=[255,255,255]
ode.scale=[FeetX,FeetY,FeetZ]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Right Leg (Upper)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,12]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp-0.5,yp-3.6,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateCylinder(Space,LegURad,LegULen)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dCylinderClass
ode.rgb=[0,255,0]
ode.scale=[LegURad,LegURad,LegULen]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Right Leg (Lower)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,13]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp-0.5,yp-4.9,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateCylinder(Space,LegLRad,LegLLen)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dCylinderClass
ode.rgb=[0,125,0]
ode.scale=[LegLRad,LegLRad,LegLLen]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Create Right Foot

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
RDBody[rd,14]=ode.body
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp-0.5,yp-5.7,zp-0.25)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateBox(Space,FeetX,FeetY,FeetZ)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=dBoxClass
ode.rgb=[255,255,255]
ode.scale=[FeetX,FeetY,FeetZ]
ListAddLast(ODEGeomList,ode:ODEGeom)

' ### Static Joint To Head

RDJoint[rd,0]=dJointCreateBall(World,0)
dJointAttach(RDJoint[rd,0],0,RDBody[rd,0])
dJointSetBallAnchor(RDJoint[rd,0],xp,yp,zp)

' ### Head To Body (Upper)

RDJoint[rd,1]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,1],RDBody[rd,0],RDBody[rd,1])
dJointSetHingeAxis(RDJoint[rd,1],1,0,1)
dJointSetHingeAnchor(RDJoint[rd,1],xp,yp-0.44,zp)
dJointSetHingeParam(RDJoint[rd,1],dParamLoStop,-0.7)
dJointSetHingeParam(RDJoint[rd,1],dParamHiStop,0.7)

' ### Body (Upper) To Body (Lower)

RDJoint[rd,2]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,2],RDBody[rd,1],RDBody[rd,2])
dJointSetHingeAxis(RDJoint[rd,2],1,0,0)
dJointSetHingeAnchor(RDJoint[rd,2],xp,yp-2.05,zp)
dJointSetHingeParam(RDJoint[rd,2],dParamLoStop,-0.25)
dJointSetHingeParam(RDJoint[rd,2],dParamHiStop,0.25)

' ### Left Arm (Upper) To Body (Upper)

RDJoint[rd,3]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,3],RDBody[rd,3],RDBody[rd,1])
dJointSetHingeAxis(RDJoint[rd,3],1,-1,1)
dJointSetHingeAnchor(RDJoint[rd,3],xp+0.9,yp-0.7,zp)
dJointSetHingeParam(RDJoint[rd,3],dParamLoStop,-1.5)
dJointSetHingeParam(RDJoint[rd,3],dParamHiStop,1.5)

' ### Left Arm (Lower) To Left Arm (Upper)

RDJoint[rd,4]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,4],RDBody[rd,4],RDBody[rd,3])
dJointSetHingeAxis(RDJoint[rd,4],1,0,0)
dJointSetHingeAnchor(RDJoint[rd,4],xp+0.9,yp-1.8,zp)
dJointSetHingeParam(RDJoint[rd,4],dParamLoStop,0.0)
dJointSetHingeParam(RDJoint[rd,4],dParamHiStop,2.0)

' ### Left Hand To Left Arm (Lower)

RDJoint[rd,5]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,5],RDBody[rd,5],RDBody[rd,4])
dJointSetHingeAxis(RDJoint[rd,5],0,0,1)
dJointSetHingeAnchor(RDJoint[rd,5],xp+0.9,yp-2.9,zp)
dJointSetHingeParam(RDJoint[rd,5],dParamLoStop,-0.3)
dJointSetHingeParam(RDJoint[rd,5],dParamHiStop,0.3)

' ### Right Arm (Upper) To Body (Upper)

RDJoint[rd,6]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,6],RDBody[rd,6],RDBody[rd,1])
dJointSetHingeAxis(RDJoint[rd,6],1,1,1)
dJointSetHingeAnchor(RDJoint[rd,6],xp-0.9,yp-0.7,zp)
dJointSetHingeParam(RDJoint[rd,6],dParamLoStop,-1.5)
dJointSetHingeParam(RDJoint[rd,6],dParamHiStop,1.5)

' ### Right Arm (Lower) To Right Arm (Upper)

RDJoint[rd,7]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,7],RDBody[rd,7],RDBody[rd,6])
dJointSetHingeAxis(RDJoint[rd,7],1,0,0)
dJointSetHingeAnchor(RDJoint[rd,7],xp-0.9,yp-1.8,zp)
dJointSetHingeParam(RDJoint[rd,7],dParamLoStop,0.0)
dJointSetHingeParam(RDJoint[rd,7],dParamHiStop,2.0)

' ### Right Hand To Right Arm (Lower)

RDJoint[rd,8]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,8],RDBody[rd,8],RDBody[rd,7])
dJointSetHingeAxis(RDJoint[rd,8],0,0,1)
dJointSetHingeAnchor(RDJoint[rd,8],xp-0.9,yp-2.9,zp)
dJointSetHingeParam(RDJoint[rd,8],dParamLoStop,-0.3)
dJointSetHingeParam(RDJoint[rd,8],dParamHiStop,0.3)

' ### Left Leg (Upper) To Body (Lower)

RDJoint[rd,9]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,9],RDBody[rd,9],RDBody[rd,2])
dJointSetHingeAxis(RDJoint[rd,9],1,0,-1)
dJointSetHingeAnchor(RDJoint[rd,9],xp+0.5,yp-2.9,zp)
dJointSetHingeParam(RDJoint[rd,9],dParamLoStop,-1.0)
dJointSetHingeParam(RDJoint[rd,9],dParamHiStop,1.0)

' ### Left Leg (Lower) To Left Leg (Upper)

RDJoint[rd,10]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,10],RDBody[rd,10],RDBody[rd,9])
dJointSetHingeAxis(RDJoint[rd,10],1,0,0)
dJointSetHingeAnchor(RDJoint[rd,10],xp+0.5,yp-4.25,zp)
dJointSetHingeParam(RDJoint[rd,10],dParamLoStop,-2.0)
dJointSetHingeParam(RDJoint[rd,10],dParamHiStop,0.0)

' ### Left Foot To Left Leg (Lower)

RDJoint[rd,11]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,11],RDBody[rd,11],RDBody[rd,10])
dJointSetHingeAxis(RDJoint[rd,11],1,0,0)
dJointSetHingeAnchor(RDJoint[rd,11],xp+0.5,yp-5.5,zp)
dJointSetHingeParam(RDJoint[rd,11],dParamLoStop,-0.25)
dJointSetHingeParam(RDJoint[rd,11],dParamHiStop,0.25)

' ### Right Leg (Upper) To Body (Lower)

RDJoint[rd,12]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,12],RDBody[rd,12],RDBody[rd,2])
dJointSetHingeAxis(RDJoint[rd,12],1,0,1)
dJointSetHingeAnchor(RDJoint[rd,12],xp-0.5,yp-2.9,zp)
dJointSetHingeParam(RDJoint[rd,12],dParamLoStop,-1.0)
dJointSetHingeParam(RDJoint[rd,12],dParamHiStop,1.0)

' ### Right Leg (Lower) To Right Leg (Upper)

RDJoint[rd,13]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,13],RDBody[rd,13],RDBody[rd,12])
dJointSetHingeAxis(RDJoint[rd,13],1,0,0)
dJointSetHingeAnchor(RDJoint[rd,13],xp-0.5,yp-4.25,zp)
dJointSetHingeParam(RDJoint[rd,13],dParamLoStop,-2.0)
dJointSetHingeParam(RDJoint[rd,13],dParamHiStop,0.0)

' ### Right Foot To Right Leg (Lower)

RDJoint[rd,14]=dJointCreateHinge(World,0)
dJointAttach(RDJoint[rd,14],RDBody[rd,14],RDBody[rd,13])
dJointSetHingeAxis(RDJoint[rd,14],1,0,0)
dJointSetHingeAnchor(RDJoint[rd,14],xp-0.5,yp-5.5,zp)
dJointSetHingeParam(RDJoint[rd,14],dParamLoStop,-0.25)
dJointSetHingeParam(RDJoint[rd,14],dParamHiStop,0.25)

End Function

' ###################################################################################################

Function UpdateControls()

If KeyDown(KEY_F1)=1 Then 
For i = 1 To numrags
dJointAttach(RDJoint[i,0],0,0)
Next
EndIf
If KeyDown(KEY_F2)=1 Then 
For i = 1 To numrags
dJointAttach(RDJoint[i,0],0,RDBody[i,0])
Next
EndIf

If KeyDown(KEY_SPACE)=1
	For i = 1 To numrags
	dBodyAddForce RDBody[i,0],0,150,0
	Next
	End If

If KeyDown(KEY_UP)=1 Then CamZ:+0.3
If KeyDown(KEY_DOWN)=1 Then CamZ:-0.3
If KeyDown(KEY_LEFT)=1 Then CamX:+0.3
If KeyDown(KEY_RIGHT)=1 Then CamX:-0.3

If MouseDown(MOUSE_LEFT)=1
	For i = 1 To numrags
	dBodyAddForce RDBody[i,1],0,0,10
	Next
	End If

If MouseDown(MOUSE_RIGHT)=1
	For i = 1 To numrags
	dBodyAddForce RDBody[i,1],0,0,-10
	Next
	End If

End Function

' ###################################################################################################

Function UpdateGeoms()

Local ode:ODEGeom



' ### Update Geoms
For ode:ODEGeom=EachIn ODEGeomList
	glPushMatrix()

	glTranslatef(dGeomGetPositionX(ode.geom),dGeomGetPositionY(ode.geom),dGeomGetPositionZ(ode.geom))
	dGeomGetAxisAngle(ode.geom)
	glRotatef(dVectorW(),dVectorX(),dVectorY(),dVectorZ())

	SetDrawColour(ode.rgb[0],ode.rgb[1],ode.rgb[2])

	' ### DrawSphere:		radius - slices - stacks
	' ### DrawCube:			xscale - yscale - zscale
	' ### DrawCylinder:		radiusb - radiust - length - slices - loops
	' ### DrawCCylinder:	radiusb - radiust - length - slices - loops
	If ode.mesh=dSphereClass Then DrawSphere(ode.scale[0],14,14)
	If ode.mesh=dBoxClass Then DrawCube(ode.scale[0],ode.scale[1],ode.scale[2])
	If ode.mesh=dCylinderClass Then DrawCylinder(ode.scale[0],ode.scale[1],ode.scale[2],8,8)
	If ode.mesh=dCapsuleClass Then DrawCapsule(ode.scale[0],ode.scale[1],ode.scale[2],8,8)

	glPopMatrix()
Next

End Function

' ###################################################################################################
Function DrawPlanarShadow()
' ### Update Plane
SetDrawColour(230,230,240)	' ### red - green - blue
DrawPlane(-(CamX-(CamX Mod -20)),0,-(CamZ-(CamZ Mod -20)))

Local plane:Float[]=[0.0,1.0,0.0,0.0]
Local shadowmatrix:Float[16]
Local dot:Float
Local lightpos:Float[]=[-40.0,180.0,-100.0,0.0]


'now set shadow matrix

dot = plane[0]*lightpos[0]+plane[1]*lightpos[1]+plane[2]*lightpos[2]+plane[3]*lightpos[3]

shadowmatrix[0] 	= dot - lightpos[0]*plane[0]
shadowmatrix[4] 	= 0.0 - lightpos[0]*plane[1]
shadowmatrix[8] 	= 0.0 - lightpos[0]*plane[2]
shadowmatrix[12] 	= 0.0 - lightpos[0]*plane[3]

shadowmatrix[1] 	= 0.0 - lightpos[1]*plane[0]
shadowmatrix[5] 	= dot - lightpos[1]*plane[1]
shadowmatrix[9] 	= 0.0 - lightpos[1]*plane[2]
shadowmatrix[13] 	= 0.0 - lightpos[1]*plane[3]

shadowmatrix[2] 	= 0.0 - lightpos[2]*plane[0]
shadowmatrix[6] 	= 0.0 - lightpos[2]*plane[1]
shadowmatrix[10] 	= dot - lightpos[2]*plane[2]
shadowmatrix[14] 	= 0.0 - lightpos[2]*plane[3]

shadowmatrix[3] 	= 0.0 - lightpos[3]*plane[0]
shadowmatrix[7] 	= 0.0 - lightpos[3]*plane[1]
shadowmatrix[11] 	= 0.0 - lightpos[3]*plane[2]
shadowmatrix[15] 	= dot - lightpos[3]*plane[3]


glPushMatrix()
glDisable(GL_TEXTURE_2D)
glDisable(GL_LIGHTING)
glDisable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glColor4f(0.0,0.0,0.0,0.5)
glMultMatrixf(shadowmatrix)
UpdateGeoms()'drawobject as shadow
glEnable(GL_DEPTH_TEST)
glDisable(GL_BLEND)
glEnable(GL_LIGHTING)
glPopMatrix()
UpdateGeoms()'drawobject as object

End Function


You're welcome Pete, thanks :)

@KronosUK: Excellent stuff! It's great to see shadows working with the bare bones engine, it's fast too. I might experiment a bit more with that when I update the JVODEOpenGL module. Your ragdolls look like they could do with a bit more food ;)

moving forwards with clients chatting to a server for control info to be sync'd between clients.... slowly:-



The reason the version is only 1.24 is that I didn't have enough time to get v1.27 onto my usb stick for dev whilst on hols...

During development I'd 200 cars all moving in time, didn't half cause some carnage when I started varying the force dependant upon client number (;-) cheers BP.

200 networked cars, that's impressive!

Keep it up :)

Regarding the code below can someone clarify whether the tribank and vertbank continue to be used by ode after the trimesh is created?. In other words you couldn't use this function to create two trimeshs from two or more different b3d's as they would share the same tribank/vertbank.

Function CreateTriMesh:Int(trispace:Int,xscale:Float=1.0,yscale:Float=1.0,zscale:Float=1.0)

Global TriBank:TBank=CreateBank(NTris*3*4)
Global VertBank:TBank=CreateBank(NVerts*4*4)

Local Offset:Int=0
Local TriOffset:Int=0

Local VertData:Vrts
Local TriData:Tris

For VertData:Vrts=EachIn B3DVrtsList
	PokeFloat(VertBank,Offset,xscale*VertData.X)
	Offset:+4
	PokeFloat(VertBank,Offset,yscale*VertData.Y)
	Offset:+4
	PokeFloat(VertBank,Offset,zscale*VertData.Z)
	Offset:+8
Next

For TriData:Tris=EachIn B3DTrisList
	PokeInt(TriBank,TriOffset,TriData.V0)
	TriOffset:+4
	PokeInt(TriBank,TriOffset,TriData.V1)
	TriOffset:+4
	PokeInt(TriBank,TriOffset,TriData.V2)
	TriOffset:+4
Next

Local TriMeshData:Int=dGeomTriMeshDataCreate()

dGeomTriMeshDataBuildSimple(TriMeshData,BankBuf(VertBank),NVerts,BankBuf(TriBank),NTris*3)

Return dCreateTriMesh(trispace,TriMeshData)

End Function


Once the TriMesh has been created using the banks, they're no longer accessed by ODE. I think at one time ODE needed them to be kept reserved (hence the global scope) but that isn't the case anymore. It still works ok if the banks are local scope only.

I get an unhandled memory exception on the line

dSpaceCollide(Space,World,ContactGroup)

in the main loop if I make tribank/vertbank Local so i guess Ode still needs them reserved.

Hmm, it works ok here with local scope. The error you mentioned is what used to happen when global scope was required.

Are you using V1.27 of JV-ODE (including the modules)?

Also, which version of BlitzMax are you using?

Ive copied over the v1.27 dll but still no joy. i think I need to recheck my code as there is something funny happening with my "spaces".

do you mean code spaces, like GGrrr.. underbar spaces in variable names (suffered about an hour from a trailing underbar in a var name within a function associated with the cars steerage - my fault!). If you mean 3d spaces then I can't empathise.

Safe to say, I'm now an initial capital fan as opposed to an underbar separation fan. As far as my TCP ing is going, I'm not 100 percent that everyone will be able to be represented on other peoples computers effectively without some dead reckoning wizardry. Never say die....

Does it have cloth simulation support too?

Yes, but not natively. You need to create your own cloth object using a matrix of spheres attached to each other with ball joints. Any physics engine with ball joints should be capable of this. There's a simple demo in JV-ODE Thread 10, search for 'Cloth Demo'.

Does JV-ODE support soft-body simulation?
I saw it in Physx and bullet.

No, ODE simulates rigid body physics.

However, certain types of soft body physics are still possible with ODE, for example the cloth physics as mentioned above.

Hi Jim!

Can I change the "WorldFriction" in "real time" ?

I want to make this to make variations during the game...

I have changing the WorldFriction# value and using this command dContactSetMu(WorldFriction), but, Not happen...

Can you Help me with this?

Hi EmerGki,

Not world friction, however you can use the geom functions to do this in real time instead... dGeomContactSetMu(geom,mu)

Here's a car demo with variable wheel geom friction...
; ###################################################################################################
; #										  JV-ODE Car Demo											#
; #									Code by Jim Williams (VIP3R)									#
; #								Devious Codeworks - Copyright © 2008								#
; ###################################################################################################

AppTitle "JV-ODE Car Demo"

Include "JV-ODE.bb"

Graphics3D 800,600,0,2

Global CMass#=200			; ### Car Mass
Global WMass#=14			; ### Wheel Mass

Global WorldERP#=1			; ### World Error Correction
Global WorldFriction#=70	; ### World Friction
Global GeomFriction#=70		; ### Geom Friction

Global Torque#=24			; ### Joint Torque
Global SuspensionHS#=0.01	; ### Suspension Hardness/Softness (Higher=Softer - Lower=Harder)

Global Force#=0
Global Steer#=0

Global Car
Global CGeom
Global CMesh

Global CarStartY=20

Dim Wheel(4)
Dim WGeom(4)
Dim Joint(4)

Type ODEGeom
	Field body
	Field geom
	Field mesh
End Type

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

; ### Setup ODE

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

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

dContactSetMode(dContactSlip1)
dContactSetMu(WorldFriction)

; ### Create car body

ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
Car=ode\body
dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,0,CarStartY,0)
mass=dMassCreate()
dMassSetBoxTotal(mass,CMass,3,1,4)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateBox(Space,3,1,4)
CGeom=ode\geom
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
CMesh=ode\mesh
ScaleMesh ode\mesh,1.5,0.5,2
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,40,80,255
EntityAlpha ode\mesh,1

; ### Create wheels

For count=1 To 4
	ode.ODEGeom=New ODEGeom
	ode\body=dBodyCreate(World)
	Wheel(count)=ode\body
	dBodySetRotation(ode\body,0,0,0)
	dBodySetPosition(ode\body,0,0,0)
	mass=dMassCreate()
	dMassSetSphereTotal(mass,WMass,0.7)
	dBodySetMass(ode\body,mass)
	dMassDestroy(mass)
	ode\geom=dCreateSphere(Space,0.7)
	WGeom(count)=ode\geom
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateCylinder(8)
	ScaleMesh ode\mesh,0.7,0.25,0.7
	RotateMesh ode\mesh,0,0,90
	PositionMesh ode\mesh,0,0,0
	EntityColor ode\mesh,255,255,255
Next

dBodySetPosition(Wheel(1),-2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(2),+2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(3),-2,CarStartY-0.5,-2)
dBodySetPosition(Wheel(4),+2,CarStartY-0.5,-2)

; ### Create some objects

SeedRnd MilliSecs()

For spheres=1 To 20
	ode.ODEGeom=New ODEGeom
	ode\body=dBodyCreate(World)
	dBodySetRotation(ode\body,0,0,0)
	dBodySetPosition(ode\body,Rnd(-100,100),30,Rnd(-100,100))
	ode\geom=dCreateSphere(Space,4)
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateSphere()
	ScaleMesh ode\mesh,4,4,4
	RotateMesh ode\mesh,0,0,0
	PositionMesh ode\mesh,0,0,0
	EntityColor ode\mesh,Rnd(255),Rnd(255),Rnd(255)
	EntityAlpha ode\mesh,1
	EntityShininess ode\mesh,0.7
Next

For capsules=1 To 20
	ode.ODEGeom=New ODEGeom
	ode\body=dBodyCreate(World)
	dBodySetRotation(ode\body,90,0,0)
	dBodySetPosition(ode\body,Rnd(-100,100),30,Rnd(-100,100))
	ode\geom=dCreateCapsule(Space,1,8)
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateCylinder(8)
	ScaleMesh ode\mesh,1,5,1
	RotateMesh ode\mesh,90,0,0	; <<< Mesh X-Axis must be rotated 90 degrees to fix cylinder alignment
	PositionMesh ode\mesh,0,0,0
	EntityColor ode\mesh,Rnd(255),Rnd(255),Rnd(255)
	EntityAlpha ode\mesh,1
	EntityShininess ode\mesh,0.7
Next

; ### Create light

Global Light=CreateLight()

RotateEntity Light,45,-90,0
LightColor Light,255,255,255
AmbientLight 130,130,130

; ### Create camera

Global CameraPivot=CreatePivot(CMesh)
PositionEntity CameraPivot,0,2,-7

Global Camera=CreateCamera()
CameraClsColor Camera,0,0,0
CameraRange Camera,1,1000

; ### Create plane

dCreatePlane(Space,0,1,0,0)

Plane=CreatePlane()

EntityAlpha Plane,0.8

PlaneTexture=CreateTexture(128,128,9)

ClsColor 0,200,80
Cls

Color 255,255,255

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 Plane,PlaneTexture,0,0

Mirror=CreateMirror()

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

; ### BLITZ STATIC OBJECT (White)

blitzobject=CreateCube()
ScaleMesh blitzobject,1,4,20
RotateMesh blitzobject,-10,8,4
PositionMesh blitzobject,10,5,40

EntityColor blitzobject,255,255,255
EntityAlpha blitzobject,1

; ### ODE STATIC OBJECT (Blue)

ode.ODEGeom=New ODEGeom
ode\geom=dCreateBox(Space,2,8,40)
dGeomSetRotation(ode\geom,-10,8,4)
dGeomSetPosition(ode\geom,20,5,40)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,1,4,20
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0

EntityColor ode\mesh,0,100,200
EntityAlpha ode\mesh,1

; ### ODE STATIC OBJECT (Red)

ode.ODEGeom=New ODEGeom
ode\geom=dCreateBox(Space,18,0.2,40)
dGeomSetRotation(ode\geom,-14,0,0)
dGeomSetPosition(ode\geom,-20,4.9,40)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,9,0.1,20
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0

EntityColor ode\mesh,200,0,100
EntityAlpha ode\mesh,1

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

SetupCar()

While Not KeyHit(1)

	UpdateKeys()

	UpdateCar()

	UpdateGeoms()

	For count=1 To 4
		dGeomContactSetMu(WGeom(count),GeomFriction)
	Next

	PTime=MilliSecs()

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

	PhysicsTime#=MilliSecs()-PTime

	UpdateCam()

	UpdateWorld

	RenderWorld

	Text 0,0,"JV-ODE Version "+dGetVersion()
	Text 0,15,"Physics Time:"+PhysicsTime
	Text 0,50,"Force:"+Force
	Text 0,65,"Torque:"+Torque
	Text 0,100,"Use F1 & F2 To Modify Wheel Friction"
	Text 0,115,"GeomFriction:"+GeomFriction
	Text 640,0,"A - Accelerate"
	Text 640,15,"Z - Brake/Reverse"
	Text 640,30,"Arrows - Steering"
	Text 640,45,"Space - Reset Car"

	Flip

Wend

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

End

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

Function SetupCar()

For count=1 To 4
	Joint(count)=dJointCreateHinge2(World,0)
	dJointAttach(Joint(count),Car,Wheel(count))
	dJointSetHinge2Anchor(Joint(count),dBodyGetPositionX(Wheel(count)),dBodyGetPositionY(Wheel(count)),dBodyGetPositionZ(Wheel(count)))
	dJointSetHinge2Axis1(Joint(count),0,1,0)
	dJointSetHinge2Axis2(Joint(count),-1,0,0)
	dJointSetHinge2Param(Joint(count),dParamSuspensionERP,0.8)
	dJointSetHinge2Param(Joint(count),dParamSuspensionCFM,SuspensionHS)
	If count>2
		dJointSetHinge2Param(Joint(count),dParamLoStop,0)
		dJointSetHinge2Param(Joint(count),dParamHiStop,0)
		End If
Next

Force=0

End Function

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

Function UpdateKeys()

If KeyDown(30)=1
	Force=Force+0.08
	If Force>30 Then Force=30
	End If

If KeyDown(44)=1
	Force=Force-0.1
	If Force<-10 Then Force=-10
	If Force>0 Then Force=Force*0.97
	End If

If KeyDown(30)=0 And KeyDown(44)=0 Then Force=Force*0.99

If KeyDown(203)=1 Or KeyDown(205)=1
	If KeyDown(203)=1
		Steer=0.5
		Else
		Steer=-0.5
		End If
	Else
	Steer=0
	End If

If KeyHit(57)=1
	Force=0
	dBodySetRotation(Car,dGeomGetPitch#(CGeom),dGeomGetYaw#(CGeom),0)
	End If

If KeyDown(59)=1 Then GeomFriction=GeomFriction+1
If KeyDown(60)=1 And GeomFriction>0 Then GeomFriction=GeomFriction-1

End Function

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

Function UpdateCar()

For count=1 To 4
	dBodyEnable(Wheel(count))
Next

dBodyEnable(Car)

For count=1 To 4
	dJointSetHinge2Param(Joint(count),dParamVel2,Force)
	dJointSetHinge2Param(Joint(count),dParamFMax2,Torque)
Next

For count=1 To 2
	angle#=Steer-dJointGetHinge2Angle1(Joint(count))
	dJointSetHinge2Param(Joint(count),dParamVel,angle)
	dJointSetHinge2Param(Joint(count),dParamFMax,400)
Next

End Function

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

Function UpdateCam()

PositionEntity CameraPivot,0,3,-12

camx#=EntityX(CameraPivot,1)-EntityX(Camera)
camy#=EntityY(CameraPivot,1)-EntityY(Camera)
camz#=EntityZ(CameraPivot,1)-EntityZ(Camera)

TranslateEntity Camera,camx*0.5,camy*0.5,camz*0.5

PointEntity Camera,CMesh

End Function

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

Function UpdateGeoms()

For ode.ODEGeom=Each ODEGeom
	RotateEntity ode\mesh,dGeomGetPitch#(ode\geom),dGeomGetYaw#(ode\geom),dGeomGetRoll#(ode\geom)
	PositionEntity ode\mesh,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)
Next

End Function

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


Thank You Jim! =D

Good Day,

I'm trying to buy JV-ODE but on the website the Buy Now button doesn't show up.

Hi,

It seems to be working ok here at the moment, are you using http://jv-ode.devcode.co.uk/ ?

Let me know if you're still having problems and I'll look into it further for you.

Yeah that's the site I'm using. I still can't purchase, even on my laptop. There is no Buy Now button. I hope I'm not the only one with this problem. If I am I can't explain it.

Strange, it still works here, maybe your browser cache needs clearing?

Here's some direct links to the Share*it product pages...

JV-ODE Blitz3D Version

JV-ODE BlitzMax Version

Thanks for the links dude. I cleaned the cache, same thing happens. Anyway, I will be buying your software.

I bought JV-ODE for Blitz3D a while ago and now have a new email address. The old email address is defunct and I do not have access to it. How do I download the latest version?

I do have the original email with the 1.17 version download as well as my username and password.

Mike Felker
mike at world-class-multimedia.com
www.world-class-multimedia.com

Hi,

I've updated your email address with the one in your profile and sent you an email regarding the latest version download.

Got it - thanks.

Mike

Someone has created a good "brake system" (for vehicles) with ODE? Can someone help me with this?

Use zero force and lots of torque on the wheel joints.

Adding the following code to the UpdateKeys() function in the car demos will lock all four wheels when the 'down' arrow key is pressed...

If KeyDown(208)=1
	Force=0
	Torque=1000
	Else
	Torque=24
	End If


Jim,

I'm making a "progressive brake", where you can control the "force" of the brake with the pedal... My brake work in a plane highway, but, in a Downhill highway, the brake make my car lose the control, something like the wheel turning for one side...

I have tried making the "Force" go down and Torque go up, progressively, like this:

Force=Force-0.01*BrakePedal#
HingeTorque=HingeTorque+(0.1*BrakePedal#)

I believe that I'll need to use another variable to control the brake...

..I just bought this cute wrapper...so far its all smooth, but I would like to know how to properly use >>dBodyGetLinearVel(body)<<, because when i try to use it, I got 'Illegal type conversion' error...what i did is I just wanted to get Linear velocity by doing this LVelocity=dBodyGetLinearVel(Car) (I tried with one of provided examples)..

@EmerGki: Ah progressive braking, I see. Using force damping like that is like engine braking which might not be what you want. Have you tried using zero force and only progressive torque instead? It's difficult to suggest the cause of the loss of control without seeing it in action, but it could be linked to the levels of mass and friction you're using for the car/wheels/highway.

@NA: The dBodyGetLinearVel(body) function returns a vector in ODE, which can't be returned to Blitz directly. You can either use the unique JV-ODE functions to return a specific vector component using dBodyGetLinearVelX(body), dBodyGetLinearVelY(body) or dBodyGetLinearVelZ(body). Or you can get the complete vector by calling dBodyGetLinearVel(body) and then use the vector functions like this...

dBodyGetLinearVel(body)
LVelX#=dVectorX()
LVelY#=dVectorY()
LVelZ#=dVectorZ()


..in order to make my level geometry physics interactive, I have to use trimesh stuff from examples?? or there is another way?? How to make custom shape geometry physics interactive(non static)?

TriMeshes should only be used for static objects in reality, they're too slow compared to primitives. If you want to create non static custom geometry, you need to build composite objects using multiple primitive geoms like cubes, spheres and capsules with geom offsets. Look at the Geom Offset demos to see how it works. Once you've built your custom physics geometry, update your custom mesh (the visible geometry) with the position/rotation of the body or one of the geoms.

JV-ODE V1.28 Update Released

Please check your inbox :)

All JV-ODE demos have been updated, tweaked and improved.

Added new demos:
CarDemo-AABB
CarDemo-Duo
CarDemo-Velocity
Demo-RayPick (Blitz3D Version)
Demo-Slider
Demo-TriMeshes (BlitzMax Version)


The following demos now use Geom Offsets instead of Geom Transforms...
CarDemo-TruckTrailer
CarDemo-SphereWrapCylinder
Demo-RagDolls-Zombie (Blitz3D Version)


The old Geom Transform demos are obsolete and have been removed, however Geom Transforms are still supported in JV-ODE.

The JV-ODE OpenGL 3D Engine module in the BlitzMax version has been completely redesigned to mimic the command set and appearance of Blitz3D. All JV-ODE BlitzMax demos have been modified to use the new 3D engine. It is now much easier to convert the demos to run in MiniB3D, for example to convert the Demo-Spheres code, change the Framework to SiDesign.MiniB3D and comment out the Blitz Plane code - that's it.

An updated Leadwerks Engine Demo Pack is also available from the Leadwerks Forums.

Please let me know if you experience any problems with the new update.

:)

..nice.. thanks man.. :) you really keeping things updated...

After the Version 1.25, I'm getting this error:



How to solve this problem, or, what's wrong??


So, I'm still using the 1.24...

@NA: You're welcome :)

@EmerGki: I take it you're using dMassTranslate()?

In the recent versions of ODE, the centre of mass must be at 0,0,0 in relation to the position of the body (the origin) or it will throw an error. It has always worked this way but earlier versions didn't throw an error if it was used incorrectly.

It's quite complicated and it works the opposite way to how you might think.

I've asked the ODE authors about this before and they admitted the function name is misleading. If you create a body and attach two geoms to it, with the second geom off-centre, you have to reposition all of the geometry until the centre of the whole object is at 0,0,0. Then, you translate the mass back to the centre of the whole object which is now 0,0,0.

So you don't move the centre of gravity, you move the geometry until it's overall centre is at 0,0,0, then you reset the centre of gravity to 0,0,0 with dMassTranslate(). It's used in one of the ODE examples which you can find here.

..im a bit stuck with trimeshes...maybe because i use to use all time Physx wrapper so its a different..I just dont know...in Physx if you dont describe object mass, its considered infinite mass, therefore, static..here I had look over demo-trimeshes and it seems that they are dynamic and not static/while mass is not described/..Im wondering what exactly and how to enable parts of my geometry to be static(non uniform geometry, my level practically), with use of trimeshes..

VIP3R, do you mind to post again cloth demonstration with use of spheres, I lost it..and is it possible to use pivots instead of spheres?

In ODE you have a rigid body which has mass and is affected by gravity and forces etc. Then you have the geom, which is used for collision detection. To create a TriMesh that is non-static, it needs a body like in the Demo-TriMeshes demo. To create a static TriMesh, you only create the geom and omit the body. If you look at the CarDemo-TriMesh-* demo code, you will notice the static terrain TriMeshes don't have a body associated with them.

If you don't specify the mass, ODE will use a default mass value of 1.0, not infinity. As there is no body associated with static objects, they have no mass, but behave as if their mass is infinite.

The cloth demo is in JV-ODE Physics Thread 10, about two-thirds of the way down. The visible sphere meshes can be replaced with anything you like, pivots, mesh bones etc.

..okay..I hope im doing something wrong here and its not wrapper issue..I want to set up my level to be static..now..during loading, I pass trough level structure loaded with LoadAnimMesh and store every element in to types so later I have names, and ID for each element on scene. Then I pass trough elements in Type and turn them in to trimesh with Trimesh function provided with samples..and..nothing happen..cubes or other primitives i create for sake of test, simply drop trough my level geometry....I did similar approach with Physx and it was working without any problems...I also noticed that command dSpaceCollide is present in demos while docs said its unsuported...what im missing here??

..hmm..I got it work but its extreme slow (4 fps) dropped from 70fps..what i did is, I sliced my level in to 4 chunks and load them separately as use for physics, practically this:
Ode1=LoadMesh("Ode1.b3d")
trimesh1=CreateTriMesh(Space,Ode1)
FreeEntity Ode1
Ode2=LoadMesh("Ode2.b3d")
trimesh2=CreateTriMesh(Space,Ode2)
FreeEntity Ode2
Ode3=LoadMesh("Ode3.b3d")
trimesh3=CreateTriMesh(Space,Ode3)
FreeEntity Ode3
Ode4=LoadMesh("Ode4.b3d")
trimesh4=CreateTriMesh(Space,Ode4)
FreeEntity Ode4

after this, collision working over geometry properly but with funny slow fps..level has 120K polys and same level I use to rig with Physx before worked fine and with no slowdown at all..what I did wrong here??

To create a TriMesh from a mesh loaded with LoadAnimMesh, you need to use the CreateAnimTriMesh() function instead of CreateTriMesh(). Look at the CarDemo-AnimTriMesh demo, you need to specify which layer to use for the geometry.

dSpaceCollide() is not implemented in its original form, the JV-ODE version has different parameters, notice the docs have a link 'Unique JV-ODE Function alternative' next to it.

The slowdown is caused by the static TriMeshes colliding with other scenery like the plane or other TriMeshes. You need to use a sub-space for the static scenery and disable internal collisions with dSetInternalSpaceCollideMode(0) to prevent them colliding with each other. Look at the CarDemo-TriMesh-X4 demo and check how the spaces are used, search the code for SceneSpace to see where. First the sub-spaces are added to the top level space, next internal collisions are disabled, then each scenery object is created in the sub-space SceneSpace (not 'Space' which is the top level space).

You'll soon have it running like greased lightning ;)

given meshes were collapsed in to one single mesh, thats why I used CreateTriMesh()...however I havent use dSetInternalSpaceCollideMode(0), what may cause problems...because when my car dropped on to scene, its was jumping like a horse until jump becomeso big that carr dissapear on horizon...I just copied same car settings I did without racing track, where things use to work perfect..anyway here is how structure look like..all level entities are stored in here
Type Level
field ID
field Name$
field Trimesh
end type
so, when I pass trough this structure i wanted to do
Trimesh=CreateTrimesh(Space,Entity\ID) , and similar thing working smooth like silk with Physx (but i want to go for ODE because of drivers physix require)..so when i do that on way I show with Ode, program freeze so i had to slice level in few chunks and load separately outside of hierarchy i show just now..then it worked but horribly slow, and car never ever touched track itself(i load already tested and set car, with no scaling or anything, and all previously set in empty scene with plane)..instead car jumping a lot...

Now..I set up car on such way that car shell is trimesh, but wheels are primitives(spheres) and wheels shouldcollide as they do just fine on my setup scene...so, im a bit confused because racing track is up to scale with car already set so i havent touch that..ehh

Ok, the car disappearing on the horizon is the simulation exploding, which is caused by a bad setup.

It's ok to use a single mesh for the terrain, but you must use the CreateAnimTriMesh() function if you're loading a mesh with LoadAnimMesh. You shouldn't have to slice your meshes for them to work, that's bypassing the actual problem, instead of fixing it.

As mentioned earlier, to fix the slowdown, setup your spaces like this...
Global Space=dHashSpaceCreate(0)
Global SceneSpace=dHashSpaceCreate(Space)
dSetInternalSpaceCollideMode(0)
...
dCreatePlane(SceneSpace,0,1,0,0) ; <<< If a plane is used
Trimesh=CreateTrimesh(SceneSpace,TLevel\TriMesh) ; <<< Use CreateAnimTriMesh here if using LoadAnimMesh
Next, don't use a TriMesh for the car shell, build it from primitives (boxes). You can use any mesh for the visible entity, you don't have to use cubes. You should have an ODE body (ode\body), an ODE geom (ode\geom - boxes) and the car shell mesh (ode\mesh - .B3D .3DS etc).

Be aware that Physx and ODE work differently to each other. So whatever worked in Physx might need tweaking to behave the same in ODE.

If you're still stuck, post some code (or send it via email) so that I can show you where you're going wrong. Or send me the level & car meshes, and I will add them to a simple demo for you so that you can see how to do it correctly.

...thanks man...I will send you level(its actual model for F1 racing circuit in malaysia), and car with all parts separated(shell, wheels, discs...)...i can use this email jv-ode[no-spam]devcode.co.uk?

My scene setup is same as you have been posted...is there any requirement from ODE regarding polygons on geometry or way how is it triangulated, or whatever?? I will send you level+car in next 1 hour..

..ok..geometry+ car + some screenshots sent...

Thanks, I've just received it, gimme an hour or two.

There are no special requirements for the geometry, every mesh I've tried so far has worked ok.

Ok, I've sent you a working demo with all 958 TriMeshes running at less than 1.0 physics time.

That's seriously fast!!!

..yeah..wonderful..I see why it was slow..or not collision at all..only thing I didnt use properly is Trimesh function(I used one provided with demo scenes)...I luv it..thank you A LOT..

You're welcome :)

.Vip3r, how to change friction value on the fly? I have tried to change friction value in runtime(depending what car do) with use of dContactSetMu(WorldFriction), while changing WorldFriction value on the fly, but it seems that there is no effect, related to initial set up..how to update world friction on the fly??

World friction only changes when a new geom is created. You need to use the Geom Contact functions if you want to change the friction in real time... dGeomContactSetMu(geom,mu)

There's a demo showing it in use half way up this thread ^

...Schön... :)

VIP3R,

Once again, thank you very much for your latest update (1.28).
Excellent customer support as always.

cheers,

Mark

VIP3R, have been excercising my VB.net skills in conjunction with a front end for car Demo. Dropped in 1.28 dll to the directory & works a treat. Any thoughts you have with regard to extra buttons to auto configure stuff appreciated. Heres the post:

http://www.blitzbasic.com/Community/posts.php?topic=80626

You're welcome Mark :)

@Blitzplotter: How about some buttons to change the mass / suspension / wheel friction of each car. You could use a list box to select the car, then three input boxes for the settings?

Silly question. How do I get this update? It wasn't emailed to me. Thanks.

@VIP3R, could do... need to apply some more thought to the structure of my ini file, as I intend to write out to the ini file from VB.Net with whatever is populated, the B3D exe will read the ini file and run with whatever's passed.

@proud2bme: Your update email was sent to the address you used when purchasing JV-ODE, I've not received any error to indicate it failed. Check your spam filters if you're using one. Let me know the address I have is correct and I'll resend it for you.

All I see in my junk mail folder are emails about Viagra. The original email containing my JV-ODE purchase had no problems reaching my inbox. The address there is the same.

Ok, I've resent the update email for you.

I started looking into physics stuff for my game and started wondering how some shapes (like boxes or barrels) should be initialized?

TriMesh? If so... can you provide simple code for creating TriMesh barrel (I'm testing Demo-MultipleObjects, and would be nice to see how it could work with "barrel.3ds")

Or... box geoms? But then, is there any easy way to provide physics geom for the barrel mesh?

Thanks

TriMeshes should only really be used for static scenery, they're much slower than primitives (boxes, spheres and cylinders).

Any meshes can be used to represent any type of ODE object, just change the ode\mesh to whatever you want... ode\mesh=LoadMesh("mesh.3ds")

To create a barrel with a custom mesh, you should create a cylinder ODE geom (ode\geom) and use the 'barrel.3ds' for the visible mesh (ode\mesh).

Sorry to say, I still haven't received my 1.28 update VIP3R. I sent you an email and I'm wondering why nothing you sent showed up. I did check my junk mail and, nothing there either. Thanks for any info.

VIP3R, yes, I realize that any mesh can be used to represent... but how can I (relatively) easily make the cylinder ODE geom match the barrel mesh. If I just create cylinder, it doesn't mean that my 2 units wide, 1.73 units high barrel will be okay. And not to mention the other barrel that might have totally different values.

Is there any 'easy way' to match those primitives? I wonder if anybody has created an editor for this purpose? (If not, then I suppose I gotta do it :))

@proud2bme: I haven't received any emails from you within the last 24 hours and I've still not received any errors to indicate your update email failed. Our email accounts are all running ok, I would advise you check whether your email account is working correctly. Let me know if you manage to get it working, or if you want to use a different address instead.

@Game Producer: I see, it wasn't clear that was the info you wanted. There are 3 sets of dimensions you need to think about... ODE Geoms, Blitz Meshes and Custom Meshes.

The default dimensions of Blitz meshes is 1 unit. The corresponding ODE geom size for a Blitz mesh with default dimensions is as follows...

Sphere
1.0 (Same as Blitz units)

Cube
0.5 (1/2 of Blitz units)

Cylinder
0.5 Length (1/2 of Blitz units)
1.0 Radius (Same as Blitz units)

For custom meshes like your barrel, it depends on the dimensions used when it was created. The dimensions of the ODE geom should match the mesh units. For example a barrel mesh with the dimensions of 3.0 units length and 1.0 units radius, would be setup like this... dCreateCylinder(Space,1.0,3.0)

If you alter the scale of the mesh in Blitz, you may need to do the same with the ODE geom dimensions.

@VIP3R: Yes, thanks. Then exporting content pack art (which might have different starting positions, and "weird" units that are not possible to know in Blitz side, it would mean manually creating the corresponding ODE geoms).

Gotta start making an editor for that (shouldn't be too hard though :))

Thanks for the info!

---

Another question came to my mind: is there ready made example on how to get characters (like human) moving with ASWD type of controls? (if the character is made of 'cylinder' for example (and perhaps a cube or something attached in the head :))

What about some sort of "waypoint system", is there examples for these type of controls?

---

Thanks again for great support (yeh, I'm a happy JV-ODE customer and have bugged you earlier :))

You're welcome :)

There isn't a character controller demo using capsules/cylinders, but there is something which uses a sphere in the same way...

; JV-ODE - Key Controlled Sphere Demo Using Angular Velocities
; Code by Jim Williams (VIP3R)
; Arrow key control by Jeff (PsychicParrot)

AppTitle "JV-ODE - Key Controlled sphere Demo"

Include "jv-ode.bb"

Graphics3D 800,600,0,2

Type ODEGeom

	Field body
	Field geom
	Field mesh
	Field pivot ; To find direction vectors
	Field head  ; Just a stupid head to show which direction it's going in!
	Field inair ; To tell if player is on the ground or not!!
	
End Type

; ### Setup ODE

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

dWorldSetGravity(World,0,-1,0)
dContactSetMode(dContactBounce)
dContactSetBounce(0.2)
dContactSetMu(38)

; ### Create light

Global Light=CreateLight()

RotateEntity Light,45,-90,0
LightColor Light,255,255,255
AmbientLight 130,130,130

; ### Create camera

Global Camera=CreateCamera()
CameraClsColor Camera,0,0,0
CameraRange Camera,1,1000
PositionEntity Camera,0,20,-50
RotateEntity Camera,30,0,0

; ### Control vars

Global potato#=0 ; y rotation of thingy (rotater,rotato,potato!!)
Global spud#
Global fwd_key
Global back_key
Global left_key
Global right_key
Global jump_key

; ### Create plane

dCreatePlane(Space,0,1,0,0)

Plane=CreatePlane()

EntityAlpha Plane,0.8

PlaneTexture=CreateTexture(128,128,9)

ClsColor 0,200,80
Cls

Color 255,255,255

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 Plane,PlaneTexture,0,0
EntityPickMode plane,2

Mirror=CreateMirror()

AddObject() ; Add our thingy to the world

While Not KeyHit(1)

	PTime=MilliSecs()

	; Update controls
	
	c.ODEGeom=First ODEGeom
	Getkeys(c)
	movethingy(c)
	lookforground(c)
	
	PointEntity (camera,c\mesh)
	
	UpdateGeoms()

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

	PhysicsTime#=MilliSecs()-PTime

	UpdateWorld

	RenderWorld

	Text 0,0,"JV-ODE Version "+dGetVersion()
	Text 0,15,"Physics Time:"+PhysicsTime

	Flip

Wend

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

End

Function getkeys(c.ODEGeom)

	fwd_key=False
	back_key=False
	left_key=False
	right_key=False
	jump_key=False

	If c\inair=False Then ; Only let player control 'thrust' when on the ground
	
		If KeyDown(200) Then fwd_key=True
		If KeyDown(208) Then back_key=True

	EndIf
	
		If KeyDown(205) Then left_key=True
		If KeyDown(203) Then right_key=True
		If KeyDown(57) Then jump_key=True

	;EndIf

End Function

Function lookforground(c.ODEGeom)

	If LinePick(EntityX(c\mesh,True),EntityY(c\mesh,True)+1,EntityZ(c\mesh,True),0,-4,0)<>0 Then ; Check for anything 'under' player
		c\inair=False
	  Else
		c\inair=True
	EndIf

End Function

Function movethingy(c.ODEGeom)

	If fwd_key=True Then
		spud=spud+.1
	EndIf

	If back_key=True Then
		spud=spud-.1
	EndIf
	
	If left_key=True Then
		potato=potato-2
	End If
	
	If right_key=True Then
		potato=potato+2
	End If

	If jump_key=True And c\inair=False Then		
		dBodyAddForce(c\body,0,16 ,0)		
	End If

	RotateEntity c\head,0,potato#,0
	
	; Add forward force

	TFormVector 0,0,spud,c\head,0
	
	vx# = dBodyGetAngularVelX(c\body) + TFormedX()
	vy# = dBodyGetAngularVelY(c\body) + TFormedY()
	vz# = dBodyGetAngularVelZ(c\body) + TFormedZ()

	damping#=.8
	dBodySetAngularVel(c\body,vx#*damping#,vy#*damping#,vz#*damping#)

	spud=spud*.9
	
End Function

Function AddObject()

xp=Rand(-8,8)
zp=Rand(-8,8)
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,xp,30,zp)
dBodySetAutoDisableFlag(ode\body,0)
ode\geom=dCreateSphere(Space,3)
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateSphere()
ScaleMesh ode\mesh,3,3,3
EntityColor ode\mesh,Rand(255),Rand(255),Rand(255)
EntityAlpha ode\mesh,1
EntityShininess ode\mesh,0.7
ode\head=CreateCube()

ScaleMesh ode\head,1.5,1.5,1.5

ode\pivot=CreatePivot() ; Create pivot to get direction vectors

End Function


Function UpdateGeoms()

For ode.ODEGeom=Each ODEGeom
	
		RotateEntity ode\mesh,dGeomGetPitch#(ode\geom),dGeomGetYaw#(ode\geom),dGeomGetRoll#(ode\geom)
		
		PositionEntity ode\mesh,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)
		
		PositionEntity ode\head,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom)+4.5,dGeomGetPositionZ#(ode\geom)
	
Next

End Function


Waypoints are not directly related to physics engines, hence no examples. You'll find much more information about waypoint systems in the Blitz3D Programming forum.

Okay, thanks.

I've looked more into this and found some suggestion where 'capsule' should be staying on top of a ray.

I'm looking into this example (http://www.enchantedage.com/sites/default/files/raycar/index.html) but any ideas on how to keep the capsule on top of ray would be gladly taken :)

I've don't have any experience with it tbh, never understood why people would use a capsule over a sphere-composite object. An upright capsule would drag across a surface, exactly the opposite of what a physics engine is designed to do with it.

Anyway, there's more info here...
http://opende.sourceforge.net/mediawiki-1.6.10/index.php/HOWTO_upright_capsule

Good luck ;)

sphere is "fat"... you want to have a taller guy and be able to hit the body (not just the low part) (check hit location using ray, or throw stuff towards the guy). I haven't seen many characters that resemble spheres :D

with 'ray' you are able to create jumping/crouching too.

not sure what you mean by "upright capsule would drag"... since I believe this is how people are doing character movement in games :)

thanks for the link

p.s. did you check out that ray demo link...?

Okay, getting there...

Based on information here (http://www.ode.org/old_list_archives/2006-June/019114.html) I started tweaking the 'ball control' code and added stuff like here:
	dBodySetRotation(c\body,0, 0, 0)
	dBodySetAngularVel(c\body,0, 0, 0)
	dBodySetTorque (c\body,0, 0, 0)

	;xforce# = leftforce-rightforce
	;zforce# = forwardforce-backforce

	dBodyAddForce(c\body, xforce#, 0, zforce# )


This works pretty good for moving FORWARD + RIGHT, but for some reason when I try to move down or left, it always moves 'southwest'. I haven't used ray nor spring yet, but will try that stuff at some point.

Here's the full code (any help regarding the odd behavior for down/left movement gladly taken):

(EDIT: see below for newer code...)

Updated the code a bit...

(EDIT: see below for newer code...)

Also found this:
http://www.ogre3d.org/wiki/index.php/OgreOde_Walking_Character
(seemed quite interesting approach)

And now it works! :)'
(still need some work, but at least it's decent!)

The capsule demo:

; JV-ODE - Key Controlled Sphere Demo Using Angular Velocities
; Code by Jim Williams (VIP3R)
; Arrow key control by Jeff (PsychicParrot)
; Character control by Juuso (www.GameProducer.net)

AppTitle "JV-ODE - Key Controlled capsule Demo"

Include "jv-ode.bb"

Graphics3D 800,600,0,2

SeedRnd(MilliSecs())

Type ODEGeom

	Field body
	Field geom
	Field mesh
	Field pivot ; To find direction vectors
	Field head  ; Just a stupid head to show which direction it's going in!
	Field inair ; To tell if player is on the ground or not!!
	
End Type

; ### Setup ODE

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

dWorldSetGravity(World,0,-1,0)
dContactSetMode(dContactBounce)
dContactSetBounce(0.1)
dContactSetMu(10)

; ### Create light

Global Light=CreateLight()

RotateEntity Light,45,-90,0
LightColor Light,255,255,255
AmbientLight 130,130,130

; ### Create camera

Global Camera=CreateCamera()
CameraClsColor Camera,0,0,0
CameraRange Camera,1,1000
PositionEntity Camera,0,20,-50
RotateEntity Camera,30,0,0

; ### Control vars

Global potato#=0 ; y rotation of thingy (rotater,rotato,potato!!)
Global spud#
Global fwd_key
Global back_key
Global left_key
Global right_key
Global jump_key

; ### Create plane

dCreatePlane(Space,0,1,0,0)

Plane=CreatePlane()

EntityAlpha Plane,0.8

PlaneTexture=CreateTexture(128,128,9)

ClsColor 0,200,80
Cls

Color 255,255,255

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 Plane,PlaneTexture,0,0
EntityPickMode plane,2
EntityAlpha plane, .7

;Mirror=CreateMirror()

AddObject() ; Add our thingy to the world

For i=1 To 10
	AddObject()
Next


While Not KeyHit(1)

	PTime=MilliSecs()

	; Update controls
	
	c.ODEGeom=First ODEGeom
	Getkeys(c)
	movethingy(c)
	lookforground(c)
	
	
	;PositionEntity camera, c\mesh)
	
	UpdateGeoms()

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

	PhysicsTime#=MilliSecs()-PTime

	UpdateWorld

	RenderWorld

	Text 0,0,"JV-ODE Version "+dGetVersion()
	Text 0,15,"Physics Time:"+PhysicsTime

	Flip

Wend

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

End

Function getkeys(c.ODEGeom)

	fwd_key=False
	back_key=False
	left_key=False
	right_key=False
	jump_key=False

	If c\inair=False Then ; Only let player control 'thrust' when on the ground
	
		If KeyDown(200) Then fwd_key=True
		If KeyDown(208) Then back_key=True

	EndIf
	
		If KeyDown(205) Then left_key=True
		If KeyDown(203) Then right_key=True
		If KeyDown(57) Then jump_key=True

	;EndIf

End Function

Function lookforground(c.ODEGeom)

	If LinePick(EntityX(c\mesh,True),EntityY(c\mesh,True)+1,EntityZ(c\mesh,True),0,-4,0)<>0 Then ; Check for anything 'under' player
		c\inair=False
	  Else
		c\inair=True
	EndIf

End Function

Global counter
Function movethingy(c.ODEGeom)

	speed = 2
	If fwd_key=True Then
		zforce# = speed 
	EndIf

	If back_key=True Then
		zforce# = -speed 
	EndIf
	
	If left_key=True Then
		xforce# = speed 
	End If
	
	If right_key=True Then
		xforce# = -speed 

	End If


	dBodySetAngularVel(c\body,0, 0, 0)
	dBodySetTorque (c\body,0, 0, 0)
	dBodySetRotation(c\body,90, 0, 0)

	
	;xforce# = leftforce-rightforce
	;zforce# = forwardforce-backforce

	dBodySetPosition(c\body, dGeomGetPositionX#(c\geom), 2.9 ,dGeomGetPositionZ#(c\geom) )

	dBodyAddForce(c\body, Int(xforce#), 0, Int(zforce#) )

	;DebugLog "get force:"+dBodyGetForce(c\body)
		

	If jump_key=True And c\inair=False Then		
		xforce = 10 * (Rnd(-1, 1))
		zforce = 10 * (Rnd(-1, 1))
		
		dBodyAddForce(c\body, 0 , 10 , 0 )		
	End If
	
End Function

Function AddObject()

xp=Rand(-8,8)
zp=Rand(-8,8)
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
dBodySetRotation(ode\body,90,0,0)
dBodySetPosition(ode\body,xp,0,zp)
dBodySetAutoDisableFlag(ode\body,0)
;ode\geom=dCreateSphere(Space,3)
;ode\geom=dCreateBox(Space, 2, 6, 2)
ode\geom=dCreateCapsule(space,1,8)

dGeomContactSetBounce(ode\geom, 1.000)



dGeomSetBody(ode\geom,ode\body)
;ode\mesh=CreateSphere()
;ode\mesh=CreateCube()
ode\mesh=CreateCylinder()
ScaleMesh ode\mesh,1,5,1
RotateMesh ode\mesh,90,0,0	; ### Align Blitz3D Cylinder To ODE Capsule

;RotateMesh ode\mesh,90,0,0

EntityColor ode\mesh,Rand(255),Rand(255),Rand(255)
EntityAlpha ode\mesh,1
EntityShininess ode\mesh,0.7
ode\head=CreateCube()


mass=dMassCreate()
;dMassSetBoxTotal(mass, 2, 1,1,1)
;dBodySetMass(ode\body,mass)


ScaleMesh ode\head,1.5,1.5,1.5

ode\pivot=CreatePivot() ; Create pivot to get direction vectors


PointEntity (camera,ode\mesh)

End Function


Function UpdateGeoms()

For ode.ODEGeom=Each ODEGeom
	
		RotateEntity ode\mesh,dGeomGetPitch#(ode\geom),dGeomGetYaw#(ode\geom),dGeomGetRoll#(ode\geom)
		
		PositionEntity ode\mesh,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)
		
		PositionEntity ode\head,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom)+14.5,dGeomGetPositionZ#(ode\geom)
	
Next

End Function


Sorry for quadruple posting - stopping now;)

I said a sphere-composite, for example a small sphere at the feet and another object to represent the body. Not a sphere to represent the entire character :)

Glad to see you have it working now though, it might be a good idea to remove the earlier code posts and leave only the working version.

Ah, sorry. Hasty reading from my part :)

Anyway, looks like the capsule thing works pretty neatly (removed older code). Will still look on how to do the ray-thing in the feet (since it should work better with stuff like stairs (compared to ball at the feet)

Thanks VIP3R for such quick comments & good support.

You're welcome :)

Thanks for updating your posts. I would imagine you extend the rays from the base of the capsule towards the floor, then when the ray penetrates the floor, you raise the capsule until it's no longer penetrating. It should work ok for stairs as long as the rays are long enough.

Aye, thanks again. I'll see if I manage to do that next...

Question about rays:
dGeomRaySet(ray,px#,py#,pz#, dx#,dy#,dz#)

Ogre docs said:
Ogre::Vector3 diff = dest - pos;
diff.normalise();
dGeomRaySet(mRay, pos.x, pos.y, pos.z, diff.x, diff.y, diff.z);


How do you find out which values there should be for dx, dy, and dz? I'm using the following:
px# = EntityX(gun)
py# = EntityY(gun)
pz# = EntityZ(gun)

dx# = EntityX(pivot)-EntityX(gun)
dy# = EntityY(pivot)-EntityY(gun)
dz# = EntityZ(pivot)-EntityZ(gun)

dGeomRaySet(RayGeom, px#, py#, pz#, dx#, dy#, dz# )


EDIT: Managed to get this working. Sweet! :)

Here's the "shoot the ground (or that box)" code.
; ; ###################################################################################################
; #                                     JV-ODE - Ray Pick Demo                                      #
; #                                  Code by Jim Williams (VIP3R)                                   #
; #                              Devious Codeworks - Copyright © 2008                               #
; ###################################################################################################

Include "JV-ODE.bb"

AppTitle "JV-ODE - Ray Pick Demo"

Graphics3D 800,600,0,2

Global RayGeom
Global RayCollision=0

Type ODEGeom
	Field body
	Field geom
	Field mesh
	
	Field name$
End Type

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

; ### Setup ODE

dInitODE()

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

dWorldSetAutoDisableFlag(World,1)
dWorldSetGravity(World,0,-0.98,0)
dContactSetMode(dContactBounce)
dContactSetBounce(0.01)
dContactSetMu(48)

; ### Create Light

Global Light=CreateLight()
RotateEntity Light,50,-50,0
LightColor Light,255,255,255
AmbientLight 130,130,130

; ### Create Camera

Global Camera=CreateCamera()
CameraClsColor Camera,0,0,0
CameraRange Camera,.1,1000
PositionEntity Camera,0,30,-40

;PositionEntity Camera,2,15,-30


RotateEntity Camera,50,0,0

Global gun = CreateCube()
EntityColor gun, 0, 0 ,200
;EntityAlpha gun, 0.5



; ### Create Plane

dCreatePlane(Space,0,1,0,0)

Global Plane=CreatePlane()
EntityAlpha Plane,0.8

EntityTexture Plane,PlaneTexture()

EntityPickMode plane, 2
Global pivot = CreateSphere()
ScaleEntity pivot, .3, .3, .3

;PositionEntity pivot,2,5,-30
PointEntity Camera, pivot

;CreateMirror()

; ### Create Cylinder

Global Cylinder=CreateCylinder()
ScaleMesh Cylinder,0.2,3,0.2
PositionEntity Cylinder,0,3,-5
RotateEntity Cylinder,90,0,0
EntityColor Cylinder,230,0,0
EntityShininess Cylinder,0.7

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

AddObject()



While Not KeyHit(1)

	pick = CameraPick(camera, MouseX(), MouseY())
	PositionEntity(pivot, PickedX(), PickedY()+1, PickedZ())
	

	If (KeyHit(57) )
		
		
		DebugLog "pressed space"
	EndIf
	


	UpdateGeoms()

	PTime=MilliSecs()

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

	PhysicsTime#=MilliSecs()-PTime

	RenderWorld

	Text 0,0,"JV-ODE Version "+dGetVersion()
	Text 0,15,"Physics Time:"+PhysicsTime
	Text 0,70,"Cylinder = Ray Geom Position"
	Text 0,95,"Green = Collision"
	Text 0,110,"Red = No Collision"

	AddRay()

	Flip 1

Wend

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

End

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

Function AddObject()

ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
dBodySetPosition(ode\body,0,20,0)
dBodySetRotation(ode\body,0,20,20)
dBodySetAutoDisableFlag(ode\body,1)
;ode\geom=dCreateSphere(Space,3)
ode\geom=dCreateBox(Space, 6, 6, 6)

dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,3,3,3
EntityColor ode\mesh,100,100,255
EntityShininess ode\mesh,0.7
EntityAlpha ode\mesh,0.8

ode\name$ = "target..."

End Function

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

Function AddRay()

RayGeom=dCreateRay(Space,300)
;dGeomRaySet(RayGeom,0,3,-5, 0,0,10)
PositionEntity gun, 2, 5, -10
PositionEntity gun, EntityX(camera), EntityY(camera), EntityZ(camera)



PointEntity gun, pivot

;dGeomRaySet(RayGeom, EntityX(gun), EntityY(gun), EntityZ(gun), EntityPitch(pivot), EntityYaw(pivot), EntityRoll(pivot))
px# = EntityX(gun)
py# = EntityY(gun)
pz# = EntityZ(gun)

dx# = EntityX(pivot)-EntityX(gun)
dy# = EntityY(pivot)-EntityY(gun)
dz# = EntityZ(pivot)-EntityZ(gun)

dGeomRaySet(RayGeom, px#, py#, pz#, dx#, dy#, dz# )



; ### Perform Ray Collision Check
dSpaceCollide(Space,World,ContactGroup)
count1=dGeom1CountCollisions(RayGeom)
count2=dGeom2CountCollisions(RayGeom)
RayCollision=count1+count2
dJointGroupEmpty(ContactGroup)

ms = MilliSecs()

mousehit1 = MouseHit(1)

For i=1 To count1
;loop collission count
	CollisionGeom1=dGeom1CollisionGeom(RayGeom,i)
	;DebugLog "collided1 with:"+CollisionGeom1
	For ode.ODEGeom=Each ODEGeom
		If (ode\geom = CollisionGeom1 )
			;DebugLog "ode name:"+ode\name$
		EndIf
	Next

	cx# = dGeom1CollisionX(RayGeom,i)
	cy# = dGeom1CollisionY(RayGeom,i)
	cz# = dGeom1CollisionZ(RayGeom,i)
		
	If (mousehit1)
		temp = CreateSphere()
		EntityColor temp, 200, 100, 200
		size# = .3
		ScaleEntity temp, size#, size#, size#
	;	EntityAlpha temp, .1
		PositionEntity temp, cx, cy, cz#
		
		c.ODEGeom = First ODEGeom
		EntityParent temp, c\mesh
		
		DebugLog "created thingy"
	EndIf
Next


For i=1 To count2
;loop collission count
	CollisionGeom2=dGeom2CollisionGeom(RayGeom,i)
	;DebugLog "collided1 with:"+CollisionGeom2
	For ode.ODEGeom=Each ODEGeom
		If (ode\geom = CollisionGeom2 )
			;DebugLog "ode name:"+ode\name$
		EndIf
	Next
	
	cx# = dGeom2CollisionX(RayGeom,i)
	cy# = dGeom2CollisionY(RayGeom,i)
	cz# = dGeom2CollisionZ(RayGeom,i)

	If (mousehit1)
		temp = CreateSphere()
		EntityColor temp, 200, 100, 200
		size# = .3
		ScaleEntity temp, size#, size#, size#
	;	EntityAlpha temp, .1
		PositionEntity temp, cx, cy, cz#
		
		c.ODEGeom = First ODEGeom
		EntityParent temp, c\mesh
		
		DebugLog "created thingy"
	EndIf

Next



If RayCollision>0 

	EntityColor Cylinder,0,200,100
	Else
	EntityColor Cylinder,200,0,100
	End If

;DebugLog RayCollision+" --- "+ dx+", "+dy+", "+dz

dGeomDestroy(RayGeom)

End Function

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

Function UpdateGeoms()

For ode.ODEGeom=Each ODEGeom
	PositionEntity ode\mesh,dGeomGetPositionX(ode\geom),dGeomGetPositionY(ode\geom),dGeomGetPositionZ(ode\geom)
	RotateEntity ode\mesh,dGeomGetPitch(ode\geom),dGeomGetYaw(ode\geom),dGeomGetRoll(ode\geom)
Next

End Function

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


Hmm, another tiny problem: is there a fast way to check the FIRST collidedGeom when you create a ray? (I realize I can loop everything, but it seems bit silly to first loop collided1 and collided2 and then compare distances to find out the first one)

This is so that I can shoot something... and the bullet will stop in the wall, and not also hit the guy behind the wall :)

Hmm, have you listed the collision geoms to see how they are indexed. Depending on the types of space used, they may already be indexed in a certain order. I'm sure they're indexed based on their size in hash spaces.

You can also try using dSpaceCollide2(geom1,geom2,world,group) to check collisions between two specific geoms (or spaces).

Ok, thanks. I suppose I'll just go through the index. Doesn't require much time anyway so I think it's fine.

One more newb question about rays:
- should I do call dSpaceCollide(Space,World,ContactGroup) every time I create a ray?
- or... can I simply first create X number of rays, and after those are created call the dSpaceCollide (and then after that - delete all rays)

You can create X number of rays and call dSpaceCollide() once to generate the collision information, then delete them.

That's what I thought :) Thanks again!

I've been working on "save/load" functionality, and currently I'm using the following code
First I'm disabling all geoms/bodies (looping every single 'ode' object):
	For n.netobject = Each netobject
		n\lastUpdateTime = 0
		If (n\physics <> Null)
			If (n\physics\geom)
				dGeomDisable(n\physics\geom)
			EndIf
			If (n\physics\body)
				dBodyDisable(n\physics\body)
			EndIf
		EndIf
	Next


After this, I position/rotate objects all objects:
	If (mover\physics\body)
		dBodySetAngularVel(mover\physics\body,0, 0, 0)
		dBodySetTorque (mover\physics\body,0, 0, 0)
		dBodySetPosition(mover\physics\body, x#, y#, z#)
               dBodySetRotation(physicsInstance\body, rotation_x#, rotation_y#, rotation_z# )	

	EndIf

And after positioning, I enable all objects:
	For n.netobject = Each netobject
		n\lastUpdateTime = 0
		If (n\physics <> Null)
			If (n\physics\geom)
				dGeomEnable(n\physics\geom)
			EndIf
			If (n\physics\body)
				dBodyEnable(n\physics\body)
			EndIf
		EndIf
	Next


This seems to work fine, and all the objects are snapped to the proper locations when user clicks load. If you move your character, and click 'load' everything goes to proper locations again.

There's just one tiny bug: if I've pushed a barrel object (for example), and click 'load' I can see that the barrel goes to the proper location & has the right rotation - but the barrel is still MOVING in this new snapped location. I suppose barrel is having some sort of force applied to it, and continues updating after getting snapped to the position.

Any ideas what I'm doing wrong... or how this should be done correctly?

You're missing these two functions in your position/rotation code...

dBodySetLinearVel(body,0,0,0)
dBodySetForce(body,0,0,0)


Let me know if that doesn't help.

Hi VIP3R, have got the front end varying the amount of cars in the world, along with objects and the concentration of capsules and spheres. I am going to invoke/ reinvoke an FPS counter. Can you please help with the following:- How can I superimpose a car's number onto the top and bottom of the cube - I am going to make 100/200 images (dependant on my max car count) with my numbers on then apply the numbered image within my car creation function using my loop count to the 'top' and the 'bottom' of the car.

In order to maintain a dead car count do this I want to perform a check on whether the 'top' of the car is touching the 'world' or not, then increment a dead car count - is there a more efficient way to do this, if not could you please show me an example of how to perform is top of cube touching world check - I will be setting a flag in a global array that will ensure once the check is confirmed the car will not be checked a second time.....

Regards, BP.

You need to look at texturing the cubes with the car numbers. Only 10 number images are needed (0-9), you can then create the textures with any number. These types of question are not physics related, you would be better off asking them in the Blitz3D Programming forum tbh.

Regarding the dead car count, it's easier to detect the 'Roll' angle of the car body to see if it's upside-down or not. Use a counter to make sure it has been upside-down for a few seconds then increase the dead car count. If you want to use collisions instead, look at the CarDemo-DetailedC demo to see how collision information is obtained.

Thanks VIP3R (;-), managed to create two meshes at this post:-

http://www.blitzbasic.com/Community/posts.php?topic=81131#914022

Now just gotta correlate it to somehow blending in two pngs.... I'm considering trying to see my car bodies in wireframe to help me apprecaite if there is the necessary meshes created along the lines of the following code:

ode\geom=dCreateBox(Space,3,1,4) ; I think this line intelligently makes all the quads to make a cube, whereas the assistance I'm receiving is along the lines of building a 'entity' from the most basic commands:-

Graphics3D 800, 600, 0, 2
SetBuffer BackBuffer()

;create new mesh(s)
mesh = CreateMesh()
mesh2 = CreateMesh()
;create surface(s)
surf = CreateSurface(mesh)
surf2 = CreateSurface(mesh2)

;create 4 vertices
v0 = AddVertex(surf,  1,  1, 0, 1.0, 1.0)
v1 = AddVertex(surf,  1, -1, 0, 1.0, 0.0)
v2 = AddVertex(surf, -1, -1, 0, 0.0, 0.0)
v3 = AddVertex(surf, -1,  1, 0, 0.0, 1.0)
;create another 4 vertices
v4 = AddVertex(surf2,  3,  1, 0, 1.0, 1.0)
v5 = AddVertex(surf2,  3, -1, 0, 1.0, 0.0)
v6 = AddVertex(surf2, 1, -1, 0, 0.0, 0.0)
v7 = AddVertex(surf2, 1,  1, 0, 0.0, 1.0)

;create 2 triangles
AddTriangle surf, v0, v1, v2
AddTriangle surf, v2, v3, v0
;create 2 more triangles
AddTriangle surf2, v4, v5, v6
AddTriangle surf2, v6, v7, v4

;create camera
cam = CreateCamera()
MoveEntity cam, 0, 0, -5

;main loop
Repeat

	;w = wireframe
	WireFrame KeyDown(17)
	RenderWorld
	
	Text 0, 0, "w = wireframe"
	Flip

;esc = exit	
Until KeyHit(1)

End



Somehow I need to maybe extract the information from createbox to pick out the individual sides of the entity.... I'm not sure how yet.

You're missing these two functions in your position/rotation code...

dBodySetLinearVel(body,0,0,0)
dBodySetForce(body,0,0,0)

Let me know if that doesn't help.

Excellent, seemed to do the trick!

JV-ODE V1.32 Update Released

Please check your inbox :)

JV-ODE is now compiled using ODE V0.10.1 which includes several additions, fixes and tweaks. You can view the ODE changelog for specific details here and here.

Important Notes:
JV-ODE V1.32 immediately follows V1.28, there were no versions released in between them. The version number has increased by 4 because there were 4 major changes made to JV-ODE for this update, two new ODE core updates (V0.10 and V0.10.1) and a wrapper update for each core. The ODE core V0.10 was broken, therefore the core was replaced with the new V0.10.1 bugfix release.

The ODE core has been compiled using the new TriMesh>TriMesh collider to give improved results.

As previously warned, you must initialize this version of ODE by calling dInitODE() before dWorldCreate(). It is now mandatory and failure to do so will result in an error.

The dGeomTriMeshDataBuildSimple() function is not as stable as it was in previous releases, causing faulty collision contacts to be generated. To avoid the problem, the JV-ODE TriMesh creation functions have been modified to use dGeomTriMeshDataBuildSingle() instead, which also has the added benefit of a smaller memory footprint. If you have built your own 'CreateTriMesh()' functions, it is highly recommended you change over to use dGeomTriMeshDataBuildSingle() too, you can use the built-in functions as a guide.

The new update includes built-in damping, 'sweep and prune' collision spaces, prismatic-universal & piston joints and multiple thread support (untested).

Added new functions:
dInitODE2(initflags)
dAllocateODEDataForThread%(allocateflags)
dCleanupODEAllDataForThread()
dWorldGetLinearDamping#(world)
dWorldGetAngularDamping#(world)
dWorldSetLinearDamping(world,scale#)
dWorldSetAngularDamping(world,scale#)
dWorldSetDamping(world,linear_scale#,angular_scale#)
dWorldGetLinearDampingThreshold#(world)
dWorldGetAngularDampingThreshold#(world)
dWorldSetLinearDampingThreshold(world,threshold#)
dWorldSetAngularDampingThreshold(world,threshold#)
dWorldGetMaxAngularSpeed#(world)
dWorldSetMaxAngularSpeed(world,max_speed#)
dSpaceSetSublevel(space,sublevel)
dSpaceGetSublevel%(space)
dSpaceGetClass%(space)
dSweepAndPruneSpaceCreate%(space,axisorder)
dBodyGetLinearDamping#(body)
dBodyGetAngularDamping#(body)
dBodySetLinearDamping(body,scale#)
dBodySetAngularDamping(body,scale#)
dBodySetDamping(body,linear_scale#,angular_scale#)
dBodyGetLinearDampingThreshold#(body)
dBodyGetAngularDampingThreshold#(body)
dBodySetLinearDampingThreshold(body,threshold#)
dBodySetAngularDampingThreshold(body,threshold#)
dBodySetDampingDefaults(body)
dBodyGetMaxAngularSpeed#(body)
dBodySetMaxAngularSpeed(body,max_speed#)
dBodyGetFirstGeom%(body)
dBodyGetNextGeom%(geom)
dJointSetHingeAxisOffset(joint,x#,y#,z#,angle#)
dJointGetNumBodies%(joint)
dJointCreatePU%(world,group)
dJointSetPUAnchor(joint,x#,y#,z#)
dJointSetPUAnchorDelta(joint,x#,y#,z#,dx#,dy#,dz#)
dJointSetPUAxis1(joint,x#,y#,z#)
dJointSetPUAxis2(joint,x#,y#,z#)
dJointSetPUAxis3(joint,x#,y#,z#)
dJointSetPUAxisP(joint,x#,y#,z#)
dJointSetPUParam(joint,parameter,value#)
dJointGetPUPosition#(joint)
dJointGetPUPositionRate#(joint)
dJointGetPUAnchor(joint)
dJointGetPUAxis1(joint)
dJointGetPUAxis2(joint)
dJointGetPUAxis3(joint)
dJointGetPUAxisP(joint)
dJointGetPUAngles(joint)
dJointGetPUAngle1#(joint)
dJointGetPUAngle2#(joint)
dJointGetPUAngle1Rate#(joint)
dJointGetPUAngle2Rate#(joint)
dJointGetPUParam#(joint,parameter)
dJointCreatePiston%(world,group)
dJointSetPistonAnchor(joint,x#,y#,z#)
dJointSetPistonAnchorOffset(joint,x#,y#,z#,dx#,dy#,dz#)
dJointSetPistonAxis(joint,x#,y#,z#)
dJointSetPistonParam(joint,parameter,value#)
dJointGetPistonAnchor(joint)
dJointGetPistonAnchor2(joint)
dJointGetPistonAxis(joint)
dJointGetPistonPosition#(joint)
dJointGetPistonPositionRate#(joint)
dJointGetPistonAngle#(joint)
dJointGetPistonAngleRate#(joint)
dJointAddPistonForce(joint,force#)
dJointGetPistonParam#(joint,parameter)


Please let me know if you experience any problems with the new update.

:)

Nice, thanks for the info!

I was just wondering, how can you staticly link the ODE engine to your DLL, and then sell the product? Isn't that in conflict with the GPL license?

no. ode doesnt use gpl...

@Game Producer: No problem ;)

JV-ODE uses the ODE BSD license, not the LGPL license.

Am I doing something obviously wrong here, I can't seem to create a box the same size as my mesh as far as the physics world is concerned, is it a problem the 'width' of my mesh is zero upon loading ?


xstart=16
ystart=5
zstart=1

xsz = 5
hsz = 4
dsz = 5

For bricks=1 To 20

	ode.ODEGeom=New ODEGeom
	ode\body=dBodyCreate(World)
	dBodySetRotation(ode\body,0,0,0)
	dBodySetPosition(ode\body,(bricks*xstart),ystart,zstart)
	
	Smass=dMassCreate()
	dMassSetBoxTotal(Smass,CapsuleMass,xsz,hsz,dsz) ; not sure hat s direction of 1 means
	dBodySetMass(ode\body,Smass)
	dMassDestroy(Smass)
	
	ode\geom=dCreateBox(Space,2*xsz,2*hsz,2*dsz)  ;  Box has to be twice size of mesh ??	

	dGeomSetBody(ode\geom,ode\body)

	ode\mesh=LoadMesh("8_pt_for_u3d_spike.b3d")
		
	deep=MeshDepth(ode\mesh)   ; upon load the depth of my mesh is 2
	tall=MeshHeight(ode\mesh)  ; upon load the height of my mesh is 1
	width=MeshWidth(ode\mesh)  ; upon load the width of my mesh is 0?

	FitMesh ode\mesh,width,tall,deep,xsz,hsz,dsz,0
	ScaleMesh ode\mesh,0.5,0.5,0.5
	RotateMesh ode\mesh,0,0,0

	EntityColor ode\mesh,Rnd(255),Rnd(255),Rnd(255)
	EntityAlpha ode\mesh,1
	EntityShininess ode\mesh,0.7

Next



This is probably a little stupid but I read on the news page JV-Ode has a new version.

I recently bought it but I cannot find a update link or something. To get it up-to-date again, do I need to buy it again?


Thanks!

@Blitzplotter: The first three parameters of FitMesh() are positions not dimensions. You don't need to use it anyway though, use ScaleMesh() only instead. If the width equals zero then yes it will cause a problem. You will need to return floats with MeshWidth() etc, not integers. If the width is less than 1.0 then it will return an integer of zero. Return floats instead like this...
deep#=MeshDepth(ode\mesh)
tall#=MeshHeight(ode\mesh)
width#=MeshWidth(ode\mesh)

ScaleMesh ode\mesh,width*0.5,tall*0.5,deep*0.5

@Sph!nx: No, each update is free. I send out emails to all users with the new download link to the email address they registered when purchasing JV-ODE.

If you haven't received the update email and are still using the registered email address, double check it hasn't been filtered as spam.

If your registered email address is no longer used and gives errors when sending emails, it will be removed from the updates list after two failures in succession.

If you need to update your registered email address or are still unable to find the update email, send me an email with details of your original purchase and I will update it and send a new download link for you.

Thanks for the clarification VIP3R. I am returning floats now instead of ints, should stop my lego bricks wobbling on the 0 width!

That is a great help, once I resolve this I'll be trying out 1.32 cheers!

Thanks VIP3R!

I found this e-mail in your profile: ......., I assume it is ......, just checking, cause I intend to send you my initial purchase e-mail so its kinda confidential and I don't want it to end up somewhere else...


Edit :

Removed email by request. Thanks again VIP3R!

Yep, that's correct.

Ok, I will foreward the e-mail I recieved when purchasing your library. Only proof I have I guess.


Edit : Send the e-mail! :)

Ah, you didn't receive an update email because you already have the latest version (V1.32) which was released a few days before your purchase.

You will receive an email notifying you when future updates become available.

Oops ... Sorry, I should have checked...


Thanks anyway!

You're welcome and thanks for the edit.

VIP3R,

I know Ive asked you about this before, but I can't seem to find my notes so apologies if Im covering old ground.

Essentially i have been working on a new vehicle based game and have become confused with the ODE / JV-ODE friction settings and i want to get a proper handle on how JV-ODE works, as i think i've misunderstood previously.

Ideally i want to create a friction model for a wheel that when loaded sideways i.e. when cornering, loses grip progressively and slowly, rather than a sudden 'got grip now / no grip now' type of curve.



Part 1. Out of the box (See case one on diagram)

If i have understood the ode manual correctly (!)......

-When a wheel creates a contact joint with the floor the contact normal is perpendicular to the surface.

-The FDir1 and FDir2 vectors are calculated as being perpendicular to the contact normal and to each other.

-Since the FDir1 direction has not been specified, the vector can be at any rotation to the contact normal, as long as it is perpendicular to it.

In laymans terms (i.e. my simpletons approach!) this means that FDir1 can face in any direction, and will alomost certainly not align itself with the direction the wheel is pointing. This means that the wheels behaviour when it comes to gentle progressive sideways sliding is impossible to set-up (using slip1 / slip2 and mu and mu2, etc).

Hopefully i'm right so far ....



Part 2. Setting FDir1 and why i am confused (See case two on diagram)

If i have read the ODE manual correctly (a big 'if') you can set the FDir1 direction and so align it to the direction the wheel is facing.

The FDir1 vector is still perpendicular to the contact normal with the ground, but now it is rotated to suit our purposes.

This means you can set mu and mu2 and slip1 and slip2 to give the required tyre characteristics on different surfaces and at different speeds because ODE knows which way the wheel is facing.

In theory this should enable you to create a wheel that progressivly loses grip sideways as its rotational speed increases.


This is where i get confused - in the JV-ODE car demo the FDir1 direction is set, at the start, but then remains unaltered in the main program loop.
Shouldn't this direction be updated each loop to reflect the wheels orientation or am i missing something ?

I have tried to do this myself, by respecifying the FDir1 direction as the car / wheel moves during the game, but this doesn't seem to have any effect.

Also, the slip1 and slip2 values are supposed (according to the ODE manual) to be varied depending on the wheels speed, but when i set these values in my program only the first values i pass to ODE are used, any subsequent values i pass seem to be ignored.

Many thanks for taking the time to read this :- when you get a moment let me know what you think.

kind regards

Mark Judd

You've got the concept correct ;)

The misunderstanding is probably thanks to the FDir1 demo, it's no longer included with JV-ODE for this reason (after our previous discussions on the subject). In the demo, the friction direction was manually adjusted in order to experiment with the effects of FDir1, but the main purpose of the demo was to show how to setup FDir1 in code. I realised it was too misleading and decided to scrap it a while ago.

So, everything you've posted is correct, you do need to adjust the friction direction to align with the wheels for it to work like real tyres.

To adjust these values in real time, they must be applied with the Geom contact functions only... dGeomContactSetMode(geom,mode)... dGeomContactSetFDir1(geom,fdir1x#,fdir1y#,fdir1z#) etc

Same applies to the slip values.

Using the geom functions should resolve those issues, let me know if it still isn't working correctly.

The most important part of the ODE docs regarding this problem is this bit...

To model this in ODE set the tire-road contact parameters as follows: set friction direction 1 in the direction that the tire is rolling in, and set the FDS slip coefficient in friction direction 2 to k*v, where v is the tire rolling velocity and k is a tire parameter that you can chose based on experimentation.


Nice pics btw :)

VIP3R,

Ahhh - I see where I've been going wrong.
Thanks very much. I'll give this a go and let you know how it turns out.

Incidentally the publisher I sold my Tricky Tracks game to decided for some reason to not market it (at least not yet) so Im looking at a newer version which is what this is for.

Thanks again.

Mark

EDIT : Bah! - I thought I had it but its not working - I seem to be really struggling. Any chance of a quick demo VIP3R ?

Hi VIP3R,

OK Ive spent some time messing with Fdir and have come to a dead end.
The following code is the segment of my program (from inside the main loop just before 'updategeoms') which calculates the direction of each wheel and applies the geom parameters to define Fdir1.

(Ive used the common variables from any of the JV-ODE car demos).

; loop through all four wheels of car
For count=1 To 4
; use the direction of the car body to create a vector (to set friction direction)
; get angle of car body
car_angle#=dGeomGetYaw(CGeom)
; factor in the angle between the wheel and the car body so the steering wheels are catered for
wheel_angle#=dJointGetHinge2Angle1(joint(count))*57.4 ; (57.4 = radians to degrees)
x_component#=Sin(car_angle#+wheel_angle#)*-1.0 
y_component#=0.0
z_component#=Sin(car_angle#+wheel_angle#+90.0)
; set geoms contact parameters
dGeomContactSetMode(WGeom(count),dContactFDir1+dContactSlip1)
; friction in direction wheel is rolling
dGeomContactSetMu(WGeom(count),20.0)
; friction in perpendicular direction to roll
dGeomContactSetMu2(WGeom(count),30.0)
; set friction direction
; Note (!) putting parameters in order i.e. x,y,z gives very strange result - trial and error shows y,x,z as better but not perfect (?)
dGeomContactSetFDir1(WGeom(count),y_component#,x_component#,z_component#)
; slip value for direction of roll
dGeomContactSetSlip1(WGeom(count),0.005)
; get rotational speed of wheel
spin#=dJointGetHinge2Angle2Rate(joint(count))
; slip value for second direction (factored by rotational speed i.e. k*v)
dGeomContactSetSlip2(WGeom(count),0.005+(Abs(spin#)/100))
Next


Problem is it doesnt seem to work. Try setting mu2 to a silly low value (i.e. no sideways grip) and see what happens. Its like the Fdir1 direction is not being set each loop.

I think I understand the principle of what i need to do - its just how I achieve it in the code thats stumping me.

Hopefully I'm missing something really simple (not for the first time!)

Let me know what you think friend - as always - really appreciate your time.

cheers,

Mark

Hmm, I noticed a few problems.

If you examine the x/y/z components during runtime you will see that they don't reflect the angle of the wheels globally, therefore the friction direction will be wrong most of the time. If you drive in circles, what you should see is the x and z components rise and fall depending on the global angle of the wheel.

I've created a quick demo using your code snippet with the following changes...
* Added World Contact / Mu2 / Slip settings (in addition to the geom contact settings)
* Removed the car angle code (not needed)
* Changed the wheel angle to use the yaw value (the hinge2 angle is local and it needs to be global)
* The friction values are exaggerated for testing, I think Mu and Mu2 are mixed up though, this might be because the yaw is perpendicular to the wheel.

I haven't adjusted the slip settings so they might be interfering with the friction (hence the 20000 value).

It seems to be working correctly, but needs much more tweaking and testing with those friction / slip values.

Anyway, here it is...
; ###################################################################################################
; #                                        JV-ODE Car Demo                                          #
; #                                  Code by Jim Williams (VIP3R)                                   #
; #                              Devious Codeworks - Copyright © 2008                               #
; ###################################################################################################

Include "JV-ODE.bb"

AppTitle "JV-ODE Car Demo"

Graphics3D 800,600,0,2

Global CMass#=200.0				; ### Car Mass
Global WMass#=14.0				; ### Wheel Mass

Global WorldERP#=1.0			; ### World Error Correction
Global WorldFriction#=70.0		; ### World Friction

Global Torque#=24.0				; ### Joint Torque
Global SuspensionHS#=0.01		; ### Suspension Hardness/Softness (Higher=Softer - Lower=Harder)

Global Force#=0.0
Global Steer#=0.0

Global Car
Global CGeom
Global CMesh

Global CarStartY=20

Global x_component#=0.0	; <<<< Here
Global y_component#=0.0	; <<<< Here
Global z_component#=0.0	; <<<< Here

Dim Wheel(4)
Dim WGeom(4)
Dim Joint(4)

Type ODEGeom
	Field body
	Field geom
	Field mesh
End Type

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

; ### Setup ODE

dInitODE()

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

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

dContactSetMode(dContactFDir1+dContactSlip1)	; <<<< Here
dContactSetMu(WorldFriction)
dContactSetMu2(1.0)	; <<<< Here
dContactSetFDir1(1.0,1.0,1.0)	; <<<< Here
dContactSetSlip1(0.005)	; <<<< Here
dContactSetSlip2(0.005)	; <<<< Here

; ### Create Car Body

ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
Car=ode\body
dBodySetPosition(ode\body,0,CarStartY,0)
dBodySetRotation(ode\body,0,0,0)
mass=dMassCreate()
dMassSetBoxTotal(mass,CMass,3,1,4)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateBox(Space,3,1,4)
CGeom=ode\geom
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
CMesh=ode\mesh
ScaleMesh ode\mesh,1.5,0.5,2
EntityColor ode\mesh,40,80,255

; ### Create Wheels

For count=1 To 4
	ode.ODEGeom=New ODEGeom
	ode\body=dBodyCreate(World)
	Wheel(count)=ode\body
	dBodySetPosition(ode\body,0,0,0)
	dBodySetRotation(ode\body,0,0,90)
	mass=dMassCreate()
	dMassSetSphereTotal(mass,WMass,0.7)
	dBodySetMass(ode\body,mass)
	dMassDestroy(mass)
	ode\geom=dCreateSphere(Space,0.7)
	WGeom(count)=ode\geom
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateCylinder()
	ScaleMesh ode\mesh,0.7,0.25,0.7
	EntityColor ode\mesh,255,255,255
Next

dBodySetPosition(Wheel(1),-2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(2),+2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(3),-2,CarStartY-0.5,-2)
dBodySetPosition(Wheel(4),+2,CarStartY-0.5,-2)

; ### Create Objects

SeedRnd MilliSecs()

For spheres=1 To 20
	ode.ODEGeom=New ODEGeom
	ode\body=dBodyCreate(World)
	dBodySetPosition(ode\body,Rand(-100,100),30,Rand(-100,100))
	dBodySetRotation(ode\body,0,0,0)
	ode\geom=dCreateSphere(Space,4)
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateSphere()
	ScaleMesh ode\mesh,4,4,4
	EntityColor ode\mesh,Rand(0,255),Rand(0,255),Rand(0,255)
	EntityShininess ode\mesh,0.7
Next

For capsules=1 To 20
	ode.ODEGeom=New ODEGeom
	ode\body=dBodyCreate(World)
	dBodySetPosition(ode\body,Rand(-100,100),30,Rand(-100,100))
	dBodySetRotation(ode\body,90,0,0)
	ode\geom=dCreateCapsule(Space,1,8)
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateCylinder()
	ScaleMesh ode\mesh,1,5,1
	RotateMesh ode\mesh,90,0,0	; ### Align Blitz3D Cylinder To ODE Capsule
	EntityColor ode\mesh,Rand(0,255),Rand(0,255),Rand(0,255)
	EntityShininess ode\mesh,0.7
Next

; ### Create Light

Global Light=CreateLight()
RotateEntity Light,50,-50,0
LightColor Light,255,255,255
AmbientLight 130,130,130

; ### Create Camera

Global CameraPivot=CreatePivot()

Global Camera=CreateCamera(CameraPivot)
CameraClsColor Camera,0,0,0
CameraRange Camera,1,1000

; ### Create Plane

dCreatePlane(Space,0,1,0,0)

Global Plane=CreatePlane()
EntityAlpha Plane,0.8

EntityTexture Plane,PlaneTexture()

CreateMirror()

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

; ### Blitz3D Static Object (White)

Global Blitz3DObject=CreateCube()
ScaleMesh Blitz3DObject,1,4,20
PositionEntity Blitz3DObject,10,5,40
RotateEntity Blitz3DObject,-10,8,4
EntityColor Blitz3DObject,255,255,255

; ### ODE Static Object (Blue)

ode.ODEGeom=New ODEGeom
ode\geom=dCreateBox(Space,2,8,40)
dGeomSetPosition(ode\geom,20,5,40)
dGeomSetRotation(ode\geom,-10,8,4)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,1,4,20
EntityColor ode\mesh,0,100,200

; ### ODE Static Object (Red)

ode.ODEGeom=New ODEGeom
ode\geom=dCreateBox(Space,18,0.2,40)
dGeomSetPosition(ode\geom,-20,4.9,40)
dGeomSetRotation(ode\geom,-14,0,0)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,9,0.1,20
EntityColor ode\mesh,200,0,100

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

SetupCar()

While Not KeyHit(1)

	UpdateKeys()

	UpdateCar()

	UpdateGeoms()

	PTime=MilliSecs()

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

	PhysicsTime#=MilliSecs()-PTime

	UpdateCam()

	RenderWorld

	Text 0,0,"JV-ODE Version "+dGetVersion()
	Text 0,15,"Physics Time:"+PhysicsTime
	Text 0,50,"Force:"+Force
	Text 0,65,"Torque:"+Torque
	Text 640,0,"A - Accelerate"
	Text 640,15,"Z - Brake/Reverse"
	Text 640,30,"Arrows - Steering"
	Text 640,45,"Space - Reset Car"

	Text 0,100,"X:"+x_component#
	Text 0,120,"Y:"+y_component#
	Text 0,140,"Z:"+z_component#

	Flip 1

Wend

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

End

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

Function SetupCar()

For count=1 To 4
	Joint(count)=dJointCreateHinge2(World,0)
	dJointAttach(Joint(count),Car,Wheel(count))
	dJointSetHinge2Anchor(Joint(count),dBodyGetPositionX(Wheel(count)),dBodyGetPositionY(Wheel(count)),dBodyGetPositionZ(Wheel(count)))
	dJointSetHinge2Axis1(Joint(count),0,1,0)
	dJointSetHinge2Axis2(Joint(count),-1,0,0)
	dJointSetHinge2Param(Joint(count),dParamSuspensionERP,0.8)
	dJointSetHinge2Param(Joint(count),dParamSuspensionCFM,SuspensionHS)
	If count>2
		dJointSetHinge2Param(Joint(count),dParamLoStop,0)
		dJointSetHinge2Param(Joint(count),dParamHiStop,0)
		End If

	dGeomContactSetMode(WGeom(count),dContactFDir1+dContactSlip1)	; <<<< Here
Next

End Function

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

Function UpdateKeys()

If KeyDown(30)=1
	Force=Force+0.08
	If Force>30 Then Force=30
	End If

If KeyDown(44)=1
	Force=Force-0.1
	If Force<-10 Then Force=-10
	If Force>0 Then Force=Force*0.97
	End If

If KeyDown(30)=0 And KeyDown(44)=0 Then Force=Force*0.99

If KeyDown(203)=1 Or KeyDown(205)=1
	If KeyDown(203)=1
		Steer=0.5
		Else
		Steer=-0.5
		End If
	Else
	Steer=0.0
	End If

If KeyHit(57)=1
	Force=0.0
	dBodySetRotation(Car,dGeomGetPitch(CGeom),dGeomGetYaw(CGeom),0)
	End If

End Function

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

Function UpdateCar()

For count=1 To 4
	dBodyEnable(Wheel(count))
Next

dBodyEnable(Car)

For count=1 To 4
	dJointSetHinge2Param(Joint(count),dParamVel2,Force)
	dJointSetHinge2Param(Joint(count),dParamFMax2,Torque)
Next

For count=1 To 2
	angle#=Steer-dJointGetHinge2Angle1(Joint(count))
	dJointSetHinge2Param(Joint(count),dParamVel,angle)
	dJointSetHinge2Param(Joint(count),dParamFMax,400)
Next

; Here >>>>
For count=1 To 4
	wheel_angle#=dGeomGetYaw(WGeom(count))
	x_component#=Sin(wheel_angle#)*-1.0 
	y_component#=0.0
	z_component#=Sin(wheel_angle#+90.0)

	dGeomContactSetMu(WGeom(count),30)
	dGeomContactSetMu2(WGeom(count),20000)

	dGeomContactSetFDir1(WGeom(count),x_component#,y_component#,z_component#)

	dGeomContactSetSlip1(WGeom(count),0.005)

	spin#=dJointGetHinge2Angle2Rate(joint(count))
	dGeomContactSetSlip2(WGeom(count),0.005+(Abs(spin#)/100))
Next
; <<<< Here

End Function

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

Function UpdateCam()

PositionEntity Camera,0,3,-12

PivotX#=Cos(EntityYaw(CMesh)-90)+EntityX(CMesh)
PivotY#=EntityY(CMesh)
PivotZ#=Sin(EntityYaw(CMesh)-90)+EntityZ(CMesh)

PositionEntity CameraPivot,PivotX,PivotY,PivotZ

PointEntity CameraPivot,CMesh

End Function

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

Function UpdateGeoms()

For ode.ODEGeom=Each ODEGeom
	PositionEntity ode\mesh,dGeomGetPositionX(ode\geom),dGeomGetPositionY(ode\geom),dGeomGetPositionZ(ode\geom)
	RotateEntity ode\mesh,dGeomGetPitch(ode\geom),dGeomGetYaw(ode\geom),dGeomGetRoll(ode\geom)
Next

End Function

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


I've marked the new areas of code with the tag '<<<< Here'.

Hope this helps, let me know if you need anymore info ;)

VIP3R,

You've done it again !

Thats great, thanks for your help.
Works really nicely now - just fine tuning the values to give the feel I'm after.
I had really become confused with the global / local angles issue and despite starting from scratch a couple of times seemed to wind up in the same place each time.

Once again, many thanks for your excellent support.

Mark

Hi,
i got a error message ("colliders array not initalized (..\ode\src\collision_kernel.cpp:256")- JV-ODE ERROR 2 - with this source-code. Can somebody confirm this or can help to fix it ? Maybe it is a problem with the JV-ODE 1.32 -Blitzmax-Edition ?

Thanks in Advance
Jens

Blitz3DSDK_V102
Blitzmax 1.30
JV-ODE 1.32


' #############################################################################
' #                            JV-ODE - Cubes Demo                            #
' #                        Code by Jim Williams (VIP3R)                       #
' #                    Devious Codeworks - Copyright © 2007                   #
' #############################################################################

SuperStrict

Framework BRL.GLMax2D ' only needed for "AppTerminate()"
Import BRL.Random
Import DevCode.JVODE
Import blitz3d.blitz3dsdk

AppTitle:String="JV-ODE - Cubes Demo"

bbBeginBlitz3D()
bbGraphics3D 800,600,0,2

Type ODEGeom
	Field body:Int
	Field geom:Int
	Field mesh:Int
	Field rgb:Int[]
	Field scale:Float[]
End Type

Global ODEGeomList:TList=CreateList()

' #############################################################################

' ### Setup ODE

Global World:Int=dWorldCreate()
Global Space:Int=dHashSpaceCreate(0)
Global ContactGroup:Int=dJointGroupCreate(0)

dWorldSetAutoDisableFlag(World,1)
dWorldSetGravity(World,0,-0.98,0)
dContactSetMode(dContactBounce)
dContactSetBounce(0.1)
dContactSetMu(48)

' ### Create light

Global Light:Int = bbCreateLight()

bbRotateEntity Light,45,-90,0
bbLightColor Light,255,255,255
bbAmbientLight 130,130,130

' ### Create camera

Global Camera:Int = bbCreateCamera()
bbCameraClsColor Camera,0,0,0
bbCameraRange Camera,1,1000
bbPositionEntity Camera,0,20,-50
bbRotateEntity Camera,30,0,0

' ### Create plane

dCreatePlane(Space,0,1,0,0)

Local plane:Int = bbCreatePlane()

bbEntityAlpha Plane,0.8

Local PlaneTexture:Int = bbCreateTexture(128,128,9)

bbClsColor 0,200,80
bbCls

bbColor 255,255,255

bbRect 0,0,64,64,1
bbRect 64,64,64,64,1

bbCopyRect 0,0,128,128,0,0,bbBackBuffer(),bbTextureBuffer(PlaneTexture)
bbScaleTexture PlaneTexture,20,20
bbEntityTexture Plane,PlaneTexture,0,0

Local Mirror:Int = bbCreateMirror()

' #############################################################################

Local PTime:Int
Local Timer:Int
Local PhysicsTime:Float

While Not AppTerminate() And Not bbKeyDown(1)

	If MilliSecs()-Timer>700
		AddObject()
		Timer=MilliSecs()
	End If

	UpdateGeoms()

	PTime=MilliSecs()

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

	PhysicsTime=MilliSecs()-PTime

	bbRenderWorld

	bbText 0,0,"JV-ODE Version "+dGetVersion()
	bbText 0,15,"Physics Time:"+PhysicsTime

	bbFlip 

Wend

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

End

' #############################################################################

Function AddObject()

Local xp:Float
Local zp:Float
Local ode:ODEGeom

xp=Rand(-10,10)
zp=Rand(-10,10)

ode:ODEGeom=New ODEGeom
ode.body=dBodyCreate(World)
dBodySetAxisAngle(ode.body,0,0,0,0)
dBodySetPosition(ode.body,xp,30,zp)
dBodySetAutoDisableFlag(ode.body,1)
ode.geom=dCreateBox(Space,5,5,5)
dGeomSetBody(ode.geom,ode.body)
ode.mesh=bbCreateCube()
bbScaleMesh ode.mesh,2.5,2.5,2.5
bbEntityColor ode.mesh,Rand(0,255),Rand(0,255),Rand(0,255)
ListAddLast(ODEGeomList,ode:ODEGeom)

End Function

' #############################################################################

Function UpdateGeoms()

Local ode:ODEGeom

' ### Update Geoms
For ode:ODEGeom=EachIn ODEGeomList

	If dBodyIsEnabled(ode.body)
		bbPositionEntity ode.mesh,dGeomGetPositionX(ode.geom),dGeomGetPositionY(ode.geom),dGeomGetPositionZ(ode.geom)
		bbRotateEntity ode.mesh,dGeomGetPitch#(ode.geom),dGeomGetYaw#(ode.geom),dGeomGetRoll#(ode.geom)
	EndIf

Next

End Function

' #############################################################################




Add the following line after '### Setup ODE'...

' ### Setup ODE

dInitODE()

ODE must be initialized in JV-ODE V1.32

Thank you very much VIP3R !

Sometimes I am a tiny idiot - if i'd thought about it, i could have managed myself. ;-)

EDIT: Doesnt matter, I've sussed it, while not using JV-ODE! :)

Cheers

Dabz

Can I use JV-ODE for water/sea physics? Like waves effecting boats and items float on the surface, stuff like that? If so I'll but it now. Thanks.

Sadly not, ODE only simulates rigid body physics. You need a soft body physics engine for 'proper' flowing water.

It's possible to do simple water stuff with ODE though, like icebergs etc.

Thanks for the quick reply VIP3R

How would I do that in ODE? Can you code a little example for me? I mean the icebergs.

You create a body of water using a cuboid, then give the body certain collision properties. When you drop other solid objects (like an iceberg body) onto the water cube, they will behave as if they are floating on a fluid. You can also adjust the height of the water in real-time, but it will always remain flat (no waves). The water cube can be placed at an angle to simulate flowing water though. It's really easy to do.

Wave simulation might be possible with some intensive math, but that's where things get complicated and eventually would go beyond the limits of a rigid body engine like ODE.

The full version of JV-ODE has water and iceberg demos, but they won't run in the demo version.

I'm having a bit of trouble repositioning and rotating a rigid body AFTER it has been made.

I'd rather 'recycle' Bodies, Geoms & Meshes , instead of destroying them.

The general idea is that the distance of all 25 cars is calculated.
This list is sorted. If a car is outside the maximum distance, it gets
repositioned.

Every road in the game has a number of waypoints.
Each waypoint has a number, and points towards his next Waypoint.
This generates the YAW of that Waypoint. This YAW is used to rotate the rigid body..... Only it doesn't work. :/

I've tried dbodysetrotation , dbodysetaxisangle . I even tried disabling bodies before positioning and rotating, but that didn't work either.

This is the code so far:


; ###################################################################################################
; #                                        JV-ODE Car Demo                                          #
; #                                  Code by Jim Williams (VIP3R)                                   #
; #                              Devious Codeworks - Copyright © 2008                               #
; ###################################################################################################

Include "JV-ODE.bb"

AppTitle "JV-ODE Car Demo"

Graphics3D 800,600,0,2

HidePointer 

Global CMass#=200.0				; ### Car Mass
Global WMass#=14.0				; ### Wheel Mass

Global WorldERP#=1.0			; ### World Error Correction
Global WorldFriction#=70.0		; ### World Friction

Global Torque#=24.0				; ### Joint Torque
Global SuspensionHS#=0.01		; ### Suspension Hardness/Softness (Higher=Softer - Lower=Harder)

Global Force#=0.0
Global Steer#=0.0

Global Car
Global CGeom
Global CMesh

Global CarStartY=10
Global TotalWP					; total no. of waypoints
Global Next_Waypoint			; car travels to this waypoint		
Global Dummy					; The Dummy Car 
Global cam_x#,cam_z#,cam_pitch#,cam_yaw#						
Global dest_cam_x#,dest_cam_z#,dest_cam_pitch#,dest_cam_yaw#	
 
Global 		CUBE = CreateCube()
ScaleMesh 	CUBE , 1.6 , 0.1 , 1.6
EntityColor CUBE , 255 , 0 , 0
HideEntity 	CUBE

Dim Wheel(4)
Dim WGeom(4)
Dim Joint(4)

Type ODEGeom
	Field body
	Field geom
	Field mesh
End Type

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

; ### Setup ODE

dInitODE()

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

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

dContactSetMode(dContactSlip1)
dContactSetMu(WorldFriction)

; ### Create Car Body

ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
Car=ode\body
dBodySetPosition(ode\body,0,CarStartY,0)
dBodySetRotation(ode\body,0,0,0)
mass=dMassCreate()
dMassSetBoxTotal(mass,CMass,3,1,4)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateBox(Space,3,1,4)
CGeom=ode\geom
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
CMesh=ode\mesh
ScaleMesh ode\mesh,1.5,0.5,2
EntityColor ode\mesh,40,80,255

; ### Attach Compass to Car
Global 		 CarCompass = CreateCone()
RotateMesh   CarCompass , 90 , 0 , 0 
ScaleMesh    CarCompass , 1,0.1,1
EntityColor  CarCompass , 200,10,10
EntityParent CarCompass , Cmesh
x# = EntityX#( Cmesh , 1 )
y# = EntityY#( Cmesh , 1 )
z# = EntityZ#( Cmesh , 1 )
PositionEntity CarCompass , x# , y#+1 , z# , 1

; ### Create Wheels

For count=1 To 4
	ode.ODEGeom=New ODEGeom
	ode\body=dBodyCreate(World)
	Wheel(count)=ode\body
	dBodySetPosition(ode\body,0,0,0)
	dBodySetRotation(ode\body,0,0,90)
	mass=dMassCreate()
	dMassSetSphereTotal(mass,WMass,0.7)
	dBodySetMass(ode\body,mass)
	dMassDestroy(mass)
	ode\geom=dCreateSphere(Space,0.7)
	WGeom(count)=ode\geom
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateCylinder()
	ScaleMesh ode\mesh,0.7,0.25,0.7
	EntityColor ode\mesh,255,255,255
Next

dBodySetPosition(Wheel(1),-2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(2),+2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(3),-2,CarStartY-0.5,-2)
dBodySetPosition(Wheel(4),+2,CarStartY-0.5,-2)

; ### Create Light

Global 			Light = CreateLight()
RotateEntity 	Light ,  50 ,-50  , 0
LightColor 		Light , 255 , 255 , 255
AmbientLight    130 , 130 , 130

; ### Create Camera

Global CameraPivot=CreatePivot()

Global 			Camera=CreateCamera();CameraPivot)
CameraClsColor  Camera , 0 , 0 , 0
CameraRange 	Camera , 1 , 1000

; ### Create Plane

dCreatePlane    (Space,0,1,0,0)
Global 			Plane = CreatePlane()
EntityAlpha 	Plane , 1
EntityTexture   Plane,PlaneTexture()

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

SetupCar()
Make_DummyCar()
Load_Waypoints()
MoveMouse GraphicsWidth()/2,GraphicsHeight()/2

PositionEntity CameraPivot , 0 , 8 , -10 

While Not KeyHit(1)

	UpdateCar()

	UpdateGeoms()

	PTime=MilliSecs()

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

	PhysicsTime#=MilliSecs()-PTime

	UpdateWorld 
	RenderWorld

	ExampleCODE()
	CAR_AI()

	Color 100,100,255

	Text   0 ,  0 , "JV-ODE Version "+ dGetVersion()
	Text   0 , 15 , "Physics Time.. " + PhysicsTime
	Text   0 , 50 , "Force......... " + Force
	Text   0 , 65 , "Torque........ " + Torque
	Text 240 ,  0 , "Point Mouse at Waypoint"
	Text 240 , 15 , "Click [LMB] to rotate DummyCar at Waypoint's YAW"
	Text 240 , 30 , "Move Camera with [W] & [S] ,or Cursor[UP] & [DOWN]"
	Text 240 , 45 , "Press [SPACE] to reset car" 

	Color 255,255,255
	
	Flip 1

Wend

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

End

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

Function SetupCar()

For count=1 To 4
	Joint(count)=dJointCreateHinge2(World,0)
	dJointAttach(Joint(count),Car,Wheel(count))
	dJointSetHinge2Anchor(Joint(count),dBodyGetPositionX(Wheel(count)),dBodyGetPositionY(Wheel(count)),dBodyGetPositionZ(Wheel(count)))
	dJointSetHinge2Axis1(Joint(count),0,1,0)
	dJointSetHinge2Axis2(Joint(count),-1,0,0)
	dJointSetHinge2Param(Joint(count),dParamSuspensionERP,0.8)
	dJointSetHinge2Param(Joint(count),dParamSuspensionCFM,SuspensionHS)
	If count>2
		dJointSetHinge2Param(Joint(count),dParamLoStop,0)
		dJointSetHinge2Param(Joint(count),dParamHiStop,0)
		End If
Next

End Function

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

Function UpdateCar()

For count=1 To 4
	dBodyEnable(Wheel(count))
Next

dBodyEnable(Car)

For count=1 To 4
	dJointSetHinge2Param(Joint(count),dParamVel2,Force)
	dJointSetHinge2Param(Joint(count),dParamFMax2,Torque)
Next

For count=1 To 2
	angle#=Steer-dJointGetHinge2Angle1(Joint(count))
	dJointSetHinge2Param(Joint(count),dParamVel,angle)
	dJointSetHinge2Param(Joint(count),dParamFMax,400)
Next

End Function

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

Function UpdateGeoms()

For ode.ODEGeom=Each ODEGeom
	PositionEntity ode\mesh,dGeomGetPositionX(ode\geom),dGeomGetPositionY(ode\geom),dGeomGetPositionZ(ode\geom)
	RotateEntity ode\mesh,dGeomGetPitch(ode\geom),dGeomGetYaw(ode\geom),dGeomGetRoll(ode\geom)
Next

End Function

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

Type Waypoint
	Field X,Y,Z
	Field Pivot
	Field Number
	Field Next_WP_Num
	Field Rotate_To_Next_WP
End Type

Function ExampleCODE()

; Mouse look

	PositionEntity Camera , EntityX#(camerapivot),EntityY#(camerapivot),EntityZ#(camerapivot)

	mxs=MouseXSpeed()
	mys=MouseYSpeed()
	dest_cam_yaw#=dest_cam_yaw#-mxs
	dest_cam_pitch#=dest_cam_pitch#+mys
	cam_yaw=cam_yaw+((dest_cam_yaw-cam_yaw)/5)
	cam_pitch=cam_pitch+((dest_cam_pitch-cam_pitch)/5)
	
	RotateEntity camera,cam_pitch#,cam_yaw#,0
	
	MoveMouse GraphicsWidth()/2,GraphicsHeight()/2

; Camera move
	
	If KeyDown(200) Or KeyDown(17)  Then dest_cam_z=1
	If KeyDown(208) Or KeyDown(31)  Then dest_cam_z#=-1

	cam_z=cam_z+((dest_cam_z-cam_z)/5)
	cam_x=cam_x+((dest_cam_x-cam_x)/5)

	RotateEntity camerapivot , 0 , EntityYaw#( Camera ,1) , 0 ,1
	MoveEntity camerapivot,cam_x,0,cam_z
	dest_cam_x=0 : dest_cam_z=0

	MX = MouseX()
	MY = MouseY()

; Draw Cursor
	
	Color 32,32,32
	For tx=-1 To 1
		For ty=-1 To 1
			Line mx+tx,my+ty,mx+6+tx,my+6+ty
			Line mx+tx,my+ty,mx+tx,my+8+ty
		Next
	Next
	Color 255,255,255
	Line mx,my,mx+6,my+6
	Line mx,my,mx,my+8

	CameraPick Camera,MX,MY

	W1.Waypoint = Null
	
	If Not PickedEntity()=0
		W1.WayPoint = Object.WayPoint (Int(EntityName(PickedEntity())))
	EndIf

	If W1.Waypoint <> Null
		
		Color 255 , 0 , 0
		Text MX , MY    , "Waypoint      " + W1\Number
		Text MX , MY+15 , "Next Waypoint " + W1\Next_WP_Num
		Text MX , MY+30 , "Rotation      " + W1\Rotate_To_Next_WP
		Color 255 , 255 , 255
	
		If MouseHit(1)
			PositionEntity Dummy , W1\X , W1\Y + 1 , W1\Z , 1
			RotateEntity   Dummy , 0 , W1\Rotate_To_Next_WP , 0 ,1
		
			;For count=1 To 4
			;	dBodyDisable(Wheel(count))
			;Next
			;dBodyDisable(Car)
		
			dBodySetPosition  ( Car ,W1\X , W1\Y + 20 , W1\Z)
			dBodySetRotation  ( Car, dGeomGetPitch(CGeom),dGeomGetYaw(CGeom),0)   
			dBodySetAxisAngle ( Car ,2 , 0 , W1\Rotate_To_Next_WP , 0 )
			
			;For count=1 To 4
			;	dBodyEnable(Wheel(count))
			;Next
			;dBodyEnable(Car)

			
			
			FlushMouse()
			
		EndIf
	EndIf 

	If KeyHit(57)=1
		Force=0.0
		dBodySetRotation(Car,dGeomGetPitch(CGeom),dGeomGetYaw(CGeom),0)
	End If


End Function

Function CAR_AI()

	If TotalWP => 22
	
		Select Next_Waypoint 
			Case 0 
				Temp.WayPoint = First WayPoint 
				Next_Waypoint = Temp\Number 
			
				Temp.WayPoint = Last WayPoint 
				Temp\Next_WP_Num = 1 

			Default
				For W.Waypoint = Each Waypoint 
					If W\Number = Next_Waypoint 
						Temp = W
						Exit
					EndIf
				Next 	
				
				PointEntity CarCompass , Temp\Pivot
				
				Distance = EntityDistance ( Cmesh , Temp\Pivot )
				If Distance < 5 
					Next_Waypoint = Temp\Next_WP_Num
				Else 
					Force = Force + 0.08
					If Force > 3 Then Force = 3
				End If

				CarAngle     = EntityYaw#( Cmesh      , 1 ) 
				CompassAngle = EntityYaw#( CarCompass , 1 )

				TempAngle# = AngleDifference( CarAngle , CompassAngle )
	
				If TempAngle < -5 Then TempAngle = -5
				If TempAngle >  5 Then TempAngle =  5

				Steer = -(TempAngle * 0.05)

		End Select 
	EndIf
	
End Function

Function AngleDifference( CurrentAngle , TargetAngle )
    If TargetAngle - CurrentAngle > 180 Then TargetAngle = TargetAngle - 360
    If CurrentAngle - TargetAngle > 180 Then CurrentAngle = CurrentAngle - 360
    Return CurrentAngle - TargetAngle
End Function

Function Load_Waypoints()

	Restore WPdata

	Read Total
	
	For T = 1 To Total
	
		Read nX 
		Read nY 
		Read nZ
		Read nCurrentWP
		Read nNextWP
		Read nRotation

		W.WayPoint    = New WayPoint 

		W\X 		        = nX 
		W\Y 		        = nY 
		W\Z 		        = nZ
		W\Pivot  	        = CopyEntity ( CUBE )
		W\Number 	        = nCurrentWP
		W\Next_WP_Num       = nNextWP
		W\Rotate_To_Next_WP = nRotation
		
		PositionEntity W\Pivot , W\X , W\Y , W\Z , 1
		NameEntity     W\Pivot , Str$( Handle ( W.WayPoint ))
		EntityPickMode W\Pivot , 2
		RotateEntity   W\Pivot , 0 , Rotation , 0 , 1
	Next 
	
	TotalWP = T-1 
	  	
End Function

Function Make_DummyCar()

	Dummy = CreateCube()
	ScaleMesh Dummy , 1.5 , 0.5 , 2
	EntityColor Dummy ,0,0,255

	W1 = CreateCylinder(16) 
 	ScaleMesh  W1 , 0.7,0.25,0.7
	RotateMesh W1 , 0 , 0 , 90
	EntityColor W1 ,0 ,0,255

	W2 = CopyEntity ( W1 )
	W3 = CopyEntity ( W1 )
	W4 = CopyEntity ( W1 )
	
	PositionEntity W1 ,-2 , -0.5 , +2 
	PositionEntity W2 ,+2 , -0.5 , +2 
	PositionEntity W3 ,-2 , -0.5 , -2 
	PositionEntity W4 ,+2 , -0.5 , -2 

	EntityParent W1 , Dummy
	EntityParent W2 , Dummy
	EntityParent W3 , Dummy
	EntityParent W4 , Dummy

End Function

.WPdata

Data 22
Data  0   , 0 ,  43 ,  1 ,  2 ,  28
Data -9   , 0 ,  60 ,  2 ,  3 ,  43
Data -25  , 0 ,  77 ,  3 ,  4 ,  53
Data -42  , 0 ,  90 ,  4 ,  5 ,  48
Data -81  , 0 , 125 ,  5 ,  6 ,  26
Data -104 , 0 , 173 ,  6 ,  7 , -4
Data -102 , 0 , 201 ,  7 ,  8 , -36
Data -83  , 0 , 227 ,  8 ,  9 , -48
Data -63  , 0 , 245 ,  9 , 10 , -90
Data -36  , 0 , 245 , 10 , 11 , -90
Data -2   , 0 , 245 , 11 , 12 , -110
Data  34  , 0 , 232 , 12 , 13 , -144
Data  63  , 0 , 192 , 13 , 14 , -159
Data  77  , 0 , 155 , 14 , 15 ,  178
Data  75  , 0 , 101 , 15 , 16 ,  155
Data  52  , 0 ,  52 , 16 , 17 ,  126
Data  29  , 0 ,  35 , 17 , 18 ,  104
Data -3   , 0 ,  27 , 18 , 19 ,   49
Data -27  , 0 ,  48 , 19 , 20 , -4
Data -21  , 0 , 142 , 20 , 21 , -90
Data  32  , 0 , 142 , 21 , 22 , -169
Data  51  , 0 ,  40 , 22 , 1  ,  0



Thanks! :D

You need to zero the force, torque and velocity on the car body and all of the wheels, before you move them...

dBodySetForce(body,0,0,0)
dBodySetTorque(body,0,0,0)
dBodySetAngularVel(body,0,0,0)
dBodySetLinearVel(body,0,0,0)

Btw, it's forward slash '/' for the codebox end tag ;)

Thanks Vip3R,
It works beautifully. :)

Btw, it's forward slash '/' for the codebox end tag


whoops, sorry about that... I.ve edited it. :D

hi, i have a little problem with a 12 cars race game...

sometimes when i start the race and the cmesh touch or collition with an object, the cars bounce to an increible speed, and it goes from 45 to 1600 km/h in that exact moment, and it flies to the space :)

it doesn't always happen, when I put more cars on the scenary more possibilities fot this error to happen

sometimes too, all the cars constantly bounce

maybe i have something wrong with my 3d scenary, but when i use an odeplane, I have the same problem

I would like to know the reason why when the cmesh collides the cars bounce at ultra high speed!??

i'm sure this is some problem with my code.

thanks and regards.

If I understand correctly, the car meshes are colliding when the simulation is started? That would cause the high speed bounce as you put it.

If two or more objects overlap (collide) when you step the simulation, ODE may generate very high collision forces to correct it (the high speed bounce you've experienced).

The solution is to make sure they don't collide with anything when they're created or added to the scene.

The other issue (constant bounce) sounds like twitchy physics, adjusting things like ERP and CFM can help, you can also try adjusting the collision depth with dWorldSetContactSurfaceLayer(world,depth#).

hi..

i have this screenshot of my racecar track, i only want to know if these triangles distribution works fine with the ode cars..

i can change the polys if there is a best way to do the tracks for the ode system..



thanks VIP3R, your answers are always a big help.

another question -> is this the right forum to post this kind of question? or i must post in userlib\?

regards!, santiago

Those triangles should be ok.

You can post here with questions, it's fine.

i edit this post..

now the only problem i have with my cars, is when the road is go to up or down. when i turn the cars loose grip.. ¿how can i fix that?

It's extremely hard to say without an example showing the problem.

Try to describe in detail how the car reacts when there's grip/no grip. If it were a real-life situation, how would the car react compared to your simulation?

Apply a down force based on the velocity of your car.

Get fancy, and use some simplified lift equations:
L = 0.5 * Cl * A * r * V^2

Where L is lift (in this case, downforce), Cl =lift coefficient, A = area of the body facing the flow, r =air density, and V = velocity of the air flow.

CL = 2 * pi * angle

angle=-5 degrees

A = 3

r=0.074887

I hope you get the idea..

thanks...

Wayne. that is a good idea, i am going to apply that force to see what happens... i'm going to check ode functions, the force i think is not allways like gravity (down direction), because is created in the reality for the spoilers of the cars...

vip3r, i'll make some video and post the car data... to show the problem.

this is a link with some pictures of the game... (blitz forum link)
http://blitzbasic.com/Community/posts.php?topic=83490

vip3r, i posted a video in youtube showing the car movement, in the half part of the video, when the car reaches the track turns, look how the car makes small jumps.

Hmm, it looks like the bumps in the mesh are causing the car to bounce out of control. I remember the mesh picture you posted previously, from the video it appears that the triangles aren't flat. Try to arrange the triangles to form flat quads in bands around the track, so that the only angles there are at the edges of the quads (not the triangles). Doing this will prevent the wheels bouncing in an alternating fashion, causing the instability.

Adjusting the collision depth with dWorldSetContactSurfaceLayer(world,depth#) might also help. Wayne's suggestion sounds ideal if you're loosing too much friction.

Outstanding work btw, you can see a huge amount of work has been put into it :)

I looked at the youtube video and saw the wheels really bouncing.

How are the track meshes being created?

i have an ode plane for ground.

the track is a createmesh, with triangles sharing vertex by color. road, outroad and piano. when i finish the track i use this command to convert the trackmesh to trimesh ode...

entityfx trackmesh,2
updatenormals(trackmesh
pista_ode=CreateTriMesh(Space,trackmesh)
dGeomSetPosition(pista_ode,0,-.5,0)
dGeomSetRotation(pista_ode,0,0,0)
dGeomContactSetMu(pista_ode,100)

plano = dCreatePlane(Space,0,1,0,-.5)
dGeomContactSetMu(plano,10)
dgeomcontactsetbounce(plano,0))

i change the collision depth but don't see big changes..

im a newbie with ode, maibe in my code have more than one problem about physics...

I'm sure your physics code is mostly fine ;)

The mesh needs to be modified to remove those bumps at the edges of the triangles.

The built-in CreateTriMesh() function of JV-ODE doesn't use the mesh normals, so updating them will have no effect on the TriMesh. But, you could try changing the CreateTriMesh() function to use the following function...

dGeomTriMeshDataBuildSingle1(trimeshdata,vertices*,vtxstride,vtxcount,indices*,idxcount,tristride,normals*)

instead of...

dGeomTriMeshDataBuildSingle(trimeshdata,vertices*,vtxstride,vtxcount,indices*,idxcount,tristride)

Create a bank containing the normals data of the mesh, then use it for the normals parameter. In the same way that the verts and tris data is used.

Not sure whether that will help or not, but it's worth a try.

Does the car bounce when you are on the ground plane too ?

Have you taken a close look at the track when the wireframe is on ?

What are you using for tires on the car ?

wayne, i base my cars in the ode cars samples...
the ode wheels are like spheres, the car a cube...
i change the ode_properties, mu, mass, dimensions, bounces, etc..


i note the wheels makes a small and fast bounce when the car are stop in the road... i fixed that problem elevating the road..
that problem was because the ode_road and the ode_ground were too close.. and the ode_wheells touch two geometris...

now i only need to work in the car bounce because off the track edges differences... to fix that problem i working in the track editor, to make more smoother the triangles edges diferences, and i improve the ode cars propierties.

i recieve a lot of information about this problem, in this post and other post in the forum.. in few days i think this is totally solved.