Panda3d ode trimesh

I changed OdeBoxGeom to OdeTriMeshGeom in code from Panda3d manual. But it does not works. There’s code:

from direct.directbase import DirectStart
from pandac.PandaModules import OdeWorld, OdeSimpleSpace, OdeJointGroup
from pandac.PandaModules import OdeBody, OdeMass, OdeBoxGeom, OdePlaneGeom, OdeTriMeshGeom, OdeTriMeshData
from pandac.PandaModules import BitMask32, CardMaker, Vec4, Quat
from random import randint, random
 
# Setup our physics world
world = OdeWorld()
world.setGravity(0, 0, -10)
 
# The surface table is needed for autoCollide
world.initSurfaceTable(1)
world.setSurfaceEntry(0, 0, 150, 0.0, 9.1, 0.9, 0.00001, 0.0, 0.002)
 
# Create a space and add a contactgroup to it to add the contact joints
space = OdeSimpleSpace()
space.setAutoCollideWorld(world)
contactgroup = OdeJointGroup()
space.setAutoCollideJointGroup(contactgroup)
 
# Load the box
box = loader.loadModel("box")
# Make sure its center is at 0, 0, 0 like OdeBoxGeom
box.setPos(-.5, -.5, -.5)
box.flattenLight() # Apply transform
box.setTextureOff()
 
# Add a random amount of boxes
boxes = []
for i in range(randint(15, 30)):
  # Setup the geometry
  boxNP = box.copyTo(render)
  boxNP.setPos(randint(-10, 10), randint(-10, 10), 10 + random())
  boxNP.setColor(random(), random(), random(), 1)
  boxNP.setHpr(randint(-45, 45), randint(-45, 45), randint(-45, 45))
  # Create the body and set the mass
  boxBody = OdeBody(world)
  M = OdeMass()
  M.setBox(50, 1, 1, 1)
  boxBody.setMass(M)
  boxBody.setPosition(boxNP.getPos(render))
  boxBody.setQuaternion(boxNP.getQuat(render))
  # Create a BoxGeom
  boxGeom = OdeBoxGeom(space, 1, 1, 1)
  boxData=OdeTriMeshData(box)
  boxGeom=OdeTriMeshGeom(boxData)
  boxGeom.setCollideBits(BitMask32(0x00000002))
  boxGeom.setCategoryBits(BitMask32(0x00000001))
  boxGeom.setBody(boxBody)
  boxes.append((boxNP, boxBody))
 
# Add a plane to collide with
cm = CardMaker("ground")
cm.setFrame(-20, 20, -20, 20)
ground = render.attachNewNode(cm.generate())
ground.setPos(0, 0, 0); ground.lookAt(0, 0, -1)
groundGeom = OdePlaneGeom(space, Vec4(0, 0, 1, 0))
groundGeom.setCollideBits(BitMask32(0x00000001))
groundGeom.setCategoryBits(BitMask32(0x00000002))
 
# Set the camera position
base.disableMouse()
base.camera.setPos(40, 40, 20)
base.camera.lookAt(0, 0, 0)
 
# The task for our simulation
def simulationTask(task):
  space.autoCollide() # Setup the contact joints
  # Step the simulation and set the new positions
  world.quickStep(globalClock.getDt())
  for np, body in boxes:
    np.setPosQuat(render, body.getPosition(), Quat(body.getQuaternion()))
  contactgroup.empty() # Clear the contact joints
  return task.cont
 
# Wait a split second, then start the simulation  
taskMgr.doMethodLater(0.5, simulationTask, "Physics Simulation")
 
run()

I found error. I created both OdeBoxGeom and OdeTriMeshGeom. I fixed it, but it does not work:

from direct.directbase import DirectStart
from pandac.PandaModules import OdeWorld, OdeSimpleSpace, OdeJointGroup
from pandac.PandaModules import OdeBody, OdeMass, OdeBoxGeom, OdePlaneGeom, OdeTriMeshGeom, OdeTriMeshData
from pandac.PandaModules import BitMask32, CardMaker, Vec4, Quat
from random import randint, random
 
# Setup our physics world
world = OdeWorld()
world.setGravity(0, 0, -10)
 
# The surface table is needed for autoCollide
world.initSurfaceTable(1)
world.setSurfaceEntry(0, 0, 150, 0.0, 9.1, 0.9, 0.00001, 0.0, 0.002)
 
