From b3731e95308ce2f50e2770ed6005cda122e4b899 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 15 Dec 2014 14:36:27 -0800 Subject: [PATCH] hack for "reliable" packet send when objects stop moving --- libraries/physics/src/EntityMotionState.cpp | 16 +++++++-- libraries/physics/src/EntityMotionState.h | 2 +- libraries/physics/src/ObjectMotionState.cpp | 39 +++++++++++++++++---- libraries/physics/src/ObjectMotionState.h | 6 ++-- libraries/physics/src/PhysicsEngine.cpp | 6 ++-- 5 files changed, 53 insertions(+), 16 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index a4fd5cc498..bb87155bc3 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -108,7 +108,7 @@ void EntityMotionState::computeShapeInfo(ShapeInfo& info) { _entity->computeShapeInfo(info); } -void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { +void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) { #ifdef USE_BULLET_PHYSICS if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); @@ -165,12 +165,22 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender) { //properties.setLastEdited(now); glm::vec3 zero(0.0f); - _sentMoving = (_sentVelocity == zero && _sentAngularVelocity == zero && _sentAcceleration == zero); + _sentMoving = !(_sentVelocity == zero && _sentAngularVelocity == zero && _sentAcceleration == zero); + // RELIABLE_SEND_HACK: count number of updates for entities at rest so we can stop sending them after some limit. + if (_sentMoving) { + _numNonMovingUpdates = 0; + } else { + _numNonMovingUpdates++; + } EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); - _outgoingPacketFlags = 0; + + // The outgoing flags only itemized WHAT to send, not WHETHER to send, hence we always set them + // to the full set. These flags may be momentarily cleared by incoming external changes. + _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; + _sentFrame = frame; } #endif // USE_BULLET_PHYSICS } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 87dd3b14eb..ffd9e006e9 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -58,7 +58,7 @@ public: void computeShapeInfo(ShapeInfo& info); - void sendUpdate(OctreeEditPacketSender* packetSender); + void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame); uint32_t getIncomingDirtyFlags() const { return _entity->getDirtyFlags(); } void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index da23a4093c..1d315d4983 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -52,8 +52,8 @@ ObjectMotionState::ObjectMotionState() : _motionType(MOTION_TYPE_STATIC), _body(NULL), _sentMoving(false), - _weKnowRecipientHasReceivedNotMoving(false), - _outgoingPacketFlags(0), + _numNonMovingUpdates(0), + _outgoingPacketFlags(DIRTY_PHYSICS_FLAGS), _sentFrame(0), _sentPosition(0.0f), _sentRotation(), @@ -109,21 +109,48 @@ void ObjectMotionState::getAngularVelocity(glm::vec3& angularVelocityOut) const bulletToGLM(_body->getAngularVelocity(), angularVelocityOut); } +// RELIABLE_SEND_HACK: until we have truly reliable resends of non-moving updates +// we alwasy resend packets for objects that have stopped moving up to some max limit. +const int MAX_NUM_NON_MOVING_UPDATES = 5; + +bool ObjectMotionState::doesNotNeedToSendUpdate() const { + return !_body->isActive() && _numNonMovingUpdates > MAX_NUM_NON_MOVING_UPDATES; +} + const float FIXED_SUBSTEP = 1.0f / 60.0f; bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const { assert(_body); float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP + subStepRemainder; - const float DEFAULT_UPDATE_PERIOD = 10.0f; - if (dt > DEFAULT_UPDATE_PERIOD || (_sentMoving && !_body->isActive())) { - return true; + bool isActive = _body->isActive(); + + if (isActive) { + const float MAX_UPDATE_PERIOD_FOR_ACTIVE_THINGS = 10.0f; + if (dt > MAX_UPDATE_PERIOD_FOR_ACTIVE_THINGS) { + return true; + } + } else if (_sentMoving) { + if (!isActive) { + // this object just went inactive so send an update immediately + return true; + } + } else { + const float NON_MOVING_UPDATE_PERIOD = 1.0f; + if (dt > NON_MOVING_UPDATE_PERIOD && _numNonMovingUpdates < MAX_NUM_NON_MOVING_UPDATES) { + // RELIABLE_SEND_HACK: since we're not yet using a reliable method for non-moving update packets we repeat these + // at a faster rate than the MAX period above, and only send a limited number of them. + return true; + } } + // Else we measure the error between current and extrapolated transform (according to expected behavior // of remote EntitySimulation) and return true if the error is significant. // NOTE: math in done the simulation-frame, which is NOT necessarily the same as the world-frame // due to _worldOffset. + // TODO: Andrew to reconcile Bullet and legacy damping coefficients. + // compute position error glm::vec3 extrapolatedPosition = _sentPosition + dt * (_sentVelocity + (0.5f * dt) * _sentAcceleration); @@ -131,7 +158,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep btTransform worldTrans = _body->getWorldTransform(); bulletToGLM(worldTrans.getOrigin(), position); - float dx2 = glm::length2(position - extrapolatedPosition); + float dx2 = glm::distance2(position, extrapolatedPosition); const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m if (dx2 > MAX_POSITION_ERROR_SQUARED) { return true; diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 5e441a4746..ea9dcad0fc 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -81,9 +81,9 @@ public: virtual void clearIncomingDirtyFlags(uint32_t flags) = 0; void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; } - bool doesNotNeedToSendUpdate() const { return !_body->isActive() && _weKnowRecipientHasReceivedNotMoving; } + bool doesNotNeedToSendUpdate() const; virtual bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) const; - virtual void sendUpdate(OctreeEditPacketSender* packetSender) = 0; + virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0; virtual MotionType computeMotionType() const = 0; @@ -100,7 +100,7 @@ protected: btRigidBody* _body; bool _sentMoving; // true if last update was moving - bool _weKnowRecipientHasReceivedNotMoving; + int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects uint32_t _outgoingPacketFlags; uint32_t _sentFrame; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 198946e96d..f0f080e7c1 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -13,9 +13,9 @@ // TODO DONE: make MotionState::setWorldTransform() put itself on _incomingChanges list // TODO DONE: give PhysicsEngine instance an _entityPacketSender // TODO DONE: make sure code compiles when BULLET is not found -// TODO: make sure incoming and outgoing pipelines are connected -// TODO: provide some sort of "reliable" send for "stopped" update +// TODO DONE: make sure incoming and outgoing pipelines are connected // TODO: test entity updates (second viewer sees physics results from first) +// TODO: provide some sort of "reliable" send for "stopped" update #include "PhysicsEngine.h" #ifdef USE_BULLET_PHYSICS @@ -57,7 +57,7 @@ void PhysicsEngine::updateEntitiesInternal(const quint64& now) { if (state->doesNotNeedToSendUpdate()) { stateItr = _outgoingPackets.erase(stateItr); } else if (state->shouldSendUpdate(frame, subStepRemainder)) { - state->sendUpdate(_entityPacketSender); + state->sendUpdate(_entityPacketSender, frame); ++stateItr; } else { ++stateItr;