diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 02304b3b8d..74b792e3c0 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -249,23 +249,47 @@ void PhysicsEngine::stepSimulation() { } void PhysicsEngine::computeCollisionEvents() { - // update all contacts + // update all contacts every frame int numManifolds = _collisionDispatcher->getNumManifolds(); for (int i = 0; i < numManifolds; ++i) { btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); if (contactManifold->getNumContacts() > 0) { + // TODO: require scripts to register interest in callbacks for specific objects + // so we can filter out most collision events right here. const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); + + if (!(objectA->isActive() || objectB->isActive())) { + // both objects are inactive so stop tracking this contact, + // which will eventually trigger a CONTACT_EVENT_TYPE_END + continue; + } void* a = objectA->getUserPointer(); void* b = objectB->getUserPointer(); if (a || b) { // the manifold has up to 4 distinct points, but only extract info from the first - _contactMap[ContactKey(a, b)].update(_numSubsteps, contactManifold->getContactPoint(0), _originOffset); + _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); } } } + // We harvest collision callbacks every few frames, which contributes the following effects: + // + // (1) There is a maximum collision callback rate per pair: substep_rate / SUBSTEPS_PER_COLLIION_FRAME + // (2) END/START cycles shorter than SUBSTEPS_PER_COLLIION_FRAME will be filtered out + // (3) There is variable lag between when the contact actually starts and when it is reported, + // up to SUBSTEPS_PER_COLLIION_FRAME * time_per_substep + // + const uint32_t SUBSTEPS_PER_COLLISION_FRAME = 2; + if (_numSubsteps - _numContactFrames * SUBSTEPS_PER_COLLISION_FRAME < SUBSTEPS_PER_COLLISION_FRAME) { + // we don't harvest collision callbacks every frame + // this sets a maximum callback-per-contact rate + // and also filters out END/START events that happen on shorter timescales + return; + } + + ++_numContactFrames; // scan known contacts and trigger events ContactMap::iterator contactItr = _contactMap.begin(); while (contactItr != _contactMap.end()) { @@ -289,7 +313,7 @@ void PhysicsEngine::computeCollisionEvents() { } // TODO: enable scripts to filter based on contact event type - ContactEventType type = contactItr->second.computeType(_numSubsteps); + ContactEventType type = contactItr->second.computeType(_numContactFrames); if (type == CONTACT_EVENT_TYPE_END) { ContactMap::iterator iterToDelete = contactItr; ++contactItr; diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 73a02607e8..d333eef010 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -110,6 +110,7 @@ private: EntityEditPacketSender* _entityPacketSender = NULL; ContactMap _contactMap; + uint32_t _numContactFrames = 0; }; #endif // hifi_PhysicsEngine_h