My custom patch for collision callback events

Promit
Posts: 3
Joined: Fri Oct 20, 2006 12:08 am

My custom patch for collision callback events

Post by Promit »

For my purposes, I want two very simple collision callbacks: CollisionStarted(objA, objB) and CollisionEnded(objA, objB). I got tired of Bullet's seemingly convoluted, quirky methods for detecting what collisions have happened. Iterating over the manifolds doesn't tell you whether a collision is new or not, and can't yield the correct events as a result. Contact processing is exposed in a very confusing way, and ghost objects are a hassle. So I dropped into the source and wrote up a new set of callbacks that work the way I want. The modifications are trivial, yet immensely helpful IMO.

This is how it looks in client code:

Code: Select all

	//set the callbacks somewhere
	gCollisionStartedCallback = CollisionStarted;
	gCollisionEndedCallback = CollisionEnded;

static void CollisionStarted(btPersistentManifold* manifold)
{
	btCollisionObject* obA = static_cast<btCollisionObject*>(manifold->getBody0());
	btCollisionObject* obB = static_cast<btCollisionObject*>(manifold->getBody1());
	PhysicsComponent* phyA = (PhysicsComponent*) obA->getUserPointer();
	PhysicsComponent* phyB = (PhysicsComponent*) obB->getUserPointer();
	if(!phyA || !phyB)
		return;
	
	printf("Collision started between: %s, %s.\n", phyA->_parent->Name.c_str(), phyB->_parent->Name.c_str());
}

static void CollisionEnded(btPersistentManifold* manifold)
{
	btCollisionObject* obA = static_cast<btCollisionObject*>(manifold->getBody0());
	btCollisionObject* obB = static_cast<btCollisionObject*>(manifold->getBody1());
	PhysicsComponent* phyA = (PhysicsComponent*) obA->getUserPointer();
	PhysicsComponent* phyB = (PhysicsComponent*) obB->getUserPointer();
	if(!phyA || !phyB)
		return;
	
	printf("Collision ended between: %s, %s.\n", phyA->_parent->Name.c_str(), phyB->_parent->Name.c_str());	
}
That's it. You get a single notification when a collision starts, no matter what is happening with the contacts. You get another notification when the collision ends. In my code I walk back into my own object hierarchy, but you could conceivably do whatever since the whole manifold is present and persistent.

The changes to Bullet are a mere handful of lines, and attached to this post as a patch. The logic is dead simple: If a contact is added to a manifold with zero contacts, trigger gCollisionStarted. If a contact is removed leaving a manifold with zero contacts, trigger gCollisionEnded. Personally I think this is what most people want. This may not work well if you need all of the contact points, as the collision started callback triggers as soon as a single point is available.

I'm posting this here first in case I did something incredibly stupid or unnecessary, but all of the stuff I've seen in the forums and documentation is waaaay more of a PITA than what I've put together here. If this is something useful and productive, I'll probably publish on GameDev and my blog, dunno if it's appropriate for inclusion into Bullet main-line.
Attachments
promit-bulletcollisions.txt
Promit's custom patch to bullet for collision callbacks.
(2.52 KiB) Downloaded 811 times
Flix
Posts: 456
Joined: Tue Dec 25, 2007 1:06 pm

Re: My custom patch for collision callback events

Post by Flix »

Short version:
I think these callbacks can be useful in many cases, and I would appreciate their introduction in the Bullet library if it doesn't break something existent.
I would add a CF_MANIFOLD_CALLBACK collision flag (analogous to CF_CUSTOM_MATERIAL_CALLBACK) to filter the objects that need it, and probably change the name of the callbacks so that it's clear that they provide access to a persistent manifold (something like: gManifoldStartedCallback, gCollisionManifoldStartedCallback?).

Long version:
I've read that you're going to publish something about this. Could you please help me to understand the topic a little deeper ?
This is what I've understood about it so far (based mainly on what I think it is, not on what I'm sure it is, since I've tested only about 50% of what I'm going to describe here...).

