CollisionWorld only updates _active_ Aabbs

we manually set/clear active state of static objects
  that need their Aabbs updated
also fixing a bug when starting kinematic motion
This commit is contained in:
Andrew Meadows 2016-04-01 12:04:27 -07:00
parent e1602b57fa
commit 25fbf926df
6 changed files with 50 additions and 31 deletions

View file

@ -94,7 +94,7 @@ void EntityMotionState::updateServerPhysicsVariables() {
} }
// virtual // virtual
bool EntityMotionState::handleEasyChanges(uint32_t& flags) { void EntityMotionState::handleEasyChanges(uint32_t& flags) {
assert(entityTreeIsLocked()); assert(entityTreeIsLocked());
updateServerPhysicsVariables(); updateServerPhysicsVariables();
ObjectMotionState::handleEasyChanges(flags); ObjectMotionState::handleEasyChanges(flags);
@ -137,8 +137,6 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags) {
if ((flags & Simulation::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) { if ((flags & Simulation::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) {
_body->activate(); _body->activate();
} }
return true;
} }
@ -422,19 +420,18 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f;
if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) {
// acceleration measured during the most recent simulation step was close to gravity. // acceleration measured during the most recent simulation step was close to gravity.
if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { if (_accelerationNearlyGravityCount < STEPS_TO_DECIDE_BALLISTIC) {
// only increment this if we haven't reached the threshold yet. this is to avoid // only increment this if we haven't reached the threshold yet, to avoid overflowing the counter
// overflowing the counter. ++_accelerationNearlyGravityCount;
incrementAccelerationNearlyGravityCount();
} }
} else { } else {
// acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter // acceleration wasn't similar to this entity's gravity, reset the counter
resetAccelerationNearlyGravityCount(); _accelerationNearlyGravityCount = 0;
} }
// if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let
// the entity server's estimates include gravity. // the entity server's estimates include gravity.
if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { if (_accelerationNearlyGravityCount >= STEPS_TO_DECIDE_BALLISTIC) {
_entity->setAcceleration(_entity->getGravity()); _entity->setAcceleration(_entity->getGravity());
} else { } else {
_entity->setAcceleration(glm::vec3(0.0f)); _entity->setAcceleration(glm::vec3(0.0f));

View file

@ -29,7 +29,7 @@ public:
virtual ~EntityMotionState(); virtual ~EntityMotionState();
void updateServerPhysicsVariables(); void updateServerPhysicsVariables();
virtual bool handleEasyChanges(uint32_t& flags) override; virtual void handleEasyChanges(uint32_t& flags) override;
virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override; virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override;
/// \return PhysicsMotionType based on params set in EntityItem /// \return PhysicsMotionType based on params set in EntityItem
@ -51,10 +51,6 @@ public:
virtual uint32_t getIncomingDirtyFlags() override; virtual uint32_t getIncomingDirtyFlags() override;
virtual void clearIncomingDirtyFlags() override; virtual void clearIncomingDirtyFlags() override;
void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; }
void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; }
uint8_t getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; }
virtual float getObjectRestitution() const override { return _entity->getRestitution(); } virtual float getObjectRestitution() const override { return _entity->getRestitution(); }
virtual float getObjectFriction() const override { return _entity->getFriction(); } virtual float getObjectFriction() const override { return _entity->getFriction(); }
virtual float getObjectLinearDamping() const override { return _entity->getDamping(); } virtual float getObjectLinearDamping() const override { return _entity->getDamping(); }

View file

