How to enable mesh collision in an OBJ model

I want to leverage Panda3D’s collision system to trace an obj model with collision rays and generate sort of a “point cloud”.

Speed and run-time optimizations are not relevant because I’m not building a “game” - just this single purpose
I currently have a collision system set up using the built in engine in Panda, and it works with CollisionBoxes. I looked online for a mesh collider solution, someone said it’s possible to: make any visible mesh be an “into” collision solid by setting the appropriate collide mask on it.

I tried the following:
Collision ray code

def cast_ray(self, a, b):

        ray = CollisionRay()
        ray.setOrigin(a)
        ray.setDirection(b-a)

        rayNode = CollisionNode("ray")
        rayNode.addSolid(ray)

        rayNodePath = self.scene.render.attachNewNode(rayNode)
        rayNodePath.node().setIntoCollideMask(BitMask32.allOff())
        rayNodePath.node().setFromCollideMask(BitMask32.bit(0))
        rayQueue = CollisionHandlerQueue()

        self.scene.cTrav.addCollider(rayNodePath, rayQueue)
        self.scene.cTrav.traverse(self.scene.render)

Obj code

def add_rock(self, position):
        box_n = self.scene.loader.loadModel("./obj/stone_1.obj")
        box_n.setScale(1, 1, 1)
        box_n.setPos(position + Point3(0, 0, .5))
        box_n.flattenLight()
        box_n.setTextureOff()
        box_n.node().setIntoCollideMask(BitMask32.bit(0))
        box_n.reparentTo(self.scene.render)

So I tried to set box_n.node().setIntoCollideMask(BitMask32.bit(0)) but it doesn’t work

What else am I missing?

You can see an example of this here, I believe:
https://docs.panda3d.org/1.10/python/programming/collision-detection/clicking-on-3d-objects

One thing that I note is that it’s not clear that the node on which you’re setting the bitmask is actually the model’s collision-node. It might be worth searching the loaded model for CollisionNodes, and then operating specifically on those. (See this manual page for more.)

@Thaumaturge
Still feel like I’m missing something…
Following the object clicking tutorial, I added a tag to the object, but it still wasn’t picked up.

As for the second reference, ls() prints out the following

ModelRoot stone_1.obj S:(TextureAttrib)
  PandaNode stone_1.obj
    GeomNode stone1 (1 geoms: S:(MaterialAttrib))

I also tried to add a collision node with setIntoCollide, and now ls() prints out

ModelRoot stone_1.obj S:(TextureAttrib)
  PandaNode stone_1.obj
    GeomNode stone1 (1 geoms: S:(MaterialAttrib))
  CollisionNode box (0 solids) [test_tag] (hidden)

CollisionNode displays 0 solids… maybe that’s the issue? How can I add a “mesh collider”?

Hmm… It is odd that there are zero solids! It suggests that there might be a problem with the model itself.

[edit] Ah, I didn’t notice that you said that you added the collision node yourself. Indeed, a collision node with no solids won’t do much, I daresay. [/edit]

That said, if you just want to collide with visible geometry, then you needn’t have a collision node. Instead, you can set the ray to collide with the “visible geometry” bitmask–see the third line of the first piece of code in that “clicking on 3D objects” page.

2 Likes

It worked!!! Thank you :smiley:

For future reference, adjustments to the code above:

For the ray

rayNodePath.node().setFromCollideMask(GeomNode.getDefaultCollideMask())

And for the obj

    def add_rock(self, position):
        box_n = self.scene.loader.loadModel("./obj/stone_1.obj")

        box_n.setScale(1, 1, 1)
        box_n.setPos(position + Point3(0, 0, .5))
        box_n.node().setIntoCollideMask(GeomNode.getDefaultCollideMask())
        box_n.reparentTo(self.scene.render)
2 Likes