From e26081e9818a7e635249ebcc8db19b3ab38d8c8f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 23 Nov 2015 18:05:18 -0800 Subject: [PATCH] always update physics properties when they change and move activation check logic to MotionState --- libraries/audio/src/AudioConstants.h | 2 +- libraries/entities/src/EntityItem.cpp | 85 +++++++-------------- libraries/entities/src/EntityItem.h | 2 + libraries/physics/src/EntityMotionState.cpp | 6 +- libraries/physics/src/EntityMotionState.h | 4 +- libraries/physics/src/ObjectMotionState.cpp | 73 ++++++++++++++---- libraries/physics/src/ObjectMotionState.h | 4 +- 7 files changed, 95 insertions(+), 81 deletions(-) diff --git a/libraries/audio/src/AudioConstants.h b/libraries/audio/src/AudioConstants.h index e252a5354d..785060d364 100644 --- a/libraries/audio/src/AudioConstants.h +++ b/libraries/audio/src/AudioConstants.h @@ -35,4 +35,4 @@ namespace AudioConstants { } -#endif // hifi_AudioConstants_h \ No newline at end of file +#endif // hifi_AudioConstants_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 75bc26a560..992b6a1bdd 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -622,7 +622,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto nodeList = DependencyManager::get(); const QUuid& myNodeID = nodeList->getSessionUUID(); bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID); - + if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE) { // pack SimulationOwner and terse update properties near each other @@ -799,17 +799,11 @@ void EntityItem::setDensity(float density) { _density = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); } -const float ACTIVATION_RELATIVE_DENSITY_DELTA = 0.01f; // 1 percent - void EntityItem::updateDensity(float density) { float clampedDensity = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); if (_density != clampedDensity) { _density = clampedDensity; - - if (fabsf(_density - clampedDensity) / _density > ACTIVATION_RELATIVE_DENSITY_DELTA) { - // the density has changed enough that we should update the physics simulation - _dirtyFlags |= Simulation::DIRTY_MASS; - } + _dirtyFlags |= Simulation::DIRTY_MASS; } } @@ -822,11 +816,16 @@ void EntityItem::setMass(float mass) { // compute new density const float MIN_VOLUME = 1.0e-6f; // 0.001mm^3 + float newDensity = 1.0f; if (volume < 1.0e-6f) { // avoid divide by zero - _density = glm::min(mass / MIN_VOLUME, ENTITY_ITEM_MAX_DENSITY); + newDensity = glm::min(mass / MIN_VOLUME, ENTITY_ITEM_MAX_DENSITY); } else { - _density = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); + newDensity = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); + } + if (_density != newDensity) { + _density = newDensity; + _dirtyFlags |= Simulation::DIRTY_MASS; } } @@ -884,12 +883,12 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { #ifdef WANT_DEBUG qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed; #endif - + const float MIN_TIME_SKIP = 0.0f; const float MAX_TIME_SKIP = 1.0f; // in seconds - + timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP); - + if (hasActions()) { return; } @@ -1312,24 +1311,16 @@ void EntityItem::updatePosition(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; } - auto delta = glm::distance(getPosition(), value); - if (delta > IGNORE_POSITION_DELTA) { - _dirtyFlags |= Simulation::DIRTY_POSITION; + if (getPosition() != value) { setPosition(value); - if (delta > ACTIVATION_POSITION_DELTA) { - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } + _dirtyFlags |= Simulation::DIRTY_POSITION; } } void EntityItem::updateDimensions(const glm::vec3& value) { - auto delta = glm::distance(getDimensions(), value); - if (delta > IGNORE_DIMENSIONS_DELTA) { + if (getDimensions() != value) { setDimensions(value); - if (delta > ACTIVATION_DIMENSIONS_DELTA) { - // rebuilding the shape will always activate - _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); - } + _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); } } @@ -1339,14 +1330,7 @@ void EntityItem::updateRotation(const glm::quat& rotation) { } if (getRotation() != rotation) { setRotation(rotation); - - auto alignmentDot = glm::abs(glm::dot(getRotation(), rotation)); - if (alignmentDot < IGNORE_ALIGNMENT_DOT) { - _dirtyFlags |= Simulation::DIRTY_ROTATION; - } - if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } + _dirtyFlags |= Simulation::DIRTY_ROTATION; } } @@ -1367,11 +1351,8 @@ void EntityItem::updateMass(float mass) { newDensity = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); } - float oldDensity = _density; - _density = newDensity; - - if (fabsf(_density - oldDensity) / _density > ACTIVATION_RELATIVE_DENSITY_DELTA) { - // the density has changed enough that we should update the physics simulation + if (_density != newDensity) { + _density = newDensity; _dirtyFlags |= Simulation::DIRTY_MASS; } } @@ -1380,38 +1361,29 @@ void EntityItem::updateVelocity(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; } - auto delta = glm::distance(_velocity, value); - if (delta > IGNORE_LINEAR_VELOCITY_DELTA) { - _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; + if (_velocity != value) { const float MIN_LINEAR_SPEED = 0.001f; if (glm::length(value) < MIN_LINEAR_SPEED) { _velocity = ENTITY_ITEM_ZERO_VEC3; } else { _velocity = value; - // only activate when setting non-zero velocity - if (delta > ACTIVATION_LINEAR_VELOCITY_DELTA) { - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } } + _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; } } void EntityItem::updateDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); - if (fabsf(_damping - clampedDamping) > IGNORE_DAMPING_DELTA) { + if (_damping != clampedDamping) { _damping = clampedDamping; _dirtyFlags |= Simulation::DIRTY_MATERIAL; } } void EntityItem::updateGravity(const glm::vec3& value) { - auto delta = glm::distance(_gravity, value); - if (delta > IGNORE_GRAVITY_DELTA) { + if (_gravity != value) { _gravity = value; _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; - if (delta > ACTIVATION_GRAVITY_DELTA) { - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } } } @@ -1419,25 +1391,20 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; } - auto delta = glm::distance(_angularVelocity, value); - if (delta > IGNORE_ANGULAR_VELOCITY_DELTA) { - _dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY; + if (_angularVelocity != value) { const float MIN_ANGULAR_SPEED = 0.0002f; if (glm::length(value) < MIN_ANGULAR_SPEED) { _angularVelocity = ENTITY_ITEM_ZERO_VEC3; } else { _angularVelocity = value; - // only activate when setting non-zero velocity - if (delta > ACTIVATION_ANGULAR_VELOCITY_DELTA) { - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } } + _dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY; } } void EntityItem::updateAngularDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); - if (fabsf(_angularDamping - clampedDamping) > IGNORE_DAMPING_DELTA) { + if (_angularDamping != clampedDamping) { _angularDamping = clampedDamping; _dirtyFlags |= Simulation::DIRTY_MATERIAL; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 727a806b62..d80de4d427 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -48,6 +48,7 @@ namespace render { class PendingChanges; } +/* // these thesholds determine what updates will be ignored (client and server) const float IGNORE_POSITION_DELTA = 0.0001f; const float IGNORE_DIMENSIONS_DELTA = 0.0005f; @@ -64,6 +65,7 @@ const float ACTIVATION_ALIGNMENT_DOT = 0.99990f; const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; const float ACTIVATION_GRAVITY_DELTA = 0.1f; const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; +*/ #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 181ae7060e..34439e57ce 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -95,7 +95,7 @@ void EntityMotionState::updateServerPhysicsVariables(const QUuid& sessionID) { } // virtual -bool EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) { +bool EntityMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine) { assert(entityTreeIsLocked()); updateServerPhysicsVariables(engine->getSessionID()); ObjectMotionState::handleEasyChanges(flags, engine); @@ -120,7 +120,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) } if (flags & Simulation::DIRTY_SIMULATOR_OWNERSHIP) { // (DIRTY_SIMULATOR_OWNERSHIP really means "we should bid for ownership with SCRIPT priority") - // we're manipulating this object directly via script, so we artificially + // we're manipulating this object directly via script, so we artificially // manipulate the logic to trigger an immediate bid for ownership setOutgoingPriority(SCRIPT_EDIT_SIMULATION_PRIORITY); } @@ -133,7 +133,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) // virtual -bool EntityMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) { +bool EntityMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) { updateServerPhysicsVariables(engine->getSessionID()); return ObjectMotionState::handleHardAndEasyChanges(flags, engine); } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 188e7096b9..c666f87221 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -29,8 +29,8 @@ public: virtual ~EntityMotionState(); void updateServerPhysicsVariables(const QUuid& sessionID); - virtual bool handleEasyChanges(uint32_t flags, PhysicsEngine* engine); - virtual bool handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); + virtual bool handleEasyChanges(uint32_t& flags, PhysicsEngine* engine); + virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem virtual MotionType computeObjectMotionType() const; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index be0edafff5..c39f47eaf8 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -17,6 +17,14 @@ #include "PhysicsHelpers.h" #include "PhysicsLogging.h" +// these thresholds determine what updates (object-->body) will activate the physical object +const float ACTIVATION_POSITION_DELTA = 0.005f; +const float ACTIVATION_ALIGNMENT_DOT = 0.99990f; +const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; +const float ACTIVATION_GRAVITY_DELTA = 0.1f; +const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; + + // origin of physics simulation in world-frame glm::vec3 _worldOffset(0.0f); @@ -128,28 +136,65 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } -bool ObjectMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) { +bool ObjectMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine) { if (flags & Simulation::DIRTY_POSITION) { - btTransform worldTrans; - if (flags & Simulation::DIRTY_ROTATION) { - worldTrans.setRotation(glmToBullet(getObjectRotation())); - } else { - worldTrans = _body->getWorldTransform(); + btTransform worldTrans = _body->getWorldTransform(); + btVector3 newPosition = glmToBullet(getObjectPosition()); + float delta = (newPosition - worldTrans.getOrigin()).length(); + if (delta > ACTIVATION_POSITION_DELTA) { + flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + worldTrans.setOrigin(newPosition); + + if (flags & Simulation::DIRTY_ROTATION) { + btQuaternion newRotation = glmToBullet(getObjectRotation()); + float alignmentDot = fabsf(worldTrans.getRotation().dot(newRotation)); + if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { + flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + worldTrans.setRotation(newRotation); } - worldTrans.setOrigin(glmToBullet(getObjectPosition())); _body->setWorldTransform(worldTrans); } else if (flags & Simulation::DIRTY_ROTATION) { btTransform worldTrans = _body->getWorldTransform(); - worldTrans.setRotation(glmToBullet(getObjectRotation())); + btQuaternion newRotation = glmToBullet(getObjectRotation()); + float alignmentDot = fabsf(worldTrans.getRotation().dot(newRotation)); + if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { + flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + worldTrans.setRotation(newRotation); _body->setWorldTransform(worldTrans); } if (flags & Simulation::DIRTY_LINEAR_VELOCITY) { - _body->setLinearVelocity(glmToBullet(getObjectLinearVelocity())); - _body->setGravity(glmToBullet(getObjectGravity())); + btVector3 newLinearVelocity = glmToBullet(getObjectLinearVelocity()); + if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) { + float delta = (newLinearVelocity - _body->getLinearVelocity()).length(); + if (delta > ACTIVATION_LINEAR_VELOCITY_DELTA) { + flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + } + _body->setLinearVelocity(newLinearVelocity); + + btVector3 newGravity = glmToBullet(getObjectGravity()); + if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) { + float delta = (newGravity - _body->getGravity()).length(); + if (delta > ACTIVATION_GRAVITY_DELTA || + (delta > 0.0f && _body->getGravity().length2() == 0.0f)) { + flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + } + _body->setGravity(newGravity); } if (flags & Simulation::DIRTY_ANGULAR_VELOCITY) { - _body->setAngularVelocity(glmToBullet(getObjectAngularVelocity())); + btVector3 newAngularVelocity = glmToBullet(getObjectAngularVelocity()); + if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) { + float delta = (newAngularVelocity - _body->getAngularVelocity()).length(); + if (delta > ACTIVATION_ANGULAR_VELOCITY_DELTA) { + flags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + } + _body->setAngularVelocity(newAngularVelocity); } if (flags & Simulation::DIRTY_MATERIAL) { @@ -163,7 +208,7 @@ bool ObjectMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) return true; } -bool ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) { +bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) { if (flags & Simulation::DIRTY_SHAPE) { // make sure the new shape is valid if (!isReadyToComputeShape()) { @@ -195,8 +240,8 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* if (flags & EASY_DIRTY_PHYSICS_FLAGS) { handleEasyChanges(flags, engine); } - // it is possible that there are no HARD flags at this point (if DIRTY_SHAPE was removed) - // so we check again befoe we reinsert: + // it is possible there are no HARD flags at this point (if DIRTY_SHAPE was removed) + // so we check again before we reinsert: if (flags & HARD_DIRTY_PHYSICS_FLAGS) { engine->reinsertObject(this); } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 992bdd11d7..7d5c727d6d 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -80,8 +80,8 @@ public: ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); - virtual bool handleEasyChanges(uint32_t flags, PhysicsEngine* engine); - virtual bool handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); + virtual bool handleEasyChanges(uint32_t& flags, PhysicsEngine* engine); + virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); void updateBodyMaterialProperties(); void updateBodyVelocities();