Can't use model geometry as Bullet shape properly

Hi, I’m trying to integrate Bullet physics into a small racer I’m writing, but I can’t seem to use the track model as a rigid body. You can view the effect I’m getting at http://vincentnys.ulyssis.be/uploads/physics.webm. You’ll see that the player’s vehicle starts on top of a little block of geometry and then falls of gradually. The problem is that I don’t know why I’m getting that little block, rather than something that matches the white track both in size and position. What I’m doing is this:

geom = self.model.findAllMatches('**/+GeomNode').getPath(0).\
       node().getGeom(0)
bullet_mesh = BulletTriangleMesh()
bullet_mesh.addGeom(geom)
shape = BulletTriangleMeshShape(bullet_mesh,dynamic=False)

self.bullet_node = BulletRigidBodyNode("Track body node")
bullet_np = self.root.attachNewNode(self.bullet_node)
self.bullet_node.addShape(shape)

It looks like the block of collision geometry is at the location of the origin in my .blend file, if that’s any help.

Most likely you have a scale on your model. Try the “ls()” command on the NodePath loaded, or look into the .egg file. Also please notice that the way you create the mesh picks up only the first Geom within your model (there could be several more), and it does not respect potential transforms of the Geom relative to the model’s root.

Thanks for the comment. It was on the mark and it has been enlightening, but the last remark is still a bit unclear to me. I think I get the problem (that I’m just getting “raw” geometry without taking into account the transformation matrix which is applied to that geometry when I load a model) but I’m getting lost in the API. Could you tell me how I can obtain the potential transforms you mention, so that I can also apply them to the collision geometry?

Basically it is what the manual describes in the section about reading existing geometry:

  for geomNP in modelNP.findAllMatches('**/+GeomNode'):
    geomNode = geomNP.node()
    ts = geomNode.getTransform()
    for geom in geomNode.getGeoms():
      # here you have both the geom and the geom's transform (ts)

So in order to create triangle meshes you would do something like this:

  body = BulletRigidBodyNode('...')

  for geomNP in modelNP.findAllMatches('**/+GeomNode'):
    geomNode = geomNP.node()
    ts = geomNode.getTransform()
    for geom in geomNode.getGeoms():
      mesh = BulletTriangleMesh()
      mesh.addGeom(geom)

      shape = BulletTriangleMeshShape(mesh, dynamic=False)
      body.addShape(shape, ts)

Here I create one shape for each geom, and offset the shape relative to the body when adding the shape to the body.

An alternate way would be modify the geom by transforming all of it’s vertices with the TransformState ts. for example like in the manual section about modifying existing geometry described.

I agree that it would be usefull to have an automatic transform option provided by the mesh builder. I have done this for the PhysX module, but not for the Bullet module. I should add it sometime. Then you could simply use a code like this:

  mesh = BulletTriangleMesh()

  for geomNP in modelNP.findAllMatches('**/+GeomNode'):
    geomNode = geomNP.node()
    ts = geomNode.getTransform()
    for geom in geomNode.getGeoms():
      mesh.addGeom(geom, True, ts) # <-- not yet implemented!

  shape = BulletTriangleMeshShape(mesh, dynamic=False)
  body = BulletRigidBodyNode('...')
  body.addShape(shape)

I have added support for passing TransformStates to the addGeom method (both for triangle meshes and convex meshes). the next buildbot version should pick up the commit.