# Bullet apply rigid body to 3d shape

Hi, i would like to know if there is a way to use the BulletRigidBodyNode with irregular shapes, such as 3d models. In the manual there are primitive shapes and some advanced ones, but i have complex world 3d models (.egg) that i would like to use. How can i do that?

Hello, you need to add the Geom class to the BulletTriangleMesh instance.

https://docs.panda3d.org/1.10/python/programming/physics/bullet/collision-shapes#triangle-mesh-shape

Here it is shown how to extract Geom from geometry.

Do note, however, that such RigidBodyNodes will notâ€“I believeâ€“respect skinned animation: theyâ€™ll be just the mesh in its base form.

Also, if your models are fairly high-poly, then using them may be inefficient; whether this is a problem for your program may depend on just what youâ€™re doing. (Put another way, thereâ€™s a reason that collision geometry tends I believe to be simplerâ€“either low-poly or primitive shapesâ€“than visible geometry.)

Hi, thanks very much for this reply. I read through the docs you sent me, however i was unable to get it running, do you know if anyone did a tutorial about this, since i cannot find any?

I believe that thereâ€™s a code-snippet on the forum that deals with converting visible geometry to the geometry used by the built-in collision system; this could then be converted for Bullet via the â€śBulletHelperâ€ť class, specifically via the â€śfromCollisionSolidsâ€ť method.

The code-snippet:

Thanks, but after using the code snippet that you sent me with the fromCollisionSolids method, i encounter an error

``````"TypeError: BulletTriangleMesh.add_geom() argument 1 must be panda3d.core.Geom, not panda3d.core.NodePathCollection"
``````

My code:

``````def LoadWorldGeometry(self):
# create a temporary copy to generate the collision meshes from
model_copy = self.environmnet.copy_to(self.render)
model_copy.detach_node()
# "bake" the transformations into the vertices
model_copy.flatten_light()

# create root node to attach collision nodes to
collision_root = NodePath("collision_root")
collision_root.reparent_to(self.environmnet)
# offset the collision meshes from the model so they're easier to see
collision_root.set_x(1.)

# Please note that the code below will not copy the hierarchy structure of the
# loaded `model_root` and that the resulting collision meshes will all have
# their origins at (0., 0., 0.), an orientation of (0., 0., 0.) and a scale of 1
# (as a result of the call to `flatten_light`).
# If a different relationship between loaded models and their corresponding
# collision meshes is required, feel free to alter the code as needed, but keep
# in mind that any (especially non-uniform) scale affecting a collision mesh
# (whether set on the mesh itself or inherited from a node at a higher level)
# can cause problems for the built-in collision system.

# create a collision mesh for each of the loaded models
for model in model_copy.find_all_matches("**/+GeomNode"):

model_node = model.node()
collision_node = CollisionNode(model_node.name)
collision_mesh = collision_root.attach_new_node(collision_node)

for geom in model_node.modify_geoms():
print("Ă¬")

geom.decompose_in_place()
vertex_data = geom.modify_vertex_data()
vertex_data.format = GeomVertexFormat.get_v3()
view = memoryview(vertex_data.arrays[0]).cast("B").cast("f")
index_list = geom.primitives[0].get_vertex_list()
index_count = len(index_list)

for indices in (index_list[i:i+3] for i in range(0, index_count, 3)):
points = [Point3(*view[index*3:index*3+3]) for index in indices]
coll_poly = CollisionPolygon(*points)

return collision_root

self.environmnet.reparentTo(self.render)

world_mesh = BulletTriangleMesh()
``````

the code here has been extracted from my game class which contains a lot more code that is not relevant to this question, and that is why for example the

``````LoadWorldGeometry()
``````

function is called with self

Indeed, looking at the API, it seems that â€śfromCollisionSolidsâ€ť returns a NodePathCollectionâ€“i.e. a group of NodePaths, rather than a single NodePathâ€“much less a Geom!

Hmmâ€¦ Not being hugely familiar with the use of â€śfromCollisionSolidsâ€ť, let me ask: how many NodePaths are in the NodePathCollection? (I think that you can treat it as a list and just use the built-in â€ślenâ€ť function to get that number.)

It may be that itâ€™s doing the work for you and just producing a functional collision-mesh that you can then reparent into the scene-graph.

by performing the len() function on the NodePathCollection i get a result of 17

Actually, looking again at the API and around the forumâ€¦ have you tried just extracting your base Geoms after loading the modelâ€“without first constructing built-in collision-geometry from themâ€“and then passing those in to â€śaddGeomâ€ťâ€¦?

Something like this?

``````model = self.loader.loadModel("someModelFile.egg")
geomCollection = model.find("**/+GeomNode")
for geom in geomCollection:
``````

I will confess here that Iâ€™m not hugely familiar with this sort of thing, so I may very well be off about this! ^^;

``````from direct.showbase.ShowBase import ShowBase
from panda3d.bullet import BulletTriangleMesh, BulletTriangleMeshShape

class MyApp(ShowBase):

def __init__(self):
ShowBase.__init__(self)

mesh = BulletTriangleMesh()

for node_path in model.find_all_matches('**/+GeomNode'):
for i in range(node_path.node().get_num_geoms()):
geom = node_path.node().get_geom(i)
This code will extract all the `Geoms` in your model and create a `BulletTriangleMeshShape`