As far as I can understand with your contribution there are 3 ways commonly used to get collision information in Bullet:

1) gContactAddedCallback/gContactDestroyedCallback (and maybe gContactProcessedCallback?).
USAGE:
a) CF_CUSTOM_MATERIAL_CALLBACK enables gContactAddedCallback.
b) Inside gContactAddedCallback set cp.m_userPersistentData!=NULL.
c) Now gContactDestroyedCallback is called.
PROS:
-> Point (a) on its own is used in tons of demos for custom friction/restitution, for the internal edge problem fix and for detecting the index/partId of the colliding parts of the meshes/shapes.
-> Extra flexibility due to cp.m_userPersistentData.
CONS:
-> Plenty of forum posts state that the cp.m_userPersistentData trick is not reliable enough or works only with some special solver configurations (just search the forum and see it).
-> In some cases users are interested not much in the creation and destruction of single manifold points, but in the overall collision evolution between two btCollisionObjects (I mean: when a btManifoldPoint is created it does not mean that two bodies were not colliding before, and when it's destroyed it does not mean the objects are not in contact anymore). (*)
-> Some parameters of the btManifoldPoint (like m_appliedImpulse) are not usable here.

2) Your approach (I'd extend it with a collision flag to filter which object needs these callbacks).
USAGE:
-> CF_MANIFOLD_CALLBACK enables gCollisionStartedCallback/gCollisionEndedCallback (I'd call them something like: gManifoldStartedCallback or gCollisionManifoldStartedCallback and so on...).
PROS:
-> In the cases described above at point (*), this solution improves the contact results, so that in most cases these callbacks can be considered the 'correct' callbacks to use for handling total collision start / end events between two objects.
-> Easy to implement.
CONS:
-> Needs modification to the Bullet source code.
-> More work is needed if the user needs access to manifold points (but if the manifolds are persistent, maybe the user can store them somewhere after the start callback and keep using them until the end callback... or not?).
-> As far as I understand (but comments are welcome) the problem at point (*) is not completely solved with this approach: If an object is compound shaped and collides with another object with MORE than one of its child shapes, two contacts manifolds are created for the same pair of objects (each can contain a maximum of 4 contact points).

3) Manually iterating all the contact manifolds.
USAGE: Basic code

Code: Select all

const int numManifolds = btDynamicsWorld->getDispatcher()->getNumManifolds();
   for (int i=0;i<numManifolds;i++)
   {
   	 btPersistentManifold* contactManifold = btWorld->getDispatcher()->getManifoldByIndexInternal(i);
         btCollisionObject* objA = static_cast <btCollisionObject*> (contactManifold->getBody0());
         btCollisionObject* objB = static_cast <btCollisionObject*> (contactManifold->getBody1());    
         for (int j=0;j<tcontactManifold->getNumContacts();j++)	{
        	btManifoldPoint& pt = contactManifold->getContactPoint(j);  
                if (pt.m_distance1<0) {
                // Valid contact point
                } 
        }
  }
          
PROS:
-> You got all the possible collision data available in Bullet and you can build a system to solve problem: (*).
-> Flexibility: you can use only the pieces you need and discard the others.
-> I believe this solution is recommended in the Bullet docs.
CONS:
-> It's difficult to build an automatic way to fire events with this approach and such a system can't be very fast (I posted one in an old post on this forum, but it's a bit slow (I calculated an 'average contact point' every frame to feed the callbacks and I had to mantain two lists of colliding object pairs and to compare them to fire started/ended events)).

I hope somebody can correct possible mistakes.
PS: I know that technically an event is something different from a callback, but I've used these terms as synonyms above.
Promit
Posts: 3
Joined: Fri Oct 20, 2006 12:08 am

Re: My custom patch for collision callback events

Post by Promit »

That's all consistent with my understanding, at least, but I am not an expert here. I do agree that a flag would be useful to filter the callbacks.
asmithers
Posts: 13
Joined: Wed Apr 26, 2006 6:22 pm

Re: My custom patch for collision callback events

Post by asmithers »

Promit,

Nice elegant modification. I was about to write something similar and thought I would check to see if anyone had solved this issue. Your solution to this problem works very well. The most useful being that constantly embedded objects don't spam the collision events, something that I had going on with objects interacting with landscapes but still needing events.

thank you

-andi
blitter
Posts: 1
Joined: Tue Feb 07, 2012 8:02 pm

Re: My custom patch for collision callback events

Post by blitter »

Thanks Promit! This has been fantastic for me, as has the SDK which is awesome after being locked out of a competitor's source. Thanks loads all involved :-)
opengenius
Posts: 1
Joined: Sat Sep 29, 2012 9:26 am

Re: My custom patch for collision callback events

Post by opengenius »

clearManifold() in btPersistentManifold.h must be also changed to catch all "end collision" events:

Code: Select all

	SIMD_FORCE_INLINE	void	clearManifold()
	{
		int i;
		for (i=0;i<m_cachedPoints;i++)
		{
			clearUserCache(m_pointCache[i]);
		}
		
		if(gCollisionEndedCallback && m_cachedPoints)
		{
			gCollisionEndedCallback(this);
		}

		m_cachedPoints = 0;
	}
NotCamelCase
Posts: 2
Joined: Thu Dec 26, 2013 8:44 pm

Re: My custom patch for collision callback events

Post by NotCamelCase »

Has anyone used this successfully ? I've applied the code changes however I'm still getting start/end callbacks repeatedly.
Jonathan
Posts: 36
Joined: Sun Feb 10, 2013 6:52 pm

Re: My custom patch for collision callback events

Post by Jonathan »

I applied the changes manually (it's just a few lines of a code) and everything seems to be working great!

Why has this not been included in bullet's main line? This is the behavior most people are looking for.

I can confirm the extra code opengenius wrote is also necessary. Thanks!
lunkhound
Posts: 99
Joined: Thu Nov 21, 2013 8:57 pm

Re: My custom patch for collision callback events

Post by lunkhound »

Why has this not been included in bullet's main line?
If I had to guess, I'd say it's because it doesn't add anything you can't already do, and it's bad for performance.

I prefer to walk the list of persistent manifolds after each simulation step, and batch up events to send out to my game objects after all of the physics stepping is done.
While these callbacks may be convenient, they don't really enable anything you can't already do (by just walking the persistent manifolds).
Having these sorts of callbacks is bad for performance for a couple of reasons:

1. Parallelism. If you are running the physics in one thread, and the game logic in another, you can't really have these callbacks from the physics thread altering game objects while the game logic thread is altering them also. That would be a disaster. Race conditions, or mutex hell. If you want these type of callbacks you really can't have separate threads for physics and game logic. And if you are running the physics on the GPU, ala bullet3, these kind of callbacks to CPU logic aren't even possible.

2. Cache pollution. Every time the callback is called from within the physics it will be evicting physics data and code from the CPU cache, hurting performance.
N0vember
Posts: 10
Joined: Sat Mar 06, 2010 6:39 pm

Re: My custom patch for collision callback events

Post by N0vember »

I am digging this up as I recently posted about trying to obtain the behavior described in this topic : that is, simple callbacks on collisions. (Here is my thread : http://www.bulletphysics.org/Bullet/php ... =9&t=10211)

As Bullet 3 is being developped and we are shifting to GPUs, I understand the criticism lunkhound expressed to having this kind of callbacks.
That's also why I think it is critical to have this conversation right now, and possibly draw the attention of Erwin to it.

From my point of view, Bullet potentially has two very strong points : performance, and the ability to use only the collision detection part in a convenient manner. Performance is obviously there and will be even more with Bullet 3. But the simple problem in this topic shows how Bullet fails to deliver on the second part.
One of the main uses of an efficient collision library is a simple way to pick out new collisions, and gone collisions.

This is like, efficiency 101 : knowing which collisions are new and are gone, with respect to the ones that are unchanged, allows significant gains in the way the program is organized, by not reprocessing stuff that has already been processed over and over.
It's by design, one of the first thing a collision library user needs to do : do something only when a collision is new and when it is removed.

It's like the difference between redrawing a whole GUI and only the part that changed.
And especially : it's a processing that is happening inside Bullet. It's the work Bullet is already doing. It just was never organized in a way to let an external part of the code observe these two simple events (new collision, collision ended). All attempts of replicating the distinction outside of Bullet would just be an extra (not trivial) overhead for something that Bullet already does internally.

Now I hear your argument that the feature we are asking, for both simplicity of use and performance, would actually hinder performance.
That's why I am asking if we could think of a way, with just a bit more effort, to get the best of both worlds.
I understand that GPU should be insulated from the CPU part, so a callback between both is out of the question.

Now, if bullet could maintain, per simulation tick, a list, or just a simple flag, telling which contacts were added, and which were removed, that would be perfect.
The data could stay in the GPU part but we would get the easy picking out we need.

The simple and recurring use case is the following :
The application has its own set of collision informations that is derived from the one internal to bullet, but with subsequent information and processing added to it, that could originate from other collision checks, with other objects with other masks, or even information processing unrelated to physics.
So for each collision A in Bullet, we have a A' and A'' informations that are derived from it.
We have really just three architecture alternatives here regarding efficiency :
- Maintain the second set by looking over all the collisions, and sort out everything every frame to determine what needs to be processed to A' and A'' and what doesn't
- Reprocess everything every frame to A' and A'' regardless of whether it needs to
- Have an easy way to pick out the new collisions and removed collisions

Also, just a last bit of criticism against the "iterate over all the collisions" brute force method : how do you tell that one has disappeared ? you have to check for each of the previous state collisions that they are still in there. That's really inefficient when you could have a callback or a thread-friendly alternative.

I hope I am at least making some sense in my advocacy of collision callbacks or a similar feature
lunkhound
Posts: 99
Joined: Thu Nov 21, 2013 8:57 pm

Re: My custom patch for collision callback events

Post by lunkhound »

It is already possible to easily determine which collisions are new by inspecting the list of persistent manifolds. For each manifold there are a number of btManifoldPoints, and the manifold point has a "lifetime" value. If the lifetime is 1, then it is new. So, no need to add a flag for that.

One kind of tricky problem with the idea of having Bullet report a list of deleted contacts, is how to identify the contacts that previously existed. Would it simply be pointers to potentially deallocated memory? Some of those pointers could be pointing to newly allocated contacts (new contact at the same address as the old, now deleted contact). That seems really problematic.

I try to avoid creating persistent data structures (outside of bullet) that mirror bullet internals. So far I haven't felt the need to do so, however if I did need that I think it would be nice to have a unique-id on the persistent manifolds, so that a hash table could be used to quickly map from the manifold-id to my external structures. That would be a very simple change to Bullet, and wouldn't add any noticeable overhead.

The list of newly created contacts and the list of deleted contacts doesn't seem like something that Bullet should be doing, I don't think it is very useful in most cases.
However, if the manifold-id was added you could easily create those lists for yourself.
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: My custom patch for collision callback events

Post by Erwin Coumans »

It is good to sort this our for the upcoming Bullet 3.x release.

Indeed, iterating over the contact manifolds and using the lifetime flag should be sufficient to determine what contact points are 'new'.

In a new (GPU friendly) implementation, we could use double-buffering, maintaining the 'old' contact buffer and a 'new' contact buffer. We will need a parallel 'diff' then to determine the lifetime of contacts, carying over contact cache information (applied impulse). The new contact buffer would have entries for deleted points.

Would that be sufficient?
I created an issue to track progress on this, as I may not actively track the forums: https://github.com/bulletphysics/bullet3/issues/291
N0vember
Posts: 10
Joined: Sat Mar 06, 2010 6:39 pm

Re: My custom patch for collision callback events

Post by N0vember »

lunkhound wrote:It is already possible to easily determine which collisions are new by inspecting the list of persistent manifolds. For each manifold there are a number of btManifoldPoints, and the manifold point has a "lifetime" value. If the lifetime is 1, then it is new. So, no need to add a flag for that.
I didn't actually now about that flag. That's one really important little detail I didn't know about. The problem of removed contacts is still whole though.
lunkhound wrote: I try to avoid creating persistent data structures (outside of bullet) that mirror bullet internals. So far I haven't felt the need to do so, however if I did need that I think it would be nice to have a unique-id on the persistent manifolds, so that a hash table could be used to quickly map from the manifold-id to my external structures. That would be a very simple change to Bullet, and wouldn't add any noticeable overhead.
Well I have a simple example from my own application. Just suppose you have a "perception" model to determine what a player sees in a scene. You have spheres representing the perceptions of a character colliding with the things it can detect. But you also want to raycasts for obstacles between the receptor and the things it perceives.

So you have to keep a list that doesn't exactly mirrors the one in bullet internals. So you need your own. And you don't have much more than two solutions to keep this list up to date : either you only process the new and removed collisions, update your own list, and apply the raycasts on these (+ the ones in the list that moved), either your perform the raycasts all the time for all the colliding objects and compute the list of perceived objects each frame. If you're going for performance, the second option quickly limits you far more in the number of objects. The first one is the optimal one.
Erwin Coumans wrote:It is good to sort this our for the upcoming Bullet 3.x release.

Indeed, iterating over the contact manifolds and using the lifetime flag should be sufficient to determine what contact points are 'new'.

In a new (GPU friendly) implementation, we could use double-buffering, maintaining the 'old' contact buffer and a 'new' contact buffer. We will need a parallel 'diff' then to determine the lifetime of contacts, carying over contact cache information (applied impulse). The new contact buffer would have entries for deleted points.

Would that be sufficient?
I created an issue to track progress on this, as I may not actively track the forums: https://github.com/bulletphysics/bullet3/issues/291
If the end result of the double buffer would make getting deleted manifolds as simple as iterating a vector and checking a simple flag / variable / characteristic, then yes it would be exactly like I'm looking for.
As I understand you need to tackle the problem of persistence first. (As it existed in Bullet 2.x). So I am gonna follow the progress of this.
lunkhound
Posts: 99
Joined: Thu Nov 21, 2013 8:57 pm

Re: My custom patch for collision callback events

Post by lunkhound »

N0vember wrote: Well I have a simple example from my own application. Just suppose you have a "perception" model to determine what a player sees in a scene. You have spheres representing the perceptions of a character colliding with the things it can detect. But you also want to raycasts for obstacles between the receptor and the things it perceives.
For things like that I'm doing a query on the broadphase (broadphase->aabbTest()) to collect a list of objects of interest. I would think that having perception spheres as collision shapes in your physics world would add a large number of contacts for the physics to keep track of and slow things down.
N0vember
Posts: 10
Joined: Sat Mar 06, 2010 6:39 pm

Re: My custom patch for collision callback events

Post by N0vember »

lunkhound wrote: For things like that I'm doing a query on the broadphase (broadphase->aabbTest()) to collect a list of objects of interest. I would think that having perception spheres as collision shapes in your physics world would add a large number of contacts for the physics to keep track of and slow things down.
Yes, which is why I made a separate collision world, it doesn't interferes with the "physics" of my world if there were any (because for now I don't need them. I don't even have a btDynamicsWorld). I won't go into to much length, but I need the spheres, and bullet (SphereSphere algorithm) is better than me at colliding spheres efficiently :)
That is why I was saying earlier that Bullet should satisfy the basic needs of people using just the Collision component. I think it's what makes it great, and useful to me. High efficiency dynamics-less collisions.
If this double-buffer GPU thing gets implemented it will be perfect.
Post Reply