@ -39,7 +39,7 @@ const glm::vec3& ObjectMotionState::getWorldOffset() {
} }
// static // static
uint32_t worldSimulationStep = 0; uint32_t worldSimulationStep = 1;
void ObjectMotionState::setWorldSimulationStep(uint32_t step) { void ObjectMotionState::setWorldSimulationStep(uint32_t step) {
assert(step > worldSimulationStep); assert(step > worldSimulationStep);
worldSimulationStep = step; worldSimulationStep = step;
@ -164,7 +164,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) {
} }
} }
bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { void ObjectMotionState::handleEasyChanges(uint32_t& flags) {
if (flags & Simulation::DIRTY_POSITION) { if (flags & Simulation::DIRTY_POSITION) {
btTransform worldTrans = _body->getWorldTransform(); btTransform worldTrans = _body->getWorldTransform();
btVector3 newPosition = glmToBullet(getObjectPosition()); btVector3 newPosition = glmToBullet(getObjectPosition());
@ -183,6 +183,10 @@ bool ObjectMotionState::handleEasyChanges(uint32_t& flags) {
worldTrans.setRotation(newRotation); worldTrans.setRotation(newRotation);
} }
_body->setWorldTransform(worldTrans); _body->setWorldTransform(worldTrans);
if (!(flags & HARD_DIRTY_PHYSICS_FLAGS) && _body->isStaticObject()) {
// force activate static body so its Aabb is updated later
_body->activate(true);
}
} else if (flags & Simulation::DIRTY_ROTATION) { } else if (flags & Simulation::DIRTY_ROTATION) {
btTransform worldTrans = _body->getWorldTransform(); btTransform worldTrans = _body->getWorldTransform();
btQuaternion newRotation = glmToBullet(getObjectRotation()); btQuaternion newRotation = glmToBullet(getObjectRotation());
@ -192,6 +196,10 @@ bool ObjectMotionState::handleEasyChanges(uint32_t& flags) {
} }
worldTrans.setRotation(newRotation); worldTrans.setRotation(newRotation);
_body->setWorldTransform(worldTrans); _body->setWorldTransform(worldTrans);
if (!(flags & HARD_DIRTY_PHYSICS_FLAGS) && _body->isStaticObject()) {
// force activate static body so its Aabb is updated later
_body->activate(true);
}
} }
if (flags & Simulation::DIRTY_LINEAR_VELOCITY) { if (flags & Simulation::DIRTY_LINEAR_VELOCITY) {
@ -232,8 +240,6 @@ bool ObjectMotionState::handleEasyChanges(uint32_t& flags) {
if (flags & Simulation::DIRTY_MASS) { if (flags & Simulation::DIRTY_MASS) {
updateBodyMassProperties(); updateBodyMassProperties();
} }
return true;
} }
bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) { bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) {
@ -292,6 +298,10 @@ void ObjectMotionState::updateBodyVelocities() {
_body->setActivationState(ACTIVE_TAG); _body->setActivationState(ACTIVE_TAG);
} }
void ObjectMotionState::updateLastKinematicStep() {
_lastKinematicStep = ObjectMotionState::getWorldSimulationStep() - 1;
}
void ObjectMotionState::updateBodyMassProperties() { void ObjectMotionState::updateBodyMassProperties() {
float mass = getMass(); float mass = getMass();
btVector3 inertia(0.0f, 0.0f, 0.0f); btVector3 inertia(0.0f, 0.0f, 0.0f);

View file

@ -50,11 +50,12 @@ const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_MOTION_TY
Simulation::DIRTY_COLLISION_GROUP); Simulation::DIRTY_COLLISION_GROUP);
const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES | const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES |
Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL | Simulation::DIRTY_MASS | Simulation::DIRTY_MATERIAL |
Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY); Simulation::DIRTY_SIMULATOR_ID | Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY |
Simulation::DIRTY_PHYSICS_ACTIVATION);
// These are the set of incoming flags that the PhysicsEngine needs to hear about: // These are the set of incoming flags that the PhysicsEngine needs to hear about:
const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS | const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS);
Simulation::DIRTY_PHYSICS_ACTIVATION);
// These are the outgoing flags that the PhysicsEngine can affect: // These are the outgoing flags that the PhysicsEngine can affect:
const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES; const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES;
@ -80,11 +81,12 @@ public:
ObjectMotionState(btCollisionShape* shape); ObjectMotionState(btCollisionShape* shape);
~ObjectMotionState(); ~ObjectMotionState();
virtual bool handleEasyChanges(uint32_t& flags); virtual void handleEasyChanges(uint32_t& flags);
virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine);
void updateBodyMaterialProperties(); void updateBodyMaterialProperties();
void updateBodyVelocities(); void updateBodyVelocities();
void updateLastKinematicStep();
virtual void updateBodyMassProperties(); virtual void updateBodyMassProperties();
MotionStateType getType() const { return _type; } MotionStateType getType() const { return _type; }

