From 549e3fac5f528573f62b22bd774cfec6e8b45255 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 20 Jan 2015 10:45:58 -0800 Subject: [PATCH 1/8] store backpointer to MotionState in btRigidBody --- libraries/physics/src/ObjectMotionState.cpp | 13 +++++++++++++ libraries/physics/src/ObjectMotionState.h | 7 +++++-- libraries/physics/src/PhysicsEngine.cpp | 12 ++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index f4997b679c..cab36b8370 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -170,3 +170,16 @@ void ObjectMotionState::removeKinematicController() { _kinematicController = NULL; } } + +void ObjectMotionState::setRigidBody(btRigidBody* body) { + // give the body a (void*) back-pointer to this ObjectMotionState + if (_body != body) { + if (_body) { + _body->setUserPointer(NULL); + } + _body = body; + if (_body) { + _body->setUserPointer(this); + } + } +} diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 4d454554cb..0620d030b2 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -88,9 +88,13 @@ public: virtual void addKinematicController() = 0; virtual void removeKinematicController(); + btRigidBody* getRigidBody() const { return _body; } + friend class PhysicsEngine; protected: - // TODO: move these materials properties to EntityItem + void setRigidBody(btRigidBody* body); + + // TODO: move these materials properties outside of ObjectMotionState float _friction; float _restitution; float _linearDamping; @@ -98,7 +102,6 @@ protected: MotionType _motionType; - // _body has NO setters -- it is only changed by PhysicsEngine btRigidBody* _body; bool _sentMoving; // true if last update was moving diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 90fd6c65cd..ca64184bd7 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -132,7 +132,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { ObjectMotionState* motionState = *stateItr; uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; - btRigidBody* body = motionState->_body; + btRigidBody* body = motionState->getRigidBody(); if (body) { if (flags & HARD_DIRTY_PHYSICS_FLAGS) { // a HARD update requires the body be pulled out of physics engine, changed, then reinserted @@ -258,7 +258,7 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); body->updateInertiaTensor(); - motionState->_body = body; + motionState->setRigidBody(body); motionState->addKinematicController(); const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec @@ -270,7 +270,7 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) { shape->calculateLocalInertia(mass, inertia); body = new btRigidBody(mass, motionState, shape, inertia); body->updateInertiaTensor(); - motionState->_body = body; + motionState->setRigidBody(body); motionState->updateObjectVelocities(); // NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds. // (the 2 seconds is determined by: static btRigidBody::gDeactivationTime @@ -284,7 +284,7 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) { body = new btRigidBody(mass, motionState, shape, inertia); body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); body->updateInertiaTensor(); - motionState->_body = body; + motionState->setRigidBody(body); break; } } @@ -301,7 +301,7 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) { bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { assert(motionState); - btRigidBody* body = motionState->_body; + btRigidBody* body = motionState->getRigidBody(); if (body) { const btCollisionShape* shape = body->getCollisionShape(); ShapeInfo shapeInfo; @@ -309,7 +309,7 @@ bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { _dynamicsWorld->removeRigidBody(body); _shapeManager.releaseShape(shapeInfo); delete body; - motionState->_body = NULL; + motionState->setRigidBody(NULL); motionState->removeKinematicController(); return true; } From 0154c613d0af2f8c806e70026b7c21dc41788943 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 20 Jan 2015 11:02:48 -0800 Subject: [PATCH 2/8] change FrameCount to NumSubsteps for more accuracy --- libraries/physics/src/KinematicController.cpp | 4 ++-- libraries/physics/src/KinematicController.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 24 ++++++++++++------- libraries/physics/src/PhysicsEngine.h | 4 +++- .../src/SimpleEntityKinematicController.cpp | 6 ++--- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/libraries/physics/src/KinematicController.cpp b/libraries/physics/src/KinematicController.cpp index abcf669694..354b285bc1 100644 --- a/libraries/physics/src/KinematicController.cpp +++ b/libraries/physics/src/KinematicController.cpp @@ -13,10 +13,10 @@ #include "PhysicsEngine.h" KinematicController::KinematicController() { - _lastFrame = PhysicsEngine::getFrameCount(); + _lastSubstep = PhysicsEngine::getNumSubsteps(); } void KinematicController::start() { _enabled = true; - _lastFrame = PhysicsEngine::getFrameCount(); + _lastSubstep = PhysicsEngine::getNumSubsteps(); } diff --git a/libraries/physics/src/KinematicController.h b/libraries/physics/src/KinematicController.h index 382d4cbfd9..60b8548607 100644 --- a/libraries/physics/src/KinematicController.h +++ b/libraries/physics/src/KinematicController.h @@ -30,7 +30,7 @@ public: protected: bool _enabled = false; - uint32_t _lastFrame; + uint32_t _lastSubstep; }; #endif // hifi_KinematicController_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index ca64184bd7..af4a49aefe 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -13,11 +13,11 @@ #include "ShapeInfoUtil.h" #include "ThreadSafeDynamicsWorld.h" -static uint32_t _frameCount; +static uint32_t _numSubsteps; // static -uint32_t PhysicsEngine::getFrameCount() { - return _frameCount; +uint32_t PhysicsEngine::getNumSubsteps() { + return _numSubsteps; } PhysicsEngine::PhysicsEngine(const glm::vec3& offset) @@ -47,8 +47,8 @@ void PhysicsEngine::updateEntitiesInternal(const quint64& now) { ObjectMotionState* state = *stateItr; if (state->doesNotNeedToSendUpdate()) { stateItr = _outgoingPackets.erase(stateItr); - } else if (state->shouldSendUpdate(_frameCount)) { - state->sendUpdate(_entityPacketSender, _frameCount); + } else if (state->shouldSendUpdate(_numSubsteps)) { + state->sendUpdate(_entityPacketSender, _numSubsteps); ++stateItr; } else { ++stateItr; @@ -141,7 +141,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { } else if (flags) { // an EASY update does NOT require that the body be pulled out of physics engine // hence the MotionState has all the knowledge and authority to perform the update. - motionState->updateObjectEasy(flags, _frameCount); + motionState->updateObjectEasy(flags, _numSubsteps); } } @@ -216,8 +216,8 @@ void PhysicsEngine::stepSimulation() { float timeStep = btMin(dt, MAX_TIMESTEP); // This is step (2). - int numSubSteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); - _frameCount += (uint32_t)numSubSteps; + int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); + _numSubsteps += (uint32_t)numSubsteps; unlock(); // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. @@ -233,6 +233,12 @@ void PhysicsEngine::stepSimulation() { _dynamicsWorld->synchronizeMotionStates(); unlock(); _entityTree->unlock(); + + handleCollisionEvents(); +} + +void PhysicsEngine::handleCollisionEvents() { + } // Bullet collision flags are as follows: @@ -352,7 +358,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio } bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS; if (easyUpdate) { - motionState->updateObjectEasy(flags, _frameCount); + motionState->updateObjectEasy(flags, _numSubsteps); } // update the motion parameters diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index f37f12ea8d..7304f598e2 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -33,7 +33,7 @@ class ObjectMotionState; class PhysicsEngine : public EntitySimulation { public: - static uint32_t getFrameCount(); + static uint32_t getNumSubsteps(); PhysicsEngine(const glm::vec3& offset); @@ -51,6 +51,8 @@ public: void stepSimulation(); + void handleCollisionEvents(); + /// \param offset position of simulation origin in domain-frame void setOriginOffset(const glm::vec3& offset) { _originOffset = offset; } diff --git a/libraries/physics/src/SimpleEntityKinematicController.cpp b/libraries/physics/src/SimpleEntityKinematicController.cpp index 478ec1d12f..e834d4e91b 100644 --- a/libraries/physics/src/SimpleEntityKinematicController.cpp +++ b/libraries/physics/src/SimpleEntityKinematicController.cpp @@ -13,9 +13,9 @@ #include "SimpleEntityKinematicController.h" void SimpleEntityKinematicController:: stepForward() { - uint32_t frame = PhysicsEngine::getFrameCount(); - float dt = (frame - _lastFrame) * PHYSICS_ENGINE_FIXED_SUBSTEP; + uint32_t substep = PhysicsEngine::getNumSubsteps(); + float dt = (substep - _lastSubstep) * PHYSICS_ENGINE_FIXED_SUBSTEP; _entity->simulateSimpleKinematicMotion(dt); - _lastFrame = frame; + _lastSubstep = substep; } From 5da38834e2e762f387ecc23cd1c48bdd92e12020 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 20 Jan 2015 11:16:40 -0800 Subject: [PATCH 3/8] introduce notion of NumSteps vs NumSubsteps --- libraries/physics/src/PhysicsEngine.cpp | 12 +++--------- libraries/physics/src/PhysicsEngine.h | 23 +++++++++++------------ 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index af4a49aefe..870fdc6a9d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -21,13 +21,7 @@ uint32_t PhysicsEngine::getNumSubsteps() { } PhysicsEngine::PhysicsEngine(const glm::vec3& offset) - : _collisionConfig(NULL), - _collisionDispatcher(NULL), - _broadphaseFilter(NULL), - _constraintSolver(NULL), - _dynamicsWorld(NULL), - _originOffset(offset), - _entityPacketSender(NULL) { + : _originOffset(offset) { } PhysicsEngine::~PhysicsEngine() { @@ -234,10 +228,10 @@ void PhysicsEngine::stepSimulation() { unlock(); _entityTree->unlock(); - handleCollisionEvents(); + computeCollisionEvents(); } -void PhysicsEngine::handleCollisionEvents() { +void PhysicsEngine::computeCollisionEvents() { } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 7304f598e2..1f4efc6b06 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -33,8 +33,10 @@ class ObjectMotionState; class PhysicsEngine : public EntitySimulation { public: + // TODO: find a good way to make this a non-static method static uint32_t getNumSubsteps(); + PhysicsEngine() = delete; // prevent compiler from creating default ctor PhysicsEngine(const glm::vec3& offset); ~PhysicsEngine(); @@ -51,7 +53,7 @@ public: void stepSimulation(); - void handleCollisionEvents(); + void computeCollisionEvents(); /// \param offset position of simulation origin in domain-frame void setOriginOffset(const glm::vec3& offset) { _originOffset = offset; } @@ -70,22 +72,18 @@ public: /// process queue of changed from external sources void relayIncomingChangesToSimulation(); - /// \return duration of fixed simulation substep - float getFixedSubStep() const; - -protected: +private: void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); btClock _clock; - btDefaultCollisionConfiguration* _collisionConfig; - btCollisionDispatcher* _collisionDispatcher; - btBroadphaseInterface* _broadphaseFilter; - btSequentialImpulseConstraintSolver* _constraintSolver; - ThreadSafeDynamicsWorld* _dynamicsWorld; + btDefaultCollisionConfiguration* _collisionConfig = NULL; + btCollisionDispatcher* _collisionDispatcher = NULL; + btBroadphaseInterface* _broadphaseFilter = NULL; + btSequentialImpulseConstraintSolver* _constraintSolver = NULL; + ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; ShapeManager _shapeManager; -private: glm::vec3 _originOffset; // EntitySimulation stuff @@ -93,7 +91,8 @@ private: QSet _incomingChanges; // entities with pending physics changes by script or packet QSet _outgoingPackets; // MotionStates with pending changes that need to be sent over wire - EntityEditPacketSender* _entityPacketSender; + EntityEditPacketSender* _entityPacketSender = NULL; + uint32_t _numSteps = 0; // do not confuse with static _numSubsteps }; #endif // hifi_PhysicsEngine_h From 790d07d3461732094c87a928f3bc5eb0df7505cd Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 20 Jan 2015 14:18:10 -0800 Subject: [PATCH 4/8] track known contacts and generate collision events --- libraries/physics/src/ObjectMotionState.cpp | 8 ++++ libraries/physics/src/ObjectMotionState.h | 3 ++ libraries/physics/src/PhysicsEngine.cpp | 53 ++++++++++++++++++++- libraries/physics/src/PhysicsEngine.h | 17 ++++++- 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index cab36b8370..929ddab3e0 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -171,6 +171,14 @@ void ObjectMotionState::removeKinematicController() { } } +void ObjectMotionState::handleContactEvent(ContactEventType type, ObjectMotionState* otherState) { + if (type == CONTACT_TYPE_START) { + std::cout << "adebug start " << (void*)(this) << " vs " << (void*)(otherState) << std::endl; // adebug + } else if (type == CONTACT_TYPE_END) { + std::cout << "adebug end " << (void*)(this) << " vs " << (void*)(otherState) << std::endl; // adebug + } +} + void ObjectMotionState::setRigidBody(btRigidBody* body) { // give the body a (void*) back-pointer to this ObjectMotionState if (_body != body) { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 0620d030b2..2eda618d93 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -17,6 +17,7 @@ #include +#include "ContactInfo.h" #include "ShapeInfo.h" enum MotionType { @@ -88,6 +89,8 @@ public: virtual void addKinematicController() = 0; virtual void removeKinematicController(); + virtual void handleContactEvent(ContactEventType type, ObjectMotionState* otherState); + btRigidBody* getRigidBody() const { return _body; } friend class PhysicsEngine; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 870fdc6a9d..5a2881da71 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -154,6 +154,20 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { _incomingChanges.clear(); } +void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { + // trigger events for new/existing/old contacts + ContactMap::iterator contactItr = _contactMap.begin(); + while (contactItr != _contactMap.end()) { + if (contactItr->first._a == motionState || contactItr->first._b == motionState) { + ContactMap::iterator iterToDelete = contactItr; + ++contactItr; + _contactMap.erase(iterToDelete); + } else { + ++contactItr; + } + } +} + // virtual void PhysicsEngine::init(EntityEditPacketSender* packetSender) { // _entityTree should be set prior to the init() call @@ -232,7 +246,42 @@ void PhysicsEngine::stepSimulation() { } void PhysicsEngine::computeCollisionEvents() { - + // update all contacts + int numManifolds = _collisionDispatcher->getNumManifolds(); + for (int i = 0; i < numManifolds; ++i) { + btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); + if (contactManifold->getNumContacts() > 0) { + const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); + const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); + + void* a = objectA->getUserPointer(); + void* b = objectB->getUserPointer(); + if (a || b ) { + _contactMap[ContactKey(a, b)].update(_numSubsteps); + } + } + } + + // scan known contacts and trigger events + ContactMap::iterator contactItr = _contactMap.begin(); + while (contactItr != _contactMap.end()) { + ContactEventType type = contactItr->second.computeType(_numSubsteps); + ObjectMotionState* A = static_cast(contactItr->first._a); + ObjectMotionState* B = static_cast(contactItr->first._b); + if (A) { + A->handleContactEvent(type, B); + } + if (B) { + B->handleContactEvent(type, A); + } + if (type == CONTACT_TYPE_END) { + ContactMap::iterator iterToDelete = contactItr; + ++contactItr; + _contactMap.erase(iterToDelete); + } else { + ++contactItr; + } + } } // Bullet collision flags are as follows: @@ -311,6 +360,8 @@ bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { delete body; motionState->setRigidBody(NULL); motionState->removeKinematicController(); + + removeContacts(motionState); return true; } return false; diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 1f4efc6b06..9db9f5a33a 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -23,6 +23,7 @@ const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f; #include #include "BulletUtil.h" +#include "ContactInfo.h" #include "EntityMotionState.h" #include "ShapeManager.h" #include "ThreadSafeDynamicsWorld.h" @@ -31,6 +32,18 @@ const float HALF_SIMULATION_EXTENT = 512.0f; // meters class ObjectMotionState; +// simple class for keeping track of contacts +class ContactKey { +public: + ContactKey() = delete; + ContactKey(void* a, void* b) : _a(a), _b(b) {} + bool operator<(const ContactKey& other) const { return _a < other._a || (_a == other._a && _b < other._b); } + void* _a; + void* _b; +}; + +typedef std::map ContactMap; + class PhysicsEngine : public EntitySimulation { public: // TODO: find a good way to make this a non-static method @@ -73,6 +86,7 @@ public: void relayIncomingChangesToSimulation(); private: + void removeContacts(ObjectMotionState* motionState); void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); @@ -92,7 +106,8 @@ private: QSet _outgoingPackets; // MotionStates with pending changes that need to be sent over wire EntityEditPacketSender* _entityPacketSender = NULL; - uint32_t _numSteps = 0; // do not confuse with static _numSubsteps + + ContactMap _contactMap; }; #endif // hifi_PhysicsEngine_h From 86583f3f3f3cb1a5c714536bfdee9b848011c30a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 21 Jan 2015 11:27:32 -0800 Subject: [PATCH 5/8] physics collisions emit script collision events --- interface/src/Application.cpp | 21 +++-------- interface/src/Application.h | 1 - .../entities/src/EntityCollisionSystem.cpp | 13 ++----- .../entities/src/EntityCollisionSystem.h | 9 +---- libraries/entities/src/EntitySimulation.h | 7 +++- libraries/physics/src/ContactInfo.cpp | 29 +++++++++++++++ libraries/physics/src/ContactInfo.h | 37 +++++++++++++++++++ libraries/physics/src/EntityMotionState.cpp | 1 + libraries/physics/src/EntityMotionState.h | 2 + libraries/physics/src/ObjectMotionState.cpp | 8 ---- libraries/physics/src/ObjectMotionState.h | 11 +++++- libraries/physics/src/PhysicsEngine.cpp | 31 +++++++++++----- libraries/physics/src/PhysicsEngine.h | 2 + 13 files changed, 119 insertions(+), 53 deletions(-) create mode 100644 libraries/physics/src/ContactInfo.cpp create mode 100644 libraries/physics/src/ContactInfo.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4dfe8313c6..78fd0f943e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -192,7 +192,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _justStarted(true), _physicsEngine(glm::vec3(0.0f)), _entities(true, this, this), - _entityCollisionSystem(), _entityClipboardRenderer(false, this, this), _entityClipboard(), _viewFrustum(), @@ -1689,17 +1688,16 @@ void Application::init() { _entities.init(); _entities.setViewFrustum(getViewFrustum()); - EntityTree* entityTree = _entities.getTree(); - - _entityCollisionSystem.init(&_entityEditSender, entityTree, &_avatarManager); - - entityTree->setSimulation(&_entityCollisionSystem); + EntityTree* tree = _entities.getTree(); + _physicsEngine.setEntityTree(tree); + tree->setSimulation(&_physicsEngine); + _physicsEngine.init(&_entityEditSender); - connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithEntity, + connect(&_physicsEngine, &EntitySimulation::emitEntityCollisionWithEntity, ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity); // connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts - connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithEntity, + connect(&_physicsEngine, &EntitySimulation::emitEntityCollisionWithEntity, &_entities, &EntityTreeRenderer::entityCollisionWithEntity); // connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing @@ -1723,10 +1721,6 @@ void Application::init() { // save settings when avatar changes connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::bumpSettings); - EntityTree* tree = _entities.getTree(); - _physicsEngine.setEntityTree(tree); - tree->setSimulation(&_physicsEngine); - _physicsEngine.init(&_entityEditSender); // make sure our texture cache knows about window size changes DependencyManager::get()->associateWithWidget(glCanvas.data()); @@ -2047,9 +2041,6 @@ void Application::update(float deltaTime) { // NOTE: the _entities.update() call below will wait for lock // and will simulate entity motion (the EntityTree has been given an EntitySimulation). _entities.update(); // update the models... - // The _entityCollisionSystem.updateCollisions() call below merely tries for lock, - // and on failure it skips collision detection. - _entityCollisionSystem.updateCollisions(); // collide the entities... } { diff --git a/interface/src/Application.h b/interface/src/Application.h index a875c6b9fe..c79cf8a989 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -466,7 +466,6 @@ private: PhysicsEngine _physicsEngine; EntityTreeRenderer _entities; - EntityCollisionSystem _entityCollisionSystem; EntityTreeRenderer _entityClipboardRenderer; EntityTree _entityClipboard; diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 172850bc64..12d4e9e61e 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -62,14 +62,6 @@ void EntityCollisionSystem::checkEntity(EntityItem* entity) { updateCollisionWithAvatars(entity); } -void EntityCollisionSystem::emitGlobalEntityCollisionWithEntity(EntityItem* entityA, - EntityItem* entityB, const Collision& collision) { - - EntityItemID idA = entityA->getEntityItemID(); - EntityItemID idB = entityB->getEntityItemID(); - emit entityCollisionWithEntity(idA, idB, collision); -} - void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { if (entityA->getIgnoreForCollisions()) { @@ -193,7 +185,10 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { Collision collision; collision.penetration = penetration; collision.contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition()); - emitGlobalEntityCollisionWithEntity(entityA, entityB, collision); + + EntityItemID idA = entityA->getEntityItemID(); + EntityItemID idB = entityB->getEntityItemID(); + emitEntityCollisionWithEntity(idA, idB, collision); } } } diff --git a/libraries/entities/src/EntityCollisionSystem.h b/libraries/entities/src/EntityCollisionSystem.h index ce7d57bef7..d6cafd88f3 100644 --- a/libraries/entities/src/EntityCollisionSystem.h +++ b/libraries/entities/src/EntityCollisionSystem.h @@ -31,8 +31,7 @@ class AvatarData; class EntityEditPacketSender; class EntityTree; -class EntityCollisionSystem : public QObject, public SimpleEntitySimulation { -Q_OBJECT +class EntityCollisionSystem : public SimpleEntitySimulation { public: EntityCollisionSystem(); @@ -45,19 +44,13 @@ public: void checkEntity(EntityItem* Entity); void updateCollisionWithEntities(EntityItem* Entity); void updateCollisionWithAvatars(EntityItem* Entity); - void queueEntityPropertiesUpdate(EntityItem* Entity); - -signals: - void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); private: void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo); static bool updateOperation(OctreeElement* element, void* extraData); - void emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const Collision& penetration); EntityEditPacketSender* _packetSender; - AbstractAudioInterface* _audio; AvatarHashMap* _avatars; CollisionList _collisions; }; diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index dee6b1c43a..a7e18b67df 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -12,6 +12,7 @@ #ifndef hifi_EntitySimulation_h #define hifi_EntitySimulation_h +#include #include #include @@ -31,7 +32,8 @@ const int DIRTY_SIMULATION_FLAGS = EntityItem::DIRTY_LIFETIME | EntityItem::DIRTY_UPDATEABLE; -class EntitySimulation { +class EntitySimulation : public QObject { +Q_OBJECT public: EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL) { } virtual ~EntitySimulation() { setEntityTree(NULL); } @@ -61,6 +63,9 @@ public: EntityTree* getEntityTree() { return _entityTree; } +signals: + void emitEntityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); + protected: // These pure virtual methods are protected because they are not to be called will-nilly. The base class diff --git a/libraries/physics/src/ContactInfo.cpp b/libraries/physics/src/ContactInfo.cpp new file mode 100644 index 0000000000..71887b2dc9 --- /dev/null +++ b/libraries/physics/src/ContactInfo.cpp @@ -0,0 +1,29 @@ +// +// ContactEvent.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2015.01.20 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "BulletUtil.h" +#include "ContactInfo.h" + +void ContactInfo::update(uint32_t currentStep, btManifoldPoint& p, const glm::vec3& worldOffset) { + _lastStep = currentStep; + ++_numSteps; + contactPoint = bulletToGLM(p.m_positionWorldOnB) + worldOffset; + penetration = bulletToGLM(p.m_distance1 * p.m_normalWorldOnB); + // TODO: also report normal + //_normal = bulletToGLM(p.m_normalWorldOnB); +} + +ContactEventType ContactInfo::computeType(uint32_t thisStep) { + if (_lastStep != thisStep) { + return CONTACT_EVENT_TYPE_END; + } + return (_numSteps == 1) ? CONTACT_EVENT_TYPE_START : CONTACT_EVENT_TYPE_CONTINUE; +} diff --git a/libraries/physics/src/ContactInfo.h b/libraries/physics/src/ContactInfo.h new file mode 100644 index 0000000000..2c3c3a1e6f --- /dev/null +++ b/libraries/physics/src/ContactInfo.h @@ -0,0 +1,37 @@ +// +// ContactEvent.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2015.01.20 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ContactEvent_h +#define hifi_ContactEvent_h + +#include +#include + +#include "RegisteredMetaTypes.h" + +enum ContactEventType { + CONTACT_EVENT_TYPE_START, + CONTACT_EVENT_TYPE_CONTINUE, + CONTACT_EVENT_TYPE_END +}; + +class ContactInfo : public Collision +{ +public: + void update(uint32_t currentStep, btManifoldPoint& p, const glm::vec3& worldOffset); + ContactEventType computeType(uint32_t thisStep); +private: + uint32_t _lastStep = 0; + uint32_t _numSteps = 0; +}; + + +#endif // hifi_ContactEvent_h diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 9ff4a9d0e1..8b6fb1ea9f 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -33,6 +33,7 @@ void EntityMotionState::enqueueOutgoingEntity(EntityItem* entity) { EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) { + _type = MOTION_STATE_TYPE_ENTITY; assert(entity != NULL); } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index da06d46451..8eb639688a 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -60,6 +60,8 @@ public: uint32_t getIncomingDirtyFlags() const; void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } + EntityItem* getEntity() const { return _entity; } + protected: EntityItem* _entity; }; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 929ddab3e0..cab36b8370 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -171,14 +171,6 @@ void ObjectMotionState::removeKinematicController() { } } -void ObjectMotionState::handleContactEvent(ContactEventType type, ObjectMotionState* otherState) { - if (type == CONTACT_TYPE_START) { - std::cout << "adebug start " << (void*)(this) << " vs " << (void*)(otherState) << std::endl; // adebug - } else if (type == CONTACT_TYPE_END) { - std::cout << "adebug end " << (void*)(this) << " vs " << (void*)(otherState) << std::endl; // adebug - } -} - void ObjectMotionState::setRigidBody(btRigidBody* body) { // give the body a (void*) back-pointer to this ObjectMotionState if (_body != body) { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 2eda618d93..223664ceec 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -26,6 +26,12 @@ enum MotionType { MOTION_TYPE_KINEMATIC // keyframed motion }; +enum MotionStateType { + MOTION_STATE_TYPE_UNKNOWN, + MOTION_STATE_TYPE_ENTITY, + MOTION_STATE_TYPE_AVATAR +}; + // The update flags trigger two varieties of updates: "hard" which require the body to be pulled // and re-added to the physics engine and "easy" which just updates the body properties. const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE); @@ -59,6 +65,7 @@ public: virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0; virtual void updateObjectVelocities() = 0; + MotionStateType getType() const { return _type; } virtual MotionType getMotionType() const { return _motionType; } virtual void computeShapeInfo(ShapeInfo& info) = 0; @@ -89,14 +96,14 @@ public: virtual void addKinematicController() = 0; virtual void removeKinematicController(); - virtual void handleContactEvent(ContactEventType type, ObjectMotionState* otherState); - btRigidBody* getRigidBody() const { return _body; } friend class PhysicsEngine; protected: void setRigidBody(btRigidBody* body); + MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN; + // TODO: move these materials properties outside of ObjectMotionState float _friction; float _restitution; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 5a2881da71..ca14261c3b 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -256,8 +256,9 @@ void PhysicsEngine::computeCollisionEvents() { void* a = objectA->getUserPointer(); void* b = objectB->getUserPointer(); - if (a || b ) { - _contactMap[ContactKey(a, b)].update(_numSubsteps); + 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); } } } @@ -265,16 +266,28 @@ void PhysicsEngine::computeCollisionEvents() { // scan known contacts and trigger events ContactMap::iterator contactItr = _contactMap.begin(); while (contactItr != _contactMap.end()) { - ContactEventType type = contactItr->second.computeType(_numSubsteps); ObjectMotionState* A = static_cast(contactItr->first._a); ObjectMotionState* B = static_cast(contactItr->first._b); - if (A) { - A->handleContactEvent(type, B); + + // TODO: make triggering these events clean and efficient. The code at this context shouldn't + // have to figure out what kind of object (entity, avatar, etc) these are in order to properly + // emit a collision event. + if (A && A->getType() == MOTION_STATE_TYPE_ENTITY) { + EntityItemID idA = static_cast(A)->getEntity()->getEntityItemID(); + EntityItemID idB; + if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { + idB = static_cast(B)->getEntity()->getEntityItemID(); + } + emitEntityCollisionWithEntity(idA, idB, contactItr->second); + } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { + EntityItemID idA; + EntityItemID idB = static_cast(B)->getEntity()->getEntityItemID(); + emitEntityCollisionWithEntity(idA, idB, contactItr->second); } - if (B) { - B->handleContactEvent(type, A); - } - if (type == CONTACT_TYPE_END) { + + // TODO: enable scripts to filter based on contact event type + ContactEventType type = contactItr->second.computeType(_numSubsteps); + if (type == CONTACT_EVENT_TYPE_END) { ContactMap::iterator iterToDelete = contactItr; ++contactItr; _contactMap.erase(iterToDelete); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 9db9f5a33a..fdd4107421 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -38,11 +38,13 @@ public: ContactKey() = delete; ContactKey(void* a, void* b) : _a(a), _b(b) {} bool operator<(const ContactKey& other) const { return _a < other._a || (_a == other._a && _b < other._b); } + bool operator==(const ContactKey& other) const { return _a == other._a && _b == other._b; } void* _a; void* _b; }; typedef std::map ContactMap; +typedef std::pair ContactMapElement; class PhysicsEngine : public EntitySimulation { public: From 6840daa0b5dbd697bea72328ddff2896bfc5e9a8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 21 Jan 2015 11:55:28 -0800 Subject: [PATCH 6/8] removing tabs from formatting --- libraries/physics/src/PhysicsEngine.cpp | 42 ++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index a8b168681e..dea321be22 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -159,14 +159,14 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { // trigger events for new/existing/old contacts - ContactMap::iterator contactItr = _contactMap.begin(); - while (contactItr != _contactMap.end()) { + ContactMap::iterator contactItr = _contactMap.begin(); + while (contactItr != _contactMap.end()) { if (contactItr->first._a == motionState || contactItr->first._b == motionState) { - ContactMap::iterator iterToDelete = contactItr; - ++contactItr; - _contactMap.erase(iterToDelete); + ContactMap::iterator iterToDelete = contactItr; + ++contactItr; + _contactMap.erase(iterToDelete); } else { - ++contactItr; + ++contactItr; } } } @@ -251,26 +251,26 @@ void PhysicsEngine::stepSimulation() { void PhysicsEngine::computeCollisionEvents() { // update all contacts int numManifolds = _collisionDispatcher->getNumManifolds(); - for (int i = 0; i < numManifolds; ++i) { - btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); + for (int i = 0; i < numManifolds; ++i) { + btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); if (contactManifold->getNumContacts() > 0) { - const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); - const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); + const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); + const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); 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(_numSubsteps, contactManifold->getContactPoint(0), _originOffset); } } } - + // scan known contacts and trigger events - ContactMap::iterator contactItr = _contactMap.begin(); - while (contactItr != _contactMap.end()) { - ObjectMotionState* A = static_cast(contactItr->first._a); - ObjectMotionState* B = static_cast(contactItr->first._b); + ContactMap::iterator contactItr = _contactMap.begin(); + while (contactItr != _contactMap.end()) { + ObjectMotionState* A = static_cast(contactItr->first._a); + ObjectMotionState* B = static_cast(contactItr->first._b); // TODO: make triggering these events clean and efficient. The code at this context shouldn't // have to figure out what kind of object (entity, avatar, etc) these are in order to properly @@ -289,13 +289,13 @@ void PhysicsEngine::computeCollisionEvents() { } // TODO: enable scripts to filter based on contact event type - ContactEventType type = contactItr->second.computeType(_numSubsteps); + ContactEventType type = contactItr->second.computeType(_numSubsteps); if (type == CONTACT_EVENT_TYPE_END) { - ContactMap::iterator iterToDelete = contactItr; - ++contactItr; - _contactMap.erase(iterToDelete); + ContactMap::iterator iterToDelete = contactItr; + ++contactItr; + _contactMap.erase(iterToDelete); } else { - ++contactItr; + ++contactItr; } } } From 1c38b08e8f25d5452e623ea20a07a40648f8f49d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 21 Jan 2015 14:07:23 -0800 Subject: [PATCH 7/8] remane emitEntityCollision... to entityCollision... --- interface/src/Application.cpp | 4 ++-- libraries/entities/src/EntityCollisionSystem.cpp | 2 +- libraries/entities/src/EntitySimulation.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 78fd0f943e..86af8b0e91 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1693,11 +1693,11 @@ void Application::init() { tree->setSimulation(&_physicsEngine); _physicsEngine.init(&_entityEditSender); - connect(&_physicsEngine, &EntitySimulation::emitEntityCollisionWithEntity, + connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity); // connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts - connect(&_physicsEngine, &EntitySimulation::emitEntityCollisionWithEntity, + connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, &_entities, &EntityTreeRenderer::entityCollisionWithEntity); // connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 12d4e9e61e..6d27e7d0cc 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -188,7 +188,7 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { EntityItemID idA = entityA->getEntityItemID(); EntityItemID idB = entityB->getEntityItemID(); - emitEntityCollisionWithEntity(idA, idB, collision); + emit entityCollisionWithEntity(idA, idB, collision); } } } diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index a7e18b67df..e7f2219c19 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -64,7 +64,7 @@ public: EntityTree* getEntityTree() { return _entityTree; } signals: - void emitEntityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); + void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); protected: diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index dea321be22..02304b3b8d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -281,11 +281,11 @@ void PhysicsEngine::computeCollisionEvents() { if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { idB = static_cast(B)->getEntity()->getEntityItemID(); } - emitEntityCollisionWithEntity(idA, idB, contactItr->second); + emit entityCollisionWithEntity(idA, idB, contactItr->second); } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { EntityItemID idA; EntityItemID idB = static_cast(B)->getEntity()->getEntityItemID(); - emitEntityCollisionWithEntity(idA, idB, contactItr->second); + emit entityCollisionWithEntity(idA, idB, contactItr->second); } // TODO: enable scripts to filter based on contact event type From 1b7074e52a0278e8a3a06b8165f8fe91e5712636 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 21 Jan 2015 14:16:34 -0800 Subject: [PATCH 8/8] purge EntityCollisionSystem --- interface/src/Application.h | 1 - .../entities/src/EntityCollisionSystem.cpp | 297 ------------------ .../entities/src/EntityCollisionSystem.h | 58 ---- 3 files changed, 356 deletions(-) delete mode 100644 libraries/entities/src/EntityCollisionSystem.cpp delete mode 100644 libraries/entities/src/EntityCollisionSystem.h diff --git a/interface/src/Application.h b/interface/src/Application.h index c79cf8a989..3b793978a8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -25,7 +25,6 @@ #include #include -#include #include #include #include diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp deleted file mode 100644 index 6d27e7d0cc..0000000000 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ /dev/null @@ -1,297 +0,0 @@ -// -// EntityCollisionSystem.cpp -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 9/23/14. -// Copyright 2013-2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "EntityCollisionSystem.h" -#include "EntityEditPacketSender.h" -#include "EntityItem.h" -#include "EntityTreeElement.h" -#include "EntityTree.h" - -const int MAX_COLLISIONS_PER_Entity = 16; - -EntityCollisionSystem::EntityCollisionSystem() - : SimpleEntitySimulation(), - _packetSender(NULL), - _avatars(NULL), - _collisions(MAX_COLLISIONS_PER_Entity) { -} - -void EntityCollisionSystem::init(EntityEditPacketSender* packetSender, - EntityTree* entities, AvatarHashMap* avatars) { - assert(entities); - setEntityTree(entities); - _packetSender = packetSender; - _avatars = avatars; -} - -EntityCollisionSystem::~EntityCollisionSystem() { -} - -void EntityCollisionSystem::updateCollisions() { - PerformanceTimer perfTimer("collisions"); - assert(_entityTree); - // update all Entities - if (_entityTree->tryLockForWrite()) { - foreach (EntityItem* entity, _movingEntities) { - checkEntity(entity); - } - _entityTree->unlock(); - } -} - - -void EntityCollisionSystem::checkEntity(EntityItem* entity) { - updateCollisionWithEntities(entity); - updateCollisionWithAvatars(entity); -} - -void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { - - if (entityA->getIgnoreForCollisions()) { - return; // bail early if this entity is to be ignored... - } - - // don't collide entities with unknown IDs, - if (!entityA->isKnownID()) { - return; - } - - glm::vec3 penetration; - EntityItem* entityB = NULL; - - const int MAX_COLLISIONS_PER_ENTITY = 32; - CollisionList collisions(MAX_COLLISIONS_PER_ENTITY); - bool shapeCollisionsAccurate = false; - - bool shapeCollisions = _entityTree->findShapeCollisions(&entityA->getCollisionShapeInMeters(), - collisions, Octree::NoLock, &shapeCollisionsAccurate); - - if (shapeCollisions) { - for(int i = 0; i < collisions.size(); i++) { - - CollisionInfo* collision = collisions[i]; - penetration = collision->_penetration; - entityB = static_cast(collision->_extraData); - - // The collision _extraData should be a valid entity, but if for some reason - // it's NULL then continue with a warning. - if (!entityB) { - qDebug() << "UNEXPECTED - we have a collision with missing _extraData. Something went wrong down below!"; - continue; // skip this loop pass if the entity is NULL - } - - // don't collide entities with unknown IDs, - if (!entityB->isKnownID()) { - continue; // skip this loop pass if the entity has an unknown ID - } - - // NOTE: 'penetration' is the depth that 'entityA' overlaps 'entityB'. It points from A into B. - glm::vec3 penetrationInTreeUnits = penetration / (float)(TREE_SCALE); - - // Even if the Entities overlap... when the Entities are already moving appart - // we don't want to count this as a collision. - glm::vec3 relativeVelocity = entityA->getVelocity() - entityB->getVelocity(); - - bool fullyEnclosedCollision = glm::length(penetrationInTreeUnits) > entityA->getLargestDimension(); - - bool wantToMoveA = entityA->getCollisionsWillMove(); - bool wantToMoveB = entityB->getCollisionsWillMove(); - bool movingTowardEachOther = glm::dot(relativeVelocity, penetrationInTreeUnits) > 0.0f; - - // only do collisions if the entities are moving toward each other and one or the other - // of the entities are movable from collisions - bool doCollisions = !fullyEnclosedCollision && movingTowardEachOther && (wantToMoveA || wantToMoveB); - - if (doCollisions) { - - quint64 now = usecTimestampNow(); - - glm::vec3 axis = glm::normalize(penetration); - glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis; - - float massA = entityA->computeMass(); - float massB = entityB->computeMass(); - float totalMass = massA + massB; - float massRatioA = (2.0f * massB / totalMass); - float massRatioB = (2.0f * massA / totalMass); - - // in the event that one of our entities is non-moving, then fix up these ratios - if (wantToMoveA && !wantToMoveB) { - massRatioA = 2.0f; - massRatioB = 0.0f; - } - - if (!wantToMoveA && wantToMoveB) { - massRatioA = 0.0f; - massRatioB = 2.0f; - } - - // unless the entity is configured to not be moved by collision, calculate it's new position - // and velocity and apply it - if (wantToMoveA) { - // handle Entity A - glm::vec3 newVelocityA = entityA->getVelocity() - axialVelocity * massRatioA; - glm::vec3 newPositionA = entityA->getPosition() - 0.5f * penetrationInTreeUnits; - - EntityItemProperties propertiesA = entityA->getProperties(); - EntityItemID idA(entityA->getID()); - propertiesA.setVelocity(newVelocityA * (float)TREE_SCALE); - propertiesA.setPosition(newPositionA * (float)TREE_SCALE); - propertiesA.setLastEdited(now); - - // NOTE: EntityTree::updateEntity() will cause the entity to get sorted correctly in the EntitySimulation, - // thereby waking up static non-moving entities. - _entityTree->updateEntity(entityA, propertiesA); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idA, propertiesA); - } - - // unless the entity is configured to not be moved by collision, calculate it's new position - // and velocity and apply it - if (wantToMoveB) { - glm::vec3 newVelocityB = entityB->getVelocity() + axialVelocity * massRatioB; - glm::vec3 newPositionB = entityB->getPosition() + 0.5f * penetrationInTreeUnits; - - EntityItemProperties propertiesB = entityB->getProperties(); - - EntityItemID idB(entityB->getID()); - propertiesB.setVelocity(newVelocityB * (float)TREE_SCALE); - propertiesB.setPosition(newPositionB * (float)TREE_SCALE); - propertiesB.setLastEdited(now); - - // NOTE: EntityTree::updateEntity() will cause the entity to get sorted correctly in the EntitySimulation, - // thereby waking up static non-moving entities. - _entityTree->updateEntity(entityB, propertiesB); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idB, propertiesB); - } - - // NOTE: Do this after updating the entities so that the callback can delete the entities if they want to - Collision collision; - collision.penetration = penetration; - collision.contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition()); - - EntityItemID idA = entityA->getEntityItemID(); - EntityItemID idB = entityB->getEntityItemID(); - emit entityCollisionWithEntity(idA, idB, collision); - } - } - } -} - -void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) { - - // Entities that are in hand, don't collide with avatars - if (!_avatars) { - return; - } - - if (entity->getIgnoreForCollisions() || !entity->getCollisionsWillMove()) { - return; // bail early if this entity is to be ignored or wont move - } - - glm::vec3 center = entity->getPosition() * (float)(TREE_SCALE); - float radius = entity->getRadius() * (float)(TREE_SCALE); - const float ELASTICITY = 0.9f; - const float DAMPING = 0.1f; - glm::vec3 penetration; - - _collisions.clear(); - foreach (const AvatarSharedPointer& avatarPointer, _avatars->getAvatarHash()) { - AvatarData* avatar = avatarPointer.data(); - - float totalRadius = avatar->getBoundingRadius() + radius; - glm::vec3 relativePosition = center - avatar->getPosition(); - if (glm::dot(relativePosition, relativePosition) > (totalRadius * totalRadius)) { - continue; - } - - if (avatar->findSphereCollisions(center, radius, _collisions)) { - int numCollisions = _collisions.size(); - for (int i = 0; i < numCollisions; ++i) { - CollisionInfo* collision = _collisions.getCollision(i); - collision->_damping = DAMPING; - collision->_elasticity = ELASTICITY; - - collision->_addedVelocity /= (float)(TREE_SCALE); - glm::vec3 relativeVelocity = collision->_addedVelocity - entity->getVelocity(); - - if (glm::dot(relativeVelocity, collision->_penetration) <= 0.0f) { - // only collide when Entity and collision point are moving toward each other - // (doing this prevents some "collision snagging" when Entity penetrates the object) - collision->_penetration /= (float)(TREE_SCALE); - applyHardCollision(entity, *collision); - } - } - } - } -} - -void EntityCollisionSystem::applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo) { - - // don't collide entities with unknown IDs, - if (!entity->isKnownID()) { - return; - } - - // HALTING_* params are determined using expected acceleration of gravity over some timescale. - // This is a HACK for entities that bounce in a 1.0 gravitational field and should eventually be made more universal. - const float HALTING_ENTITY_PERIOD = 0.0167f; // ~1/60th of a second - const float HALTING_ENTITY_SPEED = 9.8 * HALTING_ENTITY_PERIOD / (float)(TREE_SCALE); - - // - // Update the entity in response to a hard collision. Position will be reset exactly - // to outside the colliding surface. Velocity will be modified according to elasticity. - // - // if elasticity = 0.0, collision is inelastic (vel normal to collision is lost) - // if elasticity = 1.0, collision is 100% elastic. - // - glm::vec3 position = entity->getPosition(); - glm::vec3 velocity = entity->getVelocity(); - - const float EPSILON = 0.0f; - glm::vec3 relativeVelocity = collisionInfo._addedVelocity - velocity; - float velocityDotPenetration = glm::dot(relativeVelocity, collisionInfo._penetration); - if (velocityDotPenetration < EPSILON) { - // entity is moving into collision surface - // - // TODO: do something smarter here by comparing the mass of the entity vs that of the other thing - // (other's mass could be stored in the Collision Info). The smaller mass should surrender more - // position offset and should slave more to the other's velocity in the static-friction case. - position -= collisionInfo._penetration; - - if (glm::length(relativeVelocity) < HALTING_ENTITY_SPEED) { - // static friction kicks in and entities moves with colliding object - velocity = collisionInfo._addedVelocity; - } else { - glm::vec3 direction = glm::normalize(collisionInfo._penetration); - velocity += glm::dot(relativeVelocity, direction) * (1.0f + collisionInfo._elasticity) * direction; // dynamic reflection - velocity += glm::clamp(collisionInfo._damping, 0.0f, 1.0f) * (relativeVelocity - glm::dot(relativeVelocity, direction) * direction); // dynamic friction - } - } - - EntityItemProperties properties = entity->getProperties(); - EntityItemID entityItemID(entity->getID()); - - properties.setPosition(position * (float)TREE_SCALE); - properties.setVelocity(velocity * (float)TREE_SCALE); - properties.setLastEdited(usecTimestampNow()); - - _entityTree->updateEntity(entity, properties); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, entityItemID, properties); -} diff --git a/libraries/entities/src/EntityCollisionSystem.h b/libraries/entities/src/EntityCollisionSystem.h deleted file mode 100644 index d6cafd88f3..0000000000 --- a/libraries/entities/src/EntityCollisionSystem.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// EntityCollisionSystem.h -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 9/23/14. -// Copyright 2013-2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_EntityCollisionSystem_h -#define hifi_EntityCollisionSystem_h - -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "EntityItem.h" -#include "SimpleEntitySimulation.h" - -class AbstractAudioInterface; -class AvatarData; -class EntityEditPacketSender; -class EntityTree; - -class EntityCollisionSystem : public SimpleEntitySimulation { -public: - EntityCollisionSystem(); - - void init(EntityEditPacketSender* packetSender, EntityTree* entities, AvatarHashMap* _avatars = NULL); - - ~EntityCollisionSystem(); - - void updateCollisions(); - - void checkEntity(EntityItem* Entity); - void updateCollisionWithEntities(EntityItem* Entity); - void updateCollisionWithAvatars(EntityItem* Entity); - -private: - void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo); - - static bool updateOperation(OctreeElement* element, void* extraData); - - EntityEditPacketSender* _packetSender; - AvatarHashMap* _avatars; - CollisionList _collisions; -}; - -#endif // hifi_EntityCollisionSystem_h