Computing Minimum De-Penetration Between Two Colliders
Posted: Tue Jun 29, 2021 5:29 pm
Hello, I'd like to compute the minimum translation needed to de-penetrate two collision bodies. I essentially want to port Unity's Physics.ComputePenetration to a roughly equivalent static function using Bullet. Here's my implementation:
Is this the right way to do this in Bullet? I was looking at btComputeMprPenetration for example, but that seemed too low-level, and I was wondering if functions like that already get called as part of collision detection itself, or something... I'm basically an idiot when it comes to physics, so help would be greatly appreciated. I just want minimum de-penetration distance, and to my mind the function above calculates it by finding the maximum penetration distance... unless I'm totally misunderstanding something here.
I should clarify and say this would be used as a helper function for a kinematic character controller using a btPairCachingGhostObject. The function above is just a factored-out version of the inner-most block of the recoverFromPenetration function in Bullet's existing kinematic character controller example.
Code: Select all
static bool physicsComputePenetration( btCollisionWorld* collisionWorld,
btBroadphasePair* collisionPair,
btCollisionObject* penetrator,
btVector3* minDepenetrationDirection,
btScalar* minDepenetrationDistance )
{
btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject);
btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);
if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse())) {
Ogre::LogManager::getSingleton().logMessage("No contact");
return false;
}
Ogre::LogManager::getSingleton().logMessage("Contact happened");
if (!needsCollision(obj0, obj1)) {
Ogre::LogManager::getSingleton().logMessage("No collision");
return false;
}
Ogre::LogManager::getSingleton().logMessage("Collision happened");
btManifoldArray manifoldArray;
if (collisionPair->m_algorithm)
collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
Ogre::LogManager::getSingleton().logMessage("Num manifolds in collision = "
+ Ogre::StringConverter::toString(manifoldArray.size()));
btScalar maxPenetration = btScalar(0.0); // TODO: Why is this 0 ???
bool isPenetrating = false;
for (int j = 0; j < manifoldArray.size(); j++)
{
btPersistentManifold* manifold = manifoldArray[j];
btScalar directionSign = manifold->getBody0() == penetrator ? btScalar(-1.0) : btScalar(1.0);
Ogre::LogManager::getSingleton().logMessage(
"Num Contact Points in Manifold "
+ Ogre::StringConverter::toString(j)
+ " = "
+ Ogre::StringConverter::toString(manifold->getNumContacts())
);
for (int p = 0; p < manifold->getNumContacts(); p++)
{
const btManifoldPoint& pt = manifold->getContactPoint(p);
btScalar dist = pt.getDistance();
Ogre::LogManager::getSingleton().logMessage(
"Contact Point "
+ Ogre::StringConverter::toString(p) + "'s "
+ " Distance = "
+ Ogre::StringConverter::toString(dist)
);
if (dist < maxPenetration)
{
maxPenetration = dist;
*minDepenetrationDirection = pt.m_normalWorldOnB * directionSign * dist;
*minDepenetrationDistance = minDepenetrationDirection->length();
*minDepenetrationDirection = minDepenetrationDirection->normalized();
isPenetrating = true;
}
}
}
return isPenetrating;
}
I should clarify and say this would be used as a helper function for a kinematic character controller using a btPairCachingGhostObject. The function above is just a factored-out version of the inner-most block of the recoverFromPenetration function in Bullet's existing kinematic character controller example.