Page MenuHome

Expose collision mask and group functionality to the Python API
Closed, ResolvedPublicPATCH


This patch exposes the collision masks and groups to the KX_GameObject python object.

The patch adds a SetCollisionBitmasks function to the BulletPhysicsController which calls updateCcdPhysicsController. This function deletes the collision object and recreates it, refreshing the collision mask and group.

Please feel free to offer any suggestions for improvement

Event Timeline

The collision masks and groups are handled completely by KX_GameObject, so there shouldn't be any need to involve Bullet. I'm also wonder if some of the set logic can be simplified; it seems to be over complicating things a bit.

After doing some extensive reading on Bullet forums, Bullet doesn't like modifying of masks during runtime - it sometimes caches values. They do not advise modifying the attributes, but instead recreating the object. This said, it would be simpler for my patch to avoid setting the mask and then recreating the object, instead it should just recreate the object. I shall investigate.

I've made all of the changes.
1) Added a set function to the mask and group (because It is better than directly modifying the attribute)
2) Added an UpdateController method to the PhysicsController. This simply calls updateCCdPhysicsController in the physics environment, passing the existing mass and flags. (It looks a lot like SetMass). I avoided naming it refresh masks because it can be used for generically recreating the physics object.
3) Added RW attributes collisionMask and collisionGroup to access these methods.

The set and get code could use a cleanup perhaps. I will modify it if the patch can be initially checked. A brief explanation as to why this works:

There is a bug that causes a collision on the first frame of the game. This is because objects don't exist, and so they are assumed to be colliding (as the AABB intersect, causing a false collision first frame - we cannot check the custom masks yet)
This simply recreates the physics body , which removes it from broadphase cache so it is checked again.

Potentially one nicer solution would be to use the setNearCallback to register a callback that can recreate the body manually after performing this check, However, because masks will only be changed by the collisionmask attribute (apart from the first frame bug) this would add more logic every collision, whereas this is just called when the masks change.

(dynamic_masks.patch is attatched)

The UpdateController() calls should be moved out of the Python functions and into the mask and group setters. This way no matter where they're called from they'll get updated. Also, setting the mask initially after the controller is created and assigned to the game object means we can also get rid of the collision on startup bug. Here's an example of what I'm talking about:

Any idea why refreshCcdPhysicsController() doesn't work for this?

I can't see the source right at the moment. But, provided that it is not overriden, refreshCcdPhysicsController should call cleanProxyFromPairs which should refresh the broadphase ->
Erwin does suggest on different occasions that it is sometimes easier to simply recreate the objects in the simulation, which is what SetMass currently does.
Yes, I was up late when creating the patch, I should have moved the call.

Supposing that the only time masks change is when they're called explicitly to do so, then it would be ok to use this as a work around. However, a callback would automatically handle the first frame bug. (But as I have said, perhaps at the expense of more collision processing.

Thanks for using m_cci.m_mass. I couldn't compile when I tried it.

After some further analysis it seems that even the act of calling refreshCcdPhysicsController and/or updateCCdPhysicsController doesn't fix the issue of sleeping (once the object is removed from the collision system). I will need to do some further analysis before determining how to proceed.

Added call to object->activate() to cause sleeping to be reset.
If the change to the collision mask/group doesn't directly change the state of the object then it will cause the system to consider the object regardless. This is an inevitability of the change. Attached is also a demonstration file. It changes the mask of the object after it would be sleeping, as well as the new patch.

Added fix for crashing with conversion. Includes fix for first frame bug. (added a narrowphase callback).

If we have the narrowphase callback, do we still need the changes to the broadphase? Also, why are you restricting the user to a bitfield between 0 and 255 if we have a short ((1<<16) - 1)? You're also missing documentation for the new KX_GameObject attributes.

You need narrowphase to fix the first frame bug, and you need the broadphase to cull collisions that would never happen (optimising physics usage).
I've removed the comparison logic, and added documentation

Fixed a typo in the python setters for collisionMask

It looks like some of the comments in the CustomNearCallback() were copied from the broadphase callback and don't apply in the narrowphase (e.g., "First check the filters"). In fact, I think the whole first comment doesn't apply to the narrowpahse. Also, "erroneus" should be "erroneous."

It might be nice to got some feedback on refreshCcdPhysicsController() versus updateCcdPhysicsController(). Especially since every object will have RerfreshCollisions() called at least once, which means every physics object might get created twice when using updateCcdPhysicsController().

This shouldn't be the case. I moved the RefreshCollisions call to the Python setter, and thus it will only be called when the user sets the mask in game, post creation. I'm not sure why it is that refreshCcdPhysicsController does not work.
I will need to remove the comments

So, does this no longer fix the problem with masks/groups not working on the first frame?

Is the CustomNearCallback still called during scene conversion? You also mention cleanup up collisions in the narrowphase, but CustomNearCallback is already part of the narrowphase. Also, do you really need to copy the comments from the broadphase check?

Yes it is. Essentially the broadphase is called (I believe) before necessarily all GameObjects are instantiated. The later call for the CustomNearCallback (which I ought to rename) will be able to find (hopefully) the GameObjects. I need to check this of course, but as Bullet updates everything simultaneously, one can assume that provided the GameObjects exist by the end of broadphase, they will exist for the narrowphase.

Comments need changing.

The last patch accidently removes m_cullingCache(NULL), m_cullingTree(NULL), from the CcdPhysicsEnvironment.
I updated the patch.

This should be two patches one for adding the api functions, and the other for fixing the first frame collision bug.

Adding a near phase callback to check for collision groups (therefore doing the check twice) shouldn't be the right soluion.
If broadphase is called during scene conversion, then that is what should be fixed.

Originally, clearing the broad phase cache had no effect, meaning we had to catch it in narrow phase. Now, however, the function does work, so we can remove the callback.

Porteries Tristan (panzergame) changed the task status from Unknown Status to Resolved.May 23 2015, 5:29 PM

Done in D1243.