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:
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.