Question about collision bitmasks

Hello, I’m confused by something with collision bitmasks. There seem to be two ways to set a collide mask on a GeomNode; setCollisionMask() and setIntoCollisionMask(). But setIntoCollisionMask() doesn’t seem to do anything. Here’s a code example illustrating my question:

import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from panda3d.core import *

class BitmaskTest(DirectObject):
  def __init__(self):
    dummyModel = NodePath()
    dummyGeo = loader.loadModel("someGeo.egg")

    cnode = dummyModel.attachNewNode(CollisionNode("cnode"))
    cnode.node().addSolid(CollisionSphere(0,0,0,1))

    cnode.node().setFromCollideMask(BitMask32(0xA))
    dummyGeo.node().setIntoCollideMask(BitMask32(0xA))

    print cnode.node().getFromCollideMask()
    print dummyGeo.node().getIntoCollideMask()
    print dummyGeo.getCollideMask()

    dummyGeo.setCollideMask(BitMask32(0xA))
    print dummyGeo.getCollideMask()

world = BitmaskTest()
run()

Can someone please explain this to me?

Thanks!

panda3d.org/manual/index.php … n_Bitmasks

 Every CollisionNode has two collide masks: a "from" mask, which is used when the CollisionNode is acting as a "from" object (i.e. it has been added to a CollisionTraverser), and an "into" mask, which is used when the node is acting as an "into" object (i.e. it is in the scene graph, and a from object is considering it for collisions). 

In addition, visible geometry nodes--that is, GeomNodes--also have an "into" mask, so that visible geometry can serve as an "into" object also. (However, only a CollisionNode can serve as a "from" object.) 

...
However, the into collide mask may be set on the NodePath, for convenience; this recursively modifies the into collide mask for all the nodes at the given NodePath level and below. 

nodePath.setCollideMask(newMask, bitsToChange, nodeType)

Thanks for your reply. Yes, I saw that in the manual, but my point is that setCollideMask() changes the “into” mask while setIntoCollideMask() doesn’t. I was wondering why.

PandaNode.setIntoCollideMask() is a lower-level function. It only sets the collide mask on that particular node; it does not recurse into children. However, NodePath.setCollideMask() does recurse into children; it sets the collide mask on that node and all of its descendants.

Now, there are only two kinds of nodes that can actually hold a collide mask: CollisionNodes and GeomNodes. Any other kinds of nodes, if you attempt to set a collide mask on them, they will quietly ignore it.

When you load a model, you get back a NodePath from loader.loadModel() that contains a hierarchy of nodes. The top node of this hierarchy is a ModelRoot node, while the actual geometry is contained in one or more descendant nodes. So, when you call dummyGeo.node().setIntoCollideMask(), you are actually setting the collide mask on the ModelRoot node only, which does nothing, because this is neither a CollisionNode nor a GeomNode. But when you call dummyGeo.setCollideMask(), it recurses through all descendants and sets the collide mask on all of the nodes, including the nested GeomNode(s).

Incidentally, NodePath.getCollideMask() also recursively visits all descendants and returns the aggregate collision mask from all of them. This is why dummyGeo.getCollideMask() appears to work.

For these reasons, we recommend using NodePath.getCollideMask() and NodePath.getCollideMask(), unless you really do want the low-level behavior that PandaNode.setIntoCollideMask() and PandaNode.getIntoCollideMask() provide.

David

Ah thank you, David. Yes, this makes sense to me. Is there a way to extract the GeomNode from a model? getChild() doesn’t seem to return any GeomNodes:

e.g.

for i in range(0,dummyGeo.node().getNumChildren()):
      print dummyGeo.getChild(i).node().isGeomNode()

always prints a ‘0’. By the way, I don’t actually need to get the GeomNode, I just want to understand how it all fits together.

The easiest way to get a sense of the hierarchy is with the ls() command:

dummyGeo.ls()

Or, pview the model and press shift-L to do the same thing (look in the console window for the output).

To find the GeomNodes programmatically, you can do:

for node in dummyGeo.findAllMatches('**/+GeomNode'):
  print node

David

That’s really, really handy to know! Thanks for your help! :slight_smile: