mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 21:33:35 +02:00
physics collisions emit script collision events
This commit is contained in:
parent
790d07d346
commit
86583f3f3f
13 changed files with 119 additions and 53 deletions
|
@ -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<TextureCache>()->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...
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -466,7 +466,6 @@ private:
|
|||
PhysicsEngine _physicsEngine;
|
||||
|
||||
EntityTreeRenderer _entities;
|
||||
EntityCollisionSystem _entityCollisionSystem;
|
||||
EntityTreeRenderer _entityClipboardRenderer;
|
||||
EntityTree _entityClipboard;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef hifi_EntitySimulation_h
|
||||
#define hifi_EntitySimulation_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QSet>
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
@ -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
|
||||
|
|
29
libraries/physics/src/ContactInfo.cpp
Normal file
29
libraries/physics/src/ContactInfo.cpp
Normal file
|
@ -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;
|
||||
}
|
37
libraries/physics/src/ContactInfo.h
Normal file
37
libraries/physics/src/ContactInfo.h
Normal file
|
@ -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 <btBulletDynamicsCommon.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#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
|
|
@ -33,6 +33,7 @@ void EntityMotionState::enqueueOutgoingEntity(EntityItem* entity) {
|
|||
|
||||
EntityMotionState::EntityMotionState(EntityItem* entity)
|
||||
: _entity(entity) {
|
||||
_type = MOTION_STATE_TYPE_ENTITY;
|
||||
assert(entity != NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<ObjectMotionState*>(contactItr->first._a);
|
||||
ObjectMotionState* B = static_cast<ObjectMotionState*>(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<EntityMotionState*>(A)->getEntity()->getEntityItemID();
|
||||
EntityItemID idB;
|
||||
if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) {
|
||||
idB = static_cast<EntityMotionState*>(B)->getEntity()->getEntityItemID();
|
||||
}
|
||||
emitEntityCollisionWithEntity(idA, idB, contactItr->second);
|
||||
} else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) {
|
||||
EntityItemID idA;
|
||||
EntityItemID idB = static_cast<EntityMotionState*>(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);
|
||||
|
|
|
@ -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<ContactKey, ContactInfo> ContactMap;
|
||||
typedef std::pair<ContactKey, ContactInfo> ContactMapElement;
|
||||
|
||||
class PhysicsEngine : public EntitySimulation {
|
||||
public:
|
||||
|
|
Loading…
Reference in a new issue