Now, it's entirely possible I'm not using ghost objects correctly, or I'm doing something else wonky.
So, here's how I stitched it together:
1) My objects have both a btRigidBody and a btPairCachingGhostObject; I manually sync the transform of the ghost object to match the rigid body in my motion state subclass.
2) After each step, objects with a ghost object run code derived from the wiki ghost object example (http://www.bulletphysics.com/mediawiki- ... d_Triggers) -- the collisions get forwarded as needed -- it works as expected.
3) Raycasts to objects with ghost objects don't work any more.
Here's some code. Note: I'm implementing bullet behind an abstract general purpose physics interface since I currently use ODE and am evaluating bullet.
First, here's where I create the ghost object:
Code: Select all
void
BulletKinematicBody::setNotifyOnContact( bool noc )
{
KinematicBody::setNotifyOnContact( noc );
if ( notifyOnContact() )
{
_ghost = new btPairCachingGhostObject();
_ghost->setCollisionShape( bulletShape() );
_ghost->setUserPointer( this );
_ghost->setCollisionFlags( btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE );
_dynamicsWorld->addCollisionObject( _ghost );
}
else if ( _ghost )
{
_dynamicsWorld->removeCollisionObject( _ghost );
delete _ghost;
_ghost = NULL;
}
becomeSteppingIfNecessary();
}
Code: Select all
void
BulletKinematicBody::checkForContacts( void )
{
//
// Adapted from Bullet wiki:
// http://www.bulletphysics.com/mediawiki-1.5.8/index.php?title=Collision_Callbacks_and_Triggers
//
btManifoldArray manifoldArray;
btBroadphasePairArray& pairArray = _ghost->getOverlappingPairCache()->getOverlappingPairArray();
int numPairs = pairArray.size();
for ( int i=0; i < numPairs; i++ )
{
manifoldArray.clear();
const btBroadphasePair& pair = pairArray[i];
//unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache:
btBroadphasePair* collisionPair = _dynamicsWorld->getPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
if (!collisionPair)
continue;
if (collisionPair->m_algorithm)
collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
for ( int j = 0; j < manifoldArray.size(); j++ )
{
btPersistentManifold* manifold = manifoldArray[j];
BulletKinematicBody *kb0 = BulletKinematicBody::kinematicBodyForBulletCollisionObject( static_cast<btCollisionObject*>(manifold->getBody0()) );
BulletKinematicBody *kb1 = BulletKinematicBody::kinematicBodyForBulletCollisionObject( static_cast<btCollisionObject*>(manifold->getBody1()) );
if ( kb0 == this && kb1 == this ) continue;
BulletKinematicBody *other = kb0 == this ? kb1 : kb0;
for ( int p = 0; p < manifold->getNumContacts(); p++ )
{
const btManifoldPoint &pt = manifold->getContactPoint(p);
if ( pt.getDistance() < 0.f )
{
contact( other->kinematicBodyID(), BTS( pt.getPositionWorldOnB() ), BTS( pt.m_normalWorldOnB ), -pt.getDistance() );
}
}
}
}
}
Code: Select all
virtual void setWorldTransform( const btTransform& centerOfMassWorldTrans )
{
btDefaultMotionState::setWorldTransform( centerOfMassWorldTrans );
mat4 m;
this->m_graphicsWorldTrans.getOpenGLMatrix( m.mat );
_body->_transform = m;
_body->updateAABB();
_body->transformChanged.run( _body->kinematicBodyID(), m );
if ( _body->_ghost )
{
_body->_ghost->setWorldTransform( centerOfMassWorldTrans );
}
}