From 86583f3f3f3cb1a5c714536bfdee9b848011c30a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 21 Jan 2015 11:27:32 -0800 Subject: [PATCH] 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: