void BulletPhysics::BulletInternalTickCallback(btDynamicsWorld* world, btScalar timeStep) { // called after bullet sdk performs its internal step CB_ASSERT(world); CB_ASSERT(world->getWorldUserInfo()); BulletPhysics* bulletPhysics = static_cast<BulletPhysics*>(world->getWorldUserInfo()); CollisionPairs currentTickCollisionPairs; // look at all existing collisions btDispatcher* dispatcher = world->getDispatcher(); const int numManifolds = dispatcher->getNumManifolds(); for (int i = 0; i < numManifolds; i++) { // get the manifold which is the data corresponding to a contact point between two colliders const btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i); CB_ASSERT(manifold); // get the colliding bodies const btRigidBody* body0 = static_cast<const btRigidBody *>(manifold->getBody0()); const btRigidBody* body1 = static_cast<const btRigidBody *>(manifold->getBody1()); // swap them if need be const bool swapped = body0 > body1; const btRigidBody* sortedBody0 = swapped ? body1 : body0; const btRigidBody* sortedBody1 = swapped ? body0 : body1; // insert the collision pair into the set const CollisionPair pair = std::make_pair(sortedBody0, sortedBody1); currentTickCollisionPairs.insert(pair); // if this is a new contact, send an event if (bulletPhysics->m_PreviousTickCollisionPairs.find(pair) == bulletPhysics->m_PreviousTickCollisionPairs.end()) { bulletPhysics->SendCollisionPairAddEvent(manifold, body0, body1); } } CollisionPairs removedCollisionPairs; // use set difference to see which collisions existed last tick but are no longer colliding std::set_difference(bulletPhysics->m_PreviousTickCollisionPairs.begin(), bulletPhysics->m_PreviousTickCollisionPairs.end(), currentTickCollisionPairs.begin(), currentTickCollisionPairs.end(), std::inserter(removedCollisionPairs, removedCollisionPairs.begin())); // send collision exit events for (auto it = removedCollisionPairs.begin(); it != removedCollisionPairs.end(); ++it) { const btRigidBody* body0 = it->first; const btRigidBody* body1 = it->second; bulletPhysics->SendCollisionPairRemoveEvent(body0, body1); } // update the collision pairs bulletPhysics->m_PreviousTickCollisionPairs = currentTickCollisionPairs; }
void BulletPhysics::RemoveCollisionObject(btCollisionObject* obj) { // remove a collision object from the physics world m_DynamicsWorld->removeCollisionObject(obj); // remove the pointer from the collision contacts list for (auto it = m_PreviousTickCollisionPairs.begin(); it != m_PreviousTickCollisionPairs.end(); ) { // step the iterator by 1 auto next = it; ++next; // remove the object from any currently happening collision if (it->first == obj || it->second == obj) { SendCollisionPairRemoveEvent(it->first, it->second); m_PreviousTickCollisionPairs.erase(it); } it = next; } // if the object was a rigid body if (btRigidBody* body = btRigidBody::upcast(obj)) { // delete the components of the body delete body->getMotionState(); delete body->getCollisionShape(); delete body->getUserPointer(); for (int i = body->getNumConstraintRefs() - 1; i >= 0; i--) { btTypedConstraint* constraint = body->getConstraintRef(i); m_DynamicsWorld->removeConstraint(constraint); delete constraint; } } delete obj; }
void BulletOpenGLApplication::CheckForCollisionEvents() { // keep a list of the collision pairs we // found during the current update CollisionPairs pairsThisUpdate; // iterate through all of the manifolds in the dispatcher for (int i = 0; i < m_pDispatcher->getNumManifolds(); ++i) { // get the manifold btPersistentManifold* pManifold = m_pDispatcher->getManifoldByIndexInternal(i); // ignore manifolds that have // no contact points. if (pManifold->getNumContacts() > 0) { // get the two rigid bodies involved in the collision const btRigidBody* pBody0 = static_cast<const btRigidBody*>(pManifold->getBody0()); const btRigidBody* pBody1 = static_cast<const btRigidBody*>(pManifold->getBody1()); // always create the pair in a predictable order // (use the pointer value..) bool const swapped = pBody0 > pBody1; const btRigidBody* pSortedBodyA = swapped ? pBody1 : pBody0; const btRigidBody* pSortedBodyB = swapped ? pBody0 : pBody1; // create the pair CollisionPair thisPair = std::make_pair(pSortedBodyA, pSortedBodyB); // insert the pair into the current list pairsThisUpdate.insert(thisPair); // if this pair doesn't exist in the list // from the previous update, it is a new // pair and we must send a collision event if (m_pairsLastUpdate.find(thisPair) == m_pairsLastUpdate.end()) { CollisionEvent((btRigidBody*)pBody0, (btRigidBody*)pBody1); } } } // create another list for pairs that // were removed this update CollisionPairs removedPairs; // this handy function gets the difference beween // two sets. It takes the difference between // collision pairs from the last update, and this // update and pushes them into the removed pairs list std::set_difference( m_pairsLastUpdate.begin(), m_pairsLastUpdate.end(), pairsThisUpdate.begin(), pairsThisUpdate.end(), std::inserter(removedPairs, removedPairs.begin())); // iterate through all of the removed pairs // sending separation events for them for (CollisionPairs::const_iterator iter = removedPairs.begin(); iter != removedPairs.end(); ++iter) { SeparationEvent((btRigidBody*)iter->first, (btRigidBody*)iter->second); } // in the next iteration we'll want to // compare against the pairs we found // in this iteration m_pairsLastUpdate = pairsThisUpdate; }
void BulletPhysicsManager::BulletInternalTickCallback( btDynamicsWorld * const world, btScalar const timeStep ) { assert( world ); assert( world->getWorldUserInfo() ); BulletPhysicsManager * const bulletPhysics = static_cast<BulletPhysicsManager*>( world->getWorldUserInfo() ); // TODO - iterating through all physics components probably isn't the fastest way to handle this... for(std::vector<GameObject*>::iterator it = bulletPhysics->physicsObjects.begin(); it != bulletPhysics->physicsObjects.end(); ++it) { GameObject* gameObject = (*it); Dynamics* rigidBodyComponent = gameObject->getDynamics(); if(rigidBodyComponent != NULL) { btRigidBody* rigidBody = dynamic_cast<BulletDynamics*>(rigidBodyComponent)->rigidBody; float maxVelocity = rigidBodyComponent->getMaxVelocity(); if(maxVelocity >= 0.0f) { btVector3 velocity = rigidBody->getLinearVelocity(); btScalar speed = velocity.length(); if(speed > maxVelocity) { velocity *= maxVelocity/speed; rigidBody->setLinearVelocity(velocity); } } } } bulletPhysics->currentTickCollisionPairs.clear(); // look at all existing contacts btDispatcher * const dispatcher = world->getDispatcher(); for ( int manifoldIdx=0; manifoldIdx<dispatcher->getNumManifolds(); ++manifoldIdx ) { // get the "manifold", which is the set of data corresponding to a contact point // between two physics objects btPersistentManifold const * const manifold = dispatcher->getManifoldByIndexInternal( manifoldIdx ); assert( manifold ); if(manifold->getNumContacts() > 0) { btCollisionObject const * const body0 = static_cast<btCollisionObject const *>(manifold->getBody0()); btCollisionObject const * const body1 = static_cast<btCollisionObject const *>(manifold->getBody1()); // always create the pair in a predictable order bool const swapped = body0 > body1; btCollisionObject const * const sortedBodyA = swapped ? body1 : body0; btCollisionObject const * const sortedBodyB = swapped ? body0 : body1; CollisionPair const thisPair = std::make_pair( sortedBodyA, sortedBodyB ); // TODO - why are there duplicate collisions? Probably shouldn't have to check if these objects have already collided this tick if ( bulletPhysics->previousTickCollisionPairs.find( thisPair ) == bulletPhysics->previousTickCollisionPairs.end() && bulletPhysics->currentTickCollisionPairs.find( thisPair ) == bulletPhysics->currentTickCollisionPairs.end()) { // this needs to happen before sending the collision add event, since we might remove one of the game objects // as part of handling the event bulletPhysics->currentTickCollisionPairs.insert( thisPair ); // this is a new contact, which wasn't in our list before. send an event to the game. bulletPhysics->SendCollisionPairAddEvent( manifold, body0, body1 ); } else { bulletPhysics->currentTickCollisionPairs.insert( thisPair ); } } } CollisionPairs removedCollisionPairs; // use the STL set difference function to find collision pairs that existed during the previous tick but not any more std::set_difference( bulletPhysics->previousTickCollisionPairs.begin(), bulletPhysics->previousTickCollisionPairs.end(), bulletPhysics->currentTickCollisionPairs.begin(), bulletPhysics->currentTickCollisionPairs.end(), std::inserter( removedCollisionPairs, removedCollisionPairs.begin() ) ); for ( CollisionPairs::const_iterator it = removedCollisionPairs.begin(), end = removedCollisionPairs.end(); it != end; ++it ) { btCollisionObject const * const body0 = it->first; btCollisionObject const * const body1 = it->second; bulletPhysics->SendCollisionPairRemoveEvent( body0, body1 ); } // the current tick becomes the previous tick. this is the way of all things. bulletPhysics->previousTickCollisionPairs = bulletPhysics->currentTickCollisionPairs; }