mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 18:53:36 +02:00
PhysicsEngine is now an EntitySimulation
This commit is contained in:
parent
919214b7cb
commit
c9ea6885c1
11 changed files with 163 additions and 90 deletions
|
@ -2021,8 +2021,10 @@ void Application::init() {
|
|||
connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::updateMyAvatarTransform);
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
// _physicsEngine.initSafe(_entities.getTree());
|
||||
// _entities.getTree()->setSimulation(&_physicsEngine);
|
||||
EntityTree* tree = _entities.getTree();
|
||||
_physicsEngine.setEntityTree(tree);
|
||||
tree->setSimulation(&_physicsEngine);
|
||||
_physicsEngine.init();
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
}
|
||||
|
||||
|
|
|
@ -504,7 +504,7 @@ private:
|
|||
ViewFrustum _sharedVoxelSystemViewFrustum;
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
ThreadSafePhysicsEngine _physicsEngine;
|
||||
PhysicsEngine _physicsEngine;
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
EntityTreeRenderer _entities;
|
||||
|
|
|
@ -9,55 +9,12 @@
|
|||
//
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <EntityTree.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <ThreadSafeDynamicsWorld.h>
|
||||
|
||||
#include "Util.h"
|
||||
#include "world.h"
|
||||
#include "Physics.h"
|
||||
|
||||
// DynamicsImpl is an implementation of ThreadSafeDynamicsWorld that knows how to lock an EntityTree
|
||||
class DynamicsImpl : public ThreadSafeDynamicsWorld {
|
||||
public:
|
||||
DynamicsImpl(
|
||||
btDispatcher* dispatcher,
|
||||
btBroadphaseInterface* pairCache,
|
||||
btConstraintSolver* constraintSolver,
|
||||
btCollisionConfiguration* collisionConfiguration,
|
||||
EntityTree* entities)
|
||||
: ThreadSafeDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration), _entities(entities) {
|
||||
assert(entities);
|
||||
}
|
||||
|
||||
bool tryLock() {
|
||||
// wait for lock
|
||||
_entities->lockForRead();
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
_entities->unlock();
|
||||
}
|
||||
private:
|
||||
EntityTree* _entities;
|
||||
};
|
||||
|
||||
ThreadSafePhysicsEngine::ThreadSafePhysicsEngine(const glm::vec3& offset) : PhysicsEngine(offset) {
|
||||
}
|
||||
|
||||
void ThreadSafePhysicsEngine::initSafe(EntityTree* entities) {
|
||||
assert(!_dynamicsWorld); // only call this once
|
||||
assert(entities);
|
||||
_collisionConfig = new btDefaultCollisionConfiguration();
|
||||
_collisionDispatcher = new btCollisionDispatcher(_collisionConfig);
|
||||
_broadphaseFilter = new btDbvtBroadphase();
|
||||
_constraintSolver = new btSequentialImpulseConstraintSolver;
|
||||
// ThreadSafePhysicsEngine gets a DynamicsImpl, which derives from ThreadSafeDynamicsWorld
|
||||
_dynamicsWorld = new DynamicsImpl(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig, entities);
|
||||
}
|
||||
|
||||
//
|
||||
// Applies static friction: maxVelocity is the largest velocity for which there
|
||||
// there is friction, and strength is the amount of friction force applied to reduce
|
||||
|
|
|
@ -12,20 +12,6 @@
|
|||
#ifndef hifi_Physics_h
|
||||
#define hifi_Physics_h
|
||||
|
||||
#include <PhysicsEngine.h>
|
||||
|
||||
class EntityTree;
|
||||
|
||||
class ThreadSafePhysicsEngine : public PhysicsEngine {
|
||||
public:
|
||||
ThreadSafePhysicsEngine(const glm::vec3& offset);
|
||||
|
||||
// virtual override from PhysicsEngine
|
||||
void init() { assert(false); } // call initSafe() instead
|
||||
|
||||
void initSafe(EntityTree* entities);
|
||||
};
|
||||
|
||||
void applyStaticFriction(float deltaTime, glm::vec3& velocity, float maxVelocity, float strength);
|
||||
void applyDamping(float deltaTime, glm::vec3& velocity, float linearStrength, float squaredStrength);
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@ class EntityTreeElementExtraEncodeData;
|
|||
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
|
||||
#define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { };
|
||||
|
||||
class EntityMotionState;
|
||||
|
||||
/// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available
|
||||
/// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate
|
||||
/// one directly, instead you must only construct one of it's derived classes with additional features.
|
||||
|
@ -303,9 +301,10 @@ public:
|
|||
void clearUpdateFlags() { _updateFlags = 0; }
|
||||
|
||||
void* getPhysicsInfo() const { return _physicsInfo; }
|
||||
void setPhysicsInfo(void* data) { _physicsInfo = data; }
|
||||
SimulationState getSimulationState() const { return _simulationState; }
|
||||
|
||||
void setSimulationState(SimulationState state) { _simulationState = state; }
|
||||
|
||||
protected:
|
||||
|
||||
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
|
||||
|
@ -349,8 +348,8 @@ protected:
|
|||
void setRadius(float value);
|
||||
|
||||
AACubeShape _collisionShape;
|
||||
void* _physicsInfo;
|
||||
SimulationState _simulationState; // only set by EntityTree
|
||||
void* _physicsInfo; // only set by EntitySimulation
|
||||
SimulationState _simulationState; // only set by EntitySimulation
|
||||
|
||||
// UpdateFlags are set whenever a property changes that requires the change to be communicated to other
|
||||
// data structures. It is the responsibility of the EntityTree to relay changes entity and clear flags.
|
||||
|
|
|
@ -154,9 +154,9 @@ void SimpleEntitySimulation::updateMortalEntities(quint64 now, QSet<EntityItem*>
|
|||
item_itr = _mortalEntities.erase(item_itr);
|
||||
entity->setSimulationState(EntityItem::Static);
|
||||
} else {
|
||||
// check to see if this entity is no longer moving
|
||||
EntityItem::SimulationState newState = entity->computeSimulationState();
|
||||
if (newState != EntityItem::Mortal) {
|
||||
// check to see if this entity is moving
|
||||
if (newState == EntityItem::Moving) {
|
||||
entity->update(now);
|
||||
_movingEntities.push_back(entity);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#ifdef USE_BULLET_PHYSICS
|
||||
#include "CustomMotionState.h"
|
||||
#else // USE_BULLET_PHYSICS
|
||||
|
||||
// CustomMotionState stubbery
|
||||
class CustomMotionState {
|
||||
public:
|
||||
|
|
|
@ -12,19 +12,116 @@
|
|||
#include "PhysicsEngine.h"
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
|
||||
#include "EntityMotionState.h"
|
||||
#include "ShapeInfoUtil.h"
|
||||
#include "ThreadSafeDynamicsWorld.h"
|
||||
|
||||
class EntityTree;
|
||||
|
||||
PhysicsEngine::PhysicsEngine(const glm::vec3& offset)
|
||||
: _collisionConfig(NULL),
|
||||
_collisionDispatcher(NULL),
|
||||
_broadphaseFilter(NULL),
|
||||
_constraintSolver(NULL),
|
||||
_dynamicsWorld(NULL),
|
||||
_originOffset(offset),
|
||||
_voxels() {
|
||||
}
|
||||
|
||||
PhysicsEngine::~PhysicsEngine() {
|
||||
}
|
||||
|
||||
/// \param tree pointer to EntityTree which is stored internally
|
||||
void PhysicsEngine::setEntityTree(EntityTree* tree) {
|
||||
assert(_entityTree == NULL);
|
||||
assert(tree);
|
||||
_entityTree = tree;
|
||||
}
|
||||
|
||||
/// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted.
|
||||
void PhysicsEngine::updateEntities(QSet<EntityItem*>& entitiesToDelete) {
|
||||
// relay changes
|
||||
QSet<EntityItem*>::iterator item_itr = _changedEntities.begin();
|
||||
while (item_itr != _changedEntities.end()) {
|
||||
EntityItem* entity = *item_itr;
|
||||
void* physicsInfo = entity->getPhysicsInfo();
|
||||
if (physicsInfo) {
|
||||
CustomMotionState* motionState = static_cast<CustomMotionState*>(physicsInfo);
|
||||
updateObject(motionState, entity->getUpdateFlags());
|
||||
}
|
||||
entity->clearUpdateFlags();
|
||||
// TODO: implement this
|
||||
++item_itr;
|
||||
}
|
||||
|
||||
// hunt for entities who have expired
|
||||
// TODO: make EntityItems use an expiry to make this work faster.
|
||||
item_itr = _mortalEntities.begin();
|
||||
while (item_itr != _mortalEntities.end()) {
|
||||
EntityItem* entity = *item_itr;
|
||||
// always check to see if the lifetime has expired, for immortal entities this is always false
|
||||
if (entity->lifetimeHasExpired()) {
|
||||
qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID();
|
||||
entitiesToDelete.insert(entity);
|
||||
// remove entity from the list
|
||||
item_itr = _mortalEntities.erase(item_itr);
|
||||
} else if (entity->isImmortal()) {
|
||||
// remove entity from the list
|
||||
item_itr = _mortalEntities.erase(item_itr);
|
||||
} else {
|
||||
++item_itr;
|
||||
}
|
||||
}
|
||||
// TODO: check for entities that have exited the world boundaries
|
||||
}
|
||||
|
||||
/// \param entity pointer to EntityItem to add to the simulation
|
||||
/// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list
|
||||
void PhysicsEngine::addEntity(EntityItem* entity) {
|
||||
assert(entity);
|
||||
void* physicsInfo = entity->getPhysicsInfo();
|
||||
if (!physicsInfo) {
|
||||
EntityMotionState* motionState = new EntityMotionState(entity);
|
||||
entity->setPhysicsInfo(static_cast<void*>(motionState));
|
||||
if (entity->isMortal()) {
|
||||
_mortalEntities.insert(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \param entity pointer to EntityItem to removed from the simulation
|
||||
/// \sideeffect the EntityItem::_simulationState member may be updated to indicate non-membership to internal list
|
||||
void PhysicsEngine::removeEntity(EntityItem* entity) {
|
||||
assert(entity);
|
||||
void* physicsInfo = entity->getPhysicsInfo();
|
||||
if (physicsInfo) {
|
||||
CustomMotionState* motionState = static_cast<CustomMotionState*>(physicsInfo);
|
||||
removeObject(motionState);
|
||||
entity->setPhysicsInfo(NULL);
|
||||
}
|
||||
_mortalEntities.remove(entity);
|
||||
}
|
||||
|
||||
/// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation
|
||||
void PhysicsEngine::entityChanged(EntityItem* entity) {
|
||||
_changedEntities.insert(entity);
|
||||
}
|
||||
|
||||
void PhysicsEngine::clearEntities() {
|
||||
// For now we assume this would only be called on shutdown in which case we can just let the memory get lost.
|
||||
}
|
||||
|
||||
// virtual
|
||||
void PhysicsEngine::init() {
|
||||
// _entityTree should be set prior to the init() call
|
||||
assert(_entityTree);
|
||||
|
||||
if (!_dynamicsWorld) {
|
||||
_collisionConfig = new btDefaultCollisionConfiguration();
|
||||
_collisionDispatcher = new btCollisionDispatcher(_collisionConfig);
|
||||
_broadphaseFilter = new btDbvtBroadphase();
|
||||
_constraintSolver = new btSequentialImpulseConstraintSolver;
|
||||
_dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig);
|
||||
_dynamicsWorld = new ThreadSafeDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig, _entityTree);
|
||||
|
||||
// default gravity of the world is zero, so each object must specify its own gravity
|
||||
// TODO: set up gravity zones
|
||||
|
|
|
@ -32,31 +32,53 @@ const uint32_t PHYSICS_UPDATE_EASY = PHYSICS_UPDATE_POSITION | PHYSICS_UPDATE_VE
|
|||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
|
||||
#include <QSet>
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
|
||||
#include <EntityItem.h>
|
||||
#include <EntitySimulation.h>
|
||||
|
||||
#include "BulletUtil.h"
|
||||
#include "CustomMotionState.h"
|
||||
#include "PositionHashKey.h"
|
||||
#include "ShapeManager.h"
|
||||
#include "ThreadSafeDynamicsWorld.h"
|
||||
#include "VoxelObject.h"
|
||||
|
||||
const float HALF_SIMULATION_EXTENT = 512.0f; // meters
|
||||
|
||||
class PhysicsEngine {
|
||||
class PhysicsEngine : public EntitySimulation {
|
||||
public:
|
||||
|
||||
PhysicsEngine(const glm::vec3& offset)
|
||||
: _collisionConfig(NULL),
|
||||
_collisionDispatcher(NULL),
|
||||
_broadphaseFilter(NULL),
|
||||
_constraintSolver(NULL),
|
||||
_dynamicsWorld(NULL),
|
||||
_originOffset(offset),
|
||||
_voxels() {
|
||||
}
|
||||
PhysicsEngine(const glm::vec3& offset);
|
||||
|
||||
~PhysicsEngine();
|
||||
|
||||
// override from EntitySimulation
|
||||
/// \param tree pointer to EntityTree which is stored internally
|
||||
void setEntityTree(EntityTree* tree);
|
||||
|
||||
// override from EntitySimulation
|
||||
/// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted.
|
||||
void updateEntities(QSet<EntityItem*>& entitiesToDelete);
|
||||
|
||||
// override from EntitySimulation
|
||||
/// \param entity pointer to EntityItem to add to the simulation
|
||||
/// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list
|
||||
void addEntity(EntityItem* entity);
|
||||
|
||||
// override from EntitySimulation
|
||||
/// \param entity pointer to EntityItem to removed from the simulation
|
||||
/// \sideeffect the EntityItem::_simulationState member may be updated to indicate non-membership to internal list
|
||||
void removeEntity(EntityItem* entity);
|
||||
|
||||
// override from EntitySimulation
|
||||
/// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation
|
||||
void entityChanged(EntityItem* entity);
|
||||
|
||||
// override from EntitySimulation
|
||||
void clearEntities();
|
||||
|
||||
virtual void init();
|
||||
|
||||
void stepSimulation();
|
||||
|
@ -99,12 +121,16 @@ protected:
|
|||
btCollisionDispatcher* _collisionDispatcher;
|
||||
btBroadphaseInterface* _broadphaseFilter;
|
||||
btSequentialImpulseConstraintSolver* _constraintSolver;
|
||||
btDiscreteDynamicsWorld* _dynamicsWorld;
|
||||
ThreadSafeDynamicsWorld* _dynamicsWorld;
|
||||
ShapeManager _shapeManager;
|
||||
|
||||
private:
|
||||
glm::vec3 _originOffset;
|
||||
btHashMap<PositionHashKey, VoxelObject> _voxels;
|
||||
|
||||
// EntitySimulation stuff
|
||||
QSet<EntityItem*> _changedEntities;
|
||||
QSet<EntityItem*> _mortalEntities;
|
||||
};
|
||||
|
||||
#else // USE_BULLET_PHYSICS
|
||||
|
|
|
@ -15,21 +15,25 @@
|
|||
* Copied and modified from btDiscreteDynamicsWorld.cpp by AndrewMeadows on 2014.11.12.
|
||||
* */
|
||||
|
||||
#include <EntityTree.h>
|
||||
|
||||
#include "ThreadSafeDynamicsWorld.h"
|
||||
|
||||
ThreadSafeDynamicsWorld::ThreadSafeDynamicsWorld(
|
||||
btDispatcher* dispatcher,
|
||||
btBroadphaseInterface* pairCache,
|
||||
btConstraintSolver* constraintSolver,
|
||||
btCollisionConfiguration* collisionConfiguration)
|
||||
btCollisionConfiguration* collisionConfiguration,
|
||||
EntityTree* entities)
|
||||
: btDiscreteDynamicsWorld(dispatcher, pairCache, constraintSolver, collisionConfiguration) {
|
||||
assert(entities);
|
||||
_entities = entities;
|
||||
}
|
||||
|
||||
void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
|
||||
if (tryLock()) {
|
||||
btDiscreteDynamicsWorld::synchronizeMotionStates();
|
||||
unlock();
|
||||
}
|
||||
_entities->lockForWrite();
|
||||
btDiscreteDynamicsWorld::synchronizeMotionStates();
|
||||
_entities->unlock();
|
||||
}
|
||||
|
||||
int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep) {
|
||||
|
@ -77,6 +81,8 @@ int ThreadSafeDynamicsWorld::stepSimulation( btScalar timeStep, int maxSubSteps,
|
|||
}
|
||||
}
|
||||
|
||||
// We only sync motion states once at the end of all substeps.
|
||||
// This is to avoid placing multiple, repeated thread locks on _entities.
|
||||
synchronizeMotionStates();
|
||||
clearForces();
|
||||
return subSteps;
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
|
||||
|
||||
class EntityTree;
|
||||
|
||||
ATTRIBUTE_ALIGNED16(class) ThreadSafeDynamicsWorld : public btDiscreteDynamicsWorld
|
||||
{
|
||||
public:
|
||||
|
@ -29,16 +31,15 @@ public:
|
|||
btDispatcher* dispatcher,
|
||||
btBroadphaseInterface* pairCache,
|
||||
btConstraintSolver* constraintSolver,
|
||||
btCollisionConfiguration* collisionConfiguration);
|
||||
btCollisionConfiguration* collisionConfiguration,
|
||||
EntityTree* entities);
|
||||
|
||||
// virtual overrides of btDiscreteDynamicsWorld
|
||||
// virtual overrides from btDiscreteDynamicsWorld
|
||||
int stepSimulation( btScalar timeStep, int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.));
|
||||
void synchronizeMotionStates();
|
||||
|
||||
/// \return true if lock succeeds
|
||||
virtual bool tryLock() = 0;
|
||||
|
||||
virtual void unlock() = 0;
|
||||
private:
|
||||
EntityTree* _entities;
|
||||
};
|
||||
|
||||
#endif // hifi_ThreadSafeDynamicsWorld_h
|
||||
|
|
Loading…
Reference in a new issue