# Create a space and add a contactgroup to it to add the contact joints
space = OdeSimpleSpace()
space.setAutoCollideWorld(world)
contactgroup = OdeJointGroup()
space.setAutoCollideJointGroup(contactgroup)
 
# Load the box
box = loader.loadModel("box")
# Make sure its center is at 0, 0, 0 like OdeBoxGeom
box.setPos(-.5, -.5, -.5)
box.flattenLight() # Apply transform
box.setTextureOff()
 
# Add a random amount of boxes
boxes = []
for i in range(randint(15, 30)):
  # Setup the geometry
  boxNP = box.copyTo(render)
  boxNP.setPos(randint(-10, 10), randint(-10, 10), 10 + random())
  boxNP.setColor(random(), random(), random(), 1)
  boxNP.setHpr(randint(-45, 45), randint(-45, 45), randint(-45, 45))
  # Create the body and set the mass
  boxBody = OdeBody(world)
  M = OdeMass()
  M.setBox(50, 1, 1, 1)
  boxBody.setMass(M)
  boxBody.setPosition(boxNP.getPos(render))
  boxBody.setQuaternion(boxNP.getQuat(render))
  # Create a BoxGeom
  boxData=OdeTriMeshData(box)
  boxGeom=OdeTriMeshGeom(boxData)
  boxGeom.setCollideBits(BitMask32(0x00000002))
  boxGeom.setCategoryBits(BitMask32(0x00000001))
  boxGeom.setBody(boxBody)
  boxes.append((boxNP, boxBody))
 
# Add a plane to collide with
cm = CardMaker("ground")
cm.setFrame(-20, 20, -20, 20)
ground = render.attachNewNode(cm.generate())
ground.setPos(0, 0, 0); ground.lookAt(0, 0, -1)
groundGeom = OdePlaneGeom(space, Vec4(0, 0, 1, 0))
groundGeom.setCollideBits(BitMask32(0x00000001))
groundGeom.setCategoryBits(BitMask32(0x00000002))
 
# Set the camera position
base.disableMouse()
base.camera.setPos(40, 40, 20)
base.camera.lookAt(0, 0, 0)
 
# The task for our simulation
def simulationTask(task):
  space.autoCollide() # Setup the contact joints
  # Step the simulation and set the new positions
  world.quickStep(globalClock.getDt())
  for np, body in boxes:
    np.setPosQuat(render, body.getPosition(), Quat(body.getQuaternion()))
  contactgroup.empty() # Clear the contact joints
  return task.cont
 
# Wait a split second, then start the simulation 
taskMgr.doMethodLater(0.5, simulationTask, "Physics Simulation")
 
run() 

Can you be more specific than “does not work”?
Are you not getting any collision reactions from the trimesh?
Do you get a Python error or a Panda exception?
Does it crash?

I dont get any reaction on collision. Boxes simply flies down.

A couple things to try:

  • Generate your OdeTriMeshData from a trianglulated mesh.
  • Try replacing the trimesh geoms with other ODE types (box and plane for example) and see if that works. Does it work with both replaced? Only the plane? Only the boxes?

ODE has some compile options, Panda’s build of ODE might ship with trimesh vs. trimesh collisions disabled.

In general you should avoid using trimesh for collision where possible, but especially for dynamic objects. If you really need a complex dynamic collision object look into ODE’s convex hulls.

What is a triangulated mesh?

As I wrote, program works if ground is OdePlaneGeom and boxes are OdeBoxGeom. But it does not work if either ground or boxes (or both) are OdeTriMeshGeom.

Can I replace it with ODE, built by myself?

I have complex “level”/“ground” model. I need collisions with it.

PS. I am newbie in ODE and physics at all.

I found that i can not do it without rebuilding panda because it is statically linked.

Usually the models in the EGG files are made of N-sided polygons: (triangles, quads, etc.). In my own project I found that I needed to make sure that the meshes were triangulated, that is make the mesh such that it is built entirely out of 3-sided polygons, before OdeTriMeshData would work properly. There might be some ability in Panda to do this, but I do it when I export my EGG files.

It is common to use a trimesh collision for your static world, but not for moving objects.

I got it working! The problem was very simple. Error was here:

 boxGeom=OdeTriMeshGeom(boxData)

I saw code of ode samples and found that all of them passes their ode space to OdeTriMeshGeom:

  boxGeom=OdeTriMeshGeom(space,boxData)

It works fine.
[/code]

Glad to see you got it working, sometimes the simplest things are the hardest to find!