View file

@ -50,6 +50,7 @@ void PhysicsEngine::init() {
// default gravity of the world is zero, so each object must specify its own gravity // default gravity of the world is zero, so each object must specify its own gravity
// TODO: set up gravity zones // TODO: set up gravity zones
_dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f)); _dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f));
_dynamicsWorld->setForceUpdateAllAabbs(false);
} }
} }
@ -80,6 +81,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
body->updateInertiaTensor(); body->updateInertiaTensor();
motionState->updateBodyVelocities(); motionState->updateBodyVelocities();
motionState->updateLastKinematicStep();
const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec
const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec
body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD);
@ -189,12 +191,18 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob
stillNeedChange.push_back(object); stillNeedChange.push_back(object);
} }
} else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) {
if (object->handleEasyChanges(flags)) { object->handleEasyChanges(flags);
object->clearIncomingDirtyFlags(); object->clearIncomingDirtyFlags();
} else {
stillNeedChange.push_back(object);
}
} }
if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) {
_activeStaticBodies.push_back(object->getRigidBody());
}
}
// active static bodies have changed (in an Easy way) and need their Aabbs updated
// but we've configured Bullet to NOT update them automatically (for improved performance)
// so we must do it outselves
for (int i = 0; i < _activeStaticBodies.size(); ++i) {
_dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]);
} }
return stillNeedChange; return stillNeedChange;
} }
@ -389,6 +397,12 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() {
const VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { const VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() {
BT_PROFILE("copyOutgoingChanges"); BT_PROFILE("copyOutgoingChanges");
// Bullet will not deactivate static objects (it doesn't expect them to be active)
// so we must deactivate them ourselves
for (int i = 0; i < _activeStaticBodies.size(); ++i) {
_activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING);
}
_activeStaticBodies.clear();
_dynamicsWorld->synchronizeMotionStates(); _dynamicsWorld->synchronizeMotionStates();
_hasOutgoingChanges = false; _hasOutgoingChanges = false;
return _dynamicsWorld->getChangedMotionStates(); return _dynamicsWorld->getChangedMotionStates();

View file

@ -13,9 +13,9 @@
#define hifi_PhysicsEngine_h #define hifi_PhysicsEngine_h
#include <stdint.h> #include <stdint.h>
#include <vector>
#include <QUuid> #include <QUuid>
#include <QVector>
#include <btBulletDynamicsCommon.h> #include <btBulletDynamicsCommon.h>
#include <BulletCollision/CollisionDispatch/btGhostObject.h> #include <BulletCollision/CollisionDispatch/btGhostObject.h>
@ -41,7 +41,7 @@ public:
}; };
typedef std::map<ContactKey, ContactInfo> ContactMap; typedef std::map<ContactKey, ContactInfo> ContactMap;
typedef QVector<Collision> CollisionEvents; typedef std::vector<Collision> CollisionEvents;
class PhysicsEngine { class PhysicsEngine {
public: public:
@ -110,6 +110,7 @@ private:
ContactMap _contactMap; ContactMap _contactMap;
CollisionEvents _collisionEvents; CollisionEvents _collisionEvents;
QHash<QUuid, EntityActionPointer> _objectActions; QHash<QUuid, EntityActionPointer> _objectActions;
std::vector<btRigidBody*> _activeStaticBodies;
glm::vec3 _originOffset; glm::vec3 _originOffset;
QUuid _sessionID; QUuid _sessionID;
@ -121,7 +122,6 @@ private:
bool _dumpNextStats = false; bool _dumpNextStats = false;
bool _hasOutgoingChanges = false; bool _hasOutgoingChanges = false;
}; };
typedef std::shared_ptr<PhysicsEngine> PhysicsEnginePointer; typedef std::shared_ptr<PhysicsEngine> PhysicsEnginePointer;