I'm researching collision detection and I'd like to replace the collision detection engine in Bullet with a variety of alternatives. Currently, I'm investigating SOLID (http://www.dtecta.com/) as a replacement.
Based on the advice in a previous post (http://www.bulletphysics.com/Bullet/php ... 61&p=10234), I've derived a custom class from btDiscreteDynamicsWorld and I've overridden the performDiscreteCollisionDetection() method. I've successfully replaced the broad phase, but I'm having difficulty with the narrow phase. I realise that the collision data needs to be placed in btPersistentManifold objects, but I'm unable to determine how these work. How do I create them? And how do I add them to the list of objects to be processed?
The narrow phase SOLID function I'm using is DT_GetPenDepth(), which returns two contact points that I think I can use with the btPersistentManifold.
Replacing narrow phase collision detection
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Re: Replacing narrow phase collision detection
Collision detection is basically over 90% of Bullet, so you won't use much of Bullet if you replace it. The Bullet collision detection system used SOLID as an inspiration, adding improvements in most areas.
The result of a single closest point/penetration query is usually a point on object A, point on object B, contact normal (connecting both points) and distance (between those two points, with negative distance == penetration).
btPersistentManifold is a contact point cache that collects and updates multiple contact points. Rigid body simulation becomes instable for most collision shapes when using only a single point, so using the btPersistentManifold contact cache is recommended. Just add the points using btPersistentManifold::addManifoldPoint. A btManifoldPoint contains the point on A and point on B in local space and world space, and contact normal in world space (pointing from point B towards A) and distance. Each frame, make sure to update all contact manifolds using btPersistentManifold::refreshContactPoints.
Note that Bullet 2.74 can produce multiple contact points at a time, using a perturbation method.
Hope this helps,
Erwin
You could try to create a btCollisionDispatcher, and only use it to create btPersistentManifold objects (use getNewManifold and releaseManifold).console wrote:Based on the advice in a previous post (http://www.bulletphysics.com/Bullet/php ... 61&p=10234), I've derived a custom class from btDiscreteDynamicsWorld and I've overridden the performDiscreteCollisionDetection() method. I've successfully replaced the broad phase, but I'm having difficulty with the narrow phase. I realise that the collision data needs to be placed in btPersistentManifold objects, but I'm unable to determine how these work. How do I create them? And how do I add them to the list of objects to be processed?
The result of a single closest point/penetration query is usually a point on object A, point on object B, contact normal (connecting both points) and distance (between those two points, with negative distance == penetration).
btPersistentManifold is a contact point cache that collects and updates multiple contact points. Rigid body simulation becomes instable for most collision shapes when using only a single point, so using the btPersistentManifold contact cache is recommended. Just add the points using btPersistentManifold::addManifoldPoint. A btManifoldPoint contains the point on A and point on B in local space and world space, and contact normal in world space (pointing from point B towards A) and distance. Each frame, make sure to update all contact manifolds using btPersistentManifold::refreshContactPoints.
Note that Bullet 2.74 can produce multiple contact points at a time, using a perturbation method.
Hope this helps,
Erwin
-
- Posts: 18
- Joined: Thu Sep 04, 2008 10:25 am
Re: Replacing narrow phase collision detection
Thanks for the advice. I understand that collision detection accounts for the majority of Bullet and that there is typically no benefit to replacing it, but I need to be able to compare different collision detection algorithms for my research. And I need a physics engine to simulate the objects, so I'm using Bullet.
I followed your suggestions and created the following collision detection code, in my class inherited from btDiscreteDynamicsWorld:
A note on the code: _objects stores a list of SOLID objects. Since SOLID cannot represent a Bullet compound object, I use a 2D array with a list of objects for each Bullet object.
This code doesn't seem to do anything as all of my objects pass through one another. I am sure the problem is in my narrow phase as my broad phase works correctly when used with Bullet's narrow phase. Could you provide any advice as to what I may be doing wrong?
I followed your suggestions and created the following collision detection code, in my class inherited from btDiscreteDynamicsWorld:
Code: Select all
for (int i = 0; i < m_dispatcher1->getNumManifolds(); i++) {
const btRigidBody* body0 = reinterpret_cast<const btRigidBody*>(m_dispatcher1->getManifoldByIndexInternal(i)->getBody0());
const btRigidBody* body1 = reinterpret_cast<const btRigidBody*>(m_dispatcher1->getManifoldByIndexInternal(i)->getBody1());
m_dispatcher1->getManifoldByIndexInternal(i)->refreshContactPoints(body0->getWorldTransform(), body1->getWorldTransform());
}
btBroadphasePairArray& overlapping = m_broadphasePairCache->getOverlappingPairCache()->getOverlappingPairArray();
for (int i = 0; i < overlapping.size(); i++) {
btRigidBody* object0 = reinterpret_cast<btRigidBody*>(overlapping[i].m_pProxy0->m_clientObject);
btRigidBody* object1 = reinterpret_cast<btRigidBody*>(overlapping[i].m_pProxy1->m_clientObject);
const unsigned int pointer0 = reinterpret_cast<unsigned int>(object0->getUserPointer());
const unsigned int pointer1 = reinterpret_cast<unsigned int>(object1->getUserPointer());
DT_Vector3 point0;
DT_Vector3 point1;
for (unsigned int j = 0; j < _objects[pointer0].size(); j++) {
for (unsigned int k = 0; k < _objects[pointer1].size(); k++) {
const ScalarType distance = DT_GetClosestPair(_objects[pointer0][j].get(), _objects[pointer0][k].get(), point0, point1);
btPersistentManifold* manifold = m_dispatcher1->getNewManifold(reinterpret_cast<void*>(object0), reinterpret_cast<void*>(object1));
const btVector3 pointA(point0[0], point0[1], point0[2]);
const btVector3 pointB(point1[0], point1[1], point1[2]);
const btVector3 normal(pointB - pointA);
manifold->addManifoldPoint(btManifoldPoint(pointA, pointB, normal, distance));
}
}
}
This code doesn't seem to do anything as all of my objects pass through one another. I am sure the problem is in my narrow phase as my broad phase works correctly when used with Bullet's narrow phase. Could you provide any advice as to what I may be doing wrong?
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Re: Replacing narrow phase collision detection
Is addManifoldPoint ever called?console wrote: This code doesn't seem to do anything as all of my objects pass through one another. I am sure the problem is in my narrow phase as my broad phase works correctly when used with Bullet's narrow phase. Could you provide any advice as to what I may be doing wrong?
There are several ways to hookup narrowphase collision algorithms.
The recommended way, that uses a lot of Bullet collision infrastructure, is to use register your custom collision algorithm, using a derived version of btDefaultCollisionConfiguration. This way, all datastructures are maintained properly.
Another way is to avoid all existing Bullet collision infrastructure: You could call SOLID dtTest, and add points during the callback (instead of calling it manually for each pair).
Please let us know how you get on,
Erwin
-
- Posts: 18
- Joined: Thu Sep 04, 2008 10:25 am
Re: Replacing narrow phase collision detection
Thanks again for your helpful feedback. Unfortunately, your recommended suggestion doesn't really work for my scenario as I want to be able to time SOLID with no intervention from Bullet. However, I followed your second suggestion (to use DT_Test) and I've implemented the following code:
addManifoldPoint is correctly called when a collision occurs and pointA and pointB are correct as they are almost the same as the ones generated when I use Bullet. However, the normal isn't the same as Bullet -- it's completely different. I get (-7.8945e-5, -1.0, -3.0847318e-7) with Bullet but (3.0517578e-5, 0.51364136, 3.0517578e-5) with SOLID.
I'm using SOLID's DT_DEPTH_RESPONSE as this is the only response type to generate a normal.
Any information as to why the normals differ would be appreciated.
Code: Select all
void MyClass::performDiscreteCollisionDetection() {
for (int i = 0; i < m_dispatcher1->getNumManifolds(); i++) {
const btRigidBody* body0 = reinterpret_cast<const btRigidBody*>(m_dispatcher1->getManifoldByIndexInternal(i)->getBody0());
const btRigidBody* body1 = reinterpret_cast<const btRigidBody*>(m_dispatcher1->getManifoldByIndexInternal(i)->getBody1());
m_dispatcher1->getManifoldByIndexInternal(i)->refreshContactPoints(body0->getWorldTransform(), body1->getWorldTransform());
}
const btCollisionObjectArray& objects = getCollisionObjectArray();
for (unsigned int i = 1; i < _objects.size(); ++i) {
const btTransform& transform = objects[i]->getWorldTransform();
const btVector3& origin = transform.getOrigin();
const btQuaternion& rotation = transform.getRotation();
const DT_Vector3 position = {origin[0], origin[1], origin[2]};
const DT_Quaternion orientation = {rotation[0], rotation[1], rotation[2], rotation[3]};
DT_SetPosition(_objects[i][0], position);
DT_SetOrientation(_objects[i][0], orientation);
}
DT_Test(_scene, _responseTable);
}
DT_Bool MyClass::CollisionCallback(void* clientData, void* clientObject0, void* clientObject1, const DT_CollData* collData) {
MyClass* pointer = reinterpret_cast<MyClass*>(clientData);
unsigned int i = reinterpret_cast<unsigned int>(clientObject0);
unsigned int j = reinterpret_cast<unsigned int>(clientObject1);
if (i != j) {
if (i > j) {
std::swap(i, j);
}
btPersistentManifold* manifold = pointer->m_dispatcher1->getNewManifold(reinterpret_cast<void*>(pointer->getCollisionObjectArray()[i]), reinterpret_cast<void*>(pointer->getCollisionObjectArray()[j]));
const btVector3 pointA(collData->point1[0], collData->point1[1], collData->point1[2]);
btVector3 pointB(collData->point2[0], collData->point2[1], collData->point2[2]);
pointB -= pointer->getCollisionObjectArray()[j]->getWorldTransform().getOrigin();
const btVector3 normal(collData->normal[0], collData->normal[1], collData->normal[2]);
manifold->addManifoldPoint(btManifoldPoint(pointA, pointB, normal, 0.0));
}
return DT_CONTINUE;
}
I'm using SOLID's DT_DEPTH_RESPONSE as this is the only response type to generate a normal.
Any information as to why the normals differ would be appreciated.
-
- Posts: 4
- Joined: Thu Oct 15, 2009 10:31 am
Re: Replacing narrow phase collision detection
Hi,
I am also attempting to replace the narrow phase completely, I wish to resolve all contact points in one function call, and not use the Bullet infrastructure. I have decided that I need to override the performDiscreteCollisionDetection() function as above, and then simply manually add points to a persistent manifold. I don't understand exactly how this works though. Are the manifolds created in the narrow phase, or is a manifold created in the broadphase upon finding an overlapping pair? Do I need to clear all the manifolds after each simulation step? Could someone explain in more detail how I create the manifolds, where I should create them, how to update them etc?
I'm very lost on this and I need to get this part done for a project very soon. Please help!
Thanks very much in advance.
Mike
I am also attempting to replace the narrow phase completely, I wish to resolve all contact points in one function call, and not use the Bullet infrastructure. I have decided that I need to override the performDiscreteCollisionDetection() function as above, and then simply manually add points to a persistent manifold. I don't understand exactly how this works though. Are the manifolds created in the narrow phase, or is a manifold created in the broadphase upon finding an overlapping pair? Do I need to clear all the manifolds after each simulation step? Could someone explain in more detail how I create the manifolds, where I should create them, how to update them etc?
I'm very lost on this and I need to get this part done for a project very soon. Please help!
Thanks very much in advance.
Mike