From c739db75621f9f28790ad7cbc3c5d3f743fd8b74 Mon Sep 17 00:00:00 2001 From: trent Date: Wed, 5 Apr 2017 17:39:52 -0400 Subject: [PATCH 1/5] Added quadratic ease-in-and-out smoothing to remote avatars position/orientation updates (through... one path, at least?). --- interface/src/avatar/Avatar.cpp | 57 ++++++++++++++++++++++++++++++--- interface/src/avatar/Avatar.h | 13 ++++++++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ade98c63d8..c1ba0bca65 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -97,7 +97,15 @@ Avatar::Avatar(RigPointer rig) : _worldUpDirection(DEFAULT_UP_DIRECTION), _moving(false), _initialized(false), - _voiceSphereID(GeometryCache::UNKNOWN_ID) + _voiceSphereID(GeometryCache::UNKNOWN_ID), + _smoothPositionTime(0.15f), + _smoothPositionTimer(std::numeric_limits::max()), + _smoothOrientationTime(0.15f), + _smoothOrientationTimer(std::numeric_limits::max()), + _smoothPositionInitial(), + _smoothPositionTarget(), + _smoothOrientationInitial(), + _smoothOrientationTarget() { // we may have been created in the network thread, but we live in the main thread moveToThread(qApp->thread()); @@ -342,6 +350,25 @@ void Avatar::simulate(float deltaTime, bool inView) { _simulationInViewRate.increment(); } + if (!isMyAvatar()) { + if (_smoothPositionTimer < _smoothPositionTime) { + // Smooth the remote avatar movement. + _smoothPositionTimer += deltaTime; + if (_smoothPositionTimer < _smoothPositionTime) { + AvatarData::setPosition(lerp(_smoothPositionInitial, _smoothPositionTarget, easeInOutQuad(_smoothPositionTimer / _smoothPositionTime))); + updateAttitude(); + } + } + + if (_smoothOrientationTimer < _smoothOrientationTime) { + // Smooth the remote avatar movement. + _smoothOrientationTimer += deltaTime; + if (_smoothOrientationTimer < _smoothOrientationTime) { + AvatarData::setOrientation(slerp(_smoothOrientationInitial, _smoothOrientationTarget, easeInOutQuad(_smoothOrientationTimer / _smoothOrientationTime))); + updateAttitude(); + } + } + } PerformanceTimer perfTimer("simulate"); { @@ -1343,13 +1370,33 @@ glm::quat Avatar::getUncachedRightPalmRotation() const { } void Avatar::setPosition(const glm::vec3& position) { - AvatarData::setPosition(position); - updateAttitude(); + if (isMyAvatar()) { + // This is the local avatar, no need to handle any position smoothing. + AvatarData::setPosition(position); + updateAttitude(); + + return; + } + + // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position. + _smoothPositionInitial = getPosition(); + _smoothPositionTarget = position; + _smoothPositionTimer = 0.0f; } void Avatar::setOrientation(const glm::quat& orientation) { - AvatarData::setOrientation(orientation); - updateAttitude(); + if (isMyAvatar()) { + // This is the local avatar, no need to handle any position smoothing. + AvatarData::setOrientation(orientation); + updateAttitude(); + + return; + } + + // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position. + _smoothOrientationInitial = getOrientation(); + _smoothOrientationTarget = orientation; + _smoothOrientationTimer = 0.0f; } void Avatar::updatePalms() { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index ba7e1c617e..8d97553039 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -210,6 +210,10 @@ public: bool hasNewJointData() const { return _hasNewJointData; } + inline float easeInOutQuad(float t) { + return((t < 0.5) ? (2*t*t) : (t*(4 - 2*t) - 1)); + } + public slots: // FIXME - these should be migrated to use Pose data instead @@ -292,6 +296,15 @@ protected: RateCounter<> _skeletonModelSimulationRate; RateCounter<> _jointDataSimulationRate; + // Smoothing data for blending from one position/orientation to another on remote agents. + float _smoothPositionTime; + float _smoothPositionTimer; + float _smoothOrientationTime; + float _smoothOrientationTimer; + glm::vec3 _smoothPositionInitial; + glm::vec3 _smoothPositionTarget; + glm::quat _smoothOrientationInitial; + glm::quat _smoothOrientationTarget; private: class AvatarEntityDataHash { From 43b3a6c6246a954b81302f6dd0b1d9c67aa253c8 Mon Sep 17 00:00:00 2001 From: trent Date: Wed, 5 Apr 2017 21:31:13 -0400 Subject: [PATCH 2/5] Addressing some style inconsitency issues, as well as making the position/orientation times constants. --- interface/src/avatar/Avatar.cpp | 92 ++++++++++++++++----------------- interface/src/avatar/Avatar.h | 3 ++ 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index c1ba0bca65..08f5c856b8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -98,14 +98,14 @@ Avatar::Avatar(RigPointer rig) : _moving(false), _initialized(false), _voiceSphereID(GeometryCache::UNKNOWN_ID), - _smoothPositionTime(0.15f), - _smoothPositionTimer(std::numeric_limits::max()), - _smoothOrientationTime(0.15f), - _smoothOrientationTimer(std::numeric_limits::max()), - _smoothPositionInitial(), - _smoothPositionTarget(), - _smoothOrientationInitial(), - _smoothOrientationTarget() + _smoothPositionTime(SMOOTH_TIME_POSITION), + _smoothPositionTimer(std::numeric_limits::max()), + _smoothOrientationTime(SMOOTH_TIME_ORIENTATION), + _smoothOrientationTimer(std::numeric_limits::max()), + _smoothPositionInitial(), + _smoothPositionTarget(), + _smoothOrientationInitial(), + _smoothOrientationTarget() { // we may have been created in the network thread, but we live in the main thread moveToThread(qApp->thread()); @@ -350,25 +350,25 @@ void Avatar::simulate(float deltaTime, bool inView) { _simulationInViewRate.increment(); } - if (!isMyAvatar()) { - if (_smoothPositionTimer < _smoothPositionTime) { - // Smooth the remote avatar movement. - _smoothPositionTimer += deltaTime; - if (_smoothPositionTimer < _smoothPositionTime) { - AvatarData::setPosition(lerp(_smoothPositionInitial, _smoothPositionTarget, easeInOutQuad(_smoothPositionTimer / _smoothPositionTime))); - updateAttitude(); - } - } + if (!isMyAvatar()) { + if (_smoothPositionTimer < _smoothPositionTime) { + // Smooth the remote avatar movement. + _smoothPositionTimer += deltaTime; + if (_smoothPositionTimer < _smoothPositionTime) { + AvatarData::setPosition(lerp(_smoothPositionInitial, _smoothPositionTarget, easeInOutQuad(_smoothPositionTimer / _smoothPositionTime))); + updateAttitude(); + } + } - if (_smoothOrientationTimer < _smoothOrientationTime) { - // Smooth the remote avatar movement. - _smoothOrientationTimer += deltaTime; - if (_smoothOrientationTimer < _smoothOrientationTime) { - AvatarData::setOrientation(slerp(_smoothOrientationInitial, _smoothOrientationTarget, easeInOutQuad(_smoothOrientationTimer / _smoothOrientationTime))); - updateAttitude(); - } - } - } + if (_smoothOrientationTimer < _smoothOrientationTime) { + // Smooth the remote avatar movement. + _smoothOrientationTimer += deltaTime; + if (_smoothOrientationTimer < _smoothOrientationTime) { + AvatarData::setOrientation(slerp(_smoothOrientationInitial, _smoothOrientationTarget, easeInOutQuad(_smoothOrientationTimer / _smoothOrientationTime))); + updateAttitude(); + } + } + } PerformanceTimer perfTimer("simulate"); { @@ -1370,33 +1370,33 @@ glm::quat Avatar::getUncachedRightPalmRotation() const { } void Avatar::setPosition(const glm::vec3& position) { - if (isMyAvatar()) { - // This is the local avatar, no need to handle any position smoothing. - AvatarData::setPosition(position); - updateAttitude(); + if (isMyAvatar()) { + // This is the local avatar, no need to handle any position smoothing. + AvatarData::setPosition(position); + updateAttitude(); - return; - } + return; + } - // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position. - _smoothPositionInitial = getPosition(); - _smoothPositionTarget = position; - _smoothPositionTimer = 0.0f; + // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position. + _smoothPositionInitial = getPosition(); + _smoothPositionTarget = position; + _smoothPositionTimer = 0.0f; } void Avatar::setOrientation(const glm::quat& orientation) { - if (isMyAvatar()) { - // This is the local avatar, no need to handle any position smoothing. - AvatarData::setOrientation(orientation); - updateAttitude(); + if (isMyAvatar()) { + // This is the local avatar, no need to handle any position smoothing. + AvatarData::setOrientation(orientation); + updateAttitude(); - return; - } + return; + } - // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position. - _smoothOrientationInitial = getOrientation(); - _smoothOrientationTarget = orientation; - _smoothOrientationTimer = 0.0f; + // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position. + _smoothOrientationInitial = getOrientation(); + _smoothOrientationTarget = orientation; + _smoothOrientationTimer = 0.0f; } void Avatar::updatePalms() { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 8d97553039..e0bdeff411 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -228,6 +228,9 @@ public slots: protected: friend class AvatarManager; + const float SMOOTH_TIME_POSITION = 0.125f; + const float SMOOTH_TIME_ORIENTATION = 0.075f; + virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send. QString _empty{}; virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter! From 76d3e6d5983e4e8fc46428b47d3cd26459272b33 Mon Sep 17 00:00:00 2001 From: trent Date: Thu, 6 Apr 2017 13:21:59 -0400 Subject: [PATCH 3/5] Added an assert for out-of-bounds values in the smoothing function; also clamped the values that I was sending in on the avatar-side. --- interface/src/avatar/Avatar.cpp | 4 ++-- interface/src/avatar/Avatar.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 08f5c856b8..a4ab999a9c 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -355,7 +355,7 @@ void Avatar::simulate(float deltaTime, bool inView) { // Smooth the remote avatar movement. _smoothPositionTimer += deltaTime; if (_smoothPositionTimer < _smoothPositionTime) { - AvatarData::setPosition(lerp(_smoothPositionInitial, _smoothPositionTarget, easeInOutQuad(_smoothPositionTimer / _smoothPositionTime))); + AvatarData::setPosition(lerp(_smoothPositionInitial, _smoothPositionTarget, easeInOutQuad(glm::clamp(_smoothPositionTimer / _smoothPositionTime, 0.0f, 1.0f)))); updateAttitude(); } } @@ -364,7 +364,7 @@ void Avatar::simulate(float deltaTime, bool inView) { // Smooth the remote avatar movement. _smoothOrientationTimer += deltaTime; if (_smoothOrientationTimer < _smoothOrientationTime) { - AvatarData::setOrientation(slerp(_smoothOrientationInitial, _smoothOrientationTarget, easeInOutQuad(_smoothOrientationTimer / _smoothOrientationTime))); + AvatarData::setOrientation(slerp(_smoothOrientationInitial, _smoothOrientationTarget, easeInOutQuad(glm::clamp(_smoothOrientationTimer / _smoothOrientationTime, 0.0f, 1.0f)))); updateAttitude(); } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index e0bdeff411..ed6bd96a75 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -211,7 +211,9 @@ public: bool hasNewJointData() const { return _hasNewJointData; } inline float easeInOutQuad(float t) { - return((t < 0.5) ? (2*t*t) : (t*(4 - 2*t) - 1)); + assert(!((t < 0.0f) || (t > 1.0f))); + + return((t < 0.5f) ? (2.0f*t*t) : (t*(4.0f - 2.0f*t) - 1.0f)); } public slots: From 21f810e040ac8d0eace476c2223493a7d7791d32 Mon Sep 17 00:00:00 2001 From: trent Date: Thu, 6 Apr 2017 14:50:16 -0400 Subject: [PATCH 4/5] Fixed formatting concerns as well as a benign order-of-constructor warning. --- interface/src/avatar/Avatar.cpp | 24 ++++++++++++++--------- interface/src/avatar/Avatar.h | 34 ++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a4ab999a9c..4b427e8221 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -97,15 +97,15 @@ Avatar::Avatar(RigPointer rig) : _worldUpDirection(DEFAULT_UP_DIRECTION), _moving(false), _initialized(false), - _voiceSphereID(GeometryCache::UNKNOWN_ID), - _smoothPositionTime(SMOOTH_TIME_POSITION), + _smoothPositionTime(SMOOTH_TIME_POSITION), _smoothPositionTimer(std::numeric_limits::max()), - _smoothOrientationTime(SMOOTH_TIME_ORIENTATION), + _smoothOrientationTime(SMOOTH_TIME_ORIENTATION), _smoothOrientationTimer(std::numeric_limits::max()), _smoothPositionInitial(), _smoothPositionTarget(), _smoothOrientationInitial(), - _smoothOrientationTarget() + _smoothOrientationTarget(), + _voiceSphereID(GeometryCache::UNKNOWN_ID) { // we may have been created in the network thread, but we live in the main thread moveToThread(qApp->thread()); @@ -355,7 +355,11 @@ void Avatar::simulate(float deltaTime, bool inView) { // Smooth the remote avatar movement. _smoothPositionTimer += deltaTime; if (_smoothPositionTimer < _smoothPositionTime) { - AvatarData::setPosition(lerp(_smoothPositionInitial, _smoothPositionTarget, easeInOutQuad(glm::clamp(_smoothPositionTimer / _smoothPositionTime, 0.0f, 1.0f)))); + AvatarData::setPosition( + lerp(_smoothPositionInitial, + _smoothPositionTarget, + easeInOutQuad(glm::clamp(_smoothPositionTimer / _smoothPositionTime, 0.0f, 1.0f))) + ); updateAttitude(); } } @@ -364,8 +368,12 @@ void Avatar::simulate(float deltaTime, bool inView) { // Smooth the remote avatar movement. _smoothOrientationTimer += deltaTime; if (_smoothOrientationTimer < _smoothOrientationTime) { - AvatarData::setOrientation(slerp(_smoothOrientationInitial, _smoothOrientationTarget, easeInOutQuad(glm::clamp(_smoothOrientationTimer / _smoothOrientationTime, 0.0f, 1.0f)))); - updateAttitude(); + AvatarData::setOrientation( + slerp(_smoothOrientationInitial, + _smoothOrientationTarget, + easeInOutQuad(glm::clamp(_smoothOrientationTimer / _smoothOrientationTime, 0.0f, 1.0f))) + ); + updateAttitude(); } } } @@ -1374,7 +1382,6 @@ void Avatar::setPosition(const glm::vec3& position) { // This is the local avatar, no need to handle any position smoothing. AvatarData::setPosition(position); updateAttitude(); - return; } @@ -1389,7 +1396,6 @@ void Avatar::setOrientation(const glm::quat& orientation) { // This is the local avatar, no need to handle any position smoothing. AvatarData::setOrientation(orientation); updateAttitude(); - return; } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index ed6bd96a75..2091ab4208 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -210,11 +210,15 @@ public: bool hasNewJointData() const { return _hasNewJointData; } - inline float easeInOutQuad(float t) { - assert(!((t < 0.0f) || (t > 1.0f))); + inline float easeInOutQuad(float lerpValue) { + assert(!((lerpValue < 0.0f) || (lerpValue > 1.0f))); - return((t < 0.5f) ? (2.0f*t*t) : (t*(4.0f - 2.0f*t) - 1.0f)); - } + if (lerpValue < 0.5f) { + return (2.0f * lerpValue * lerpValue); + } + + return (lerpValue*(4.0f - 2.0f * lerpValue) - 1.0f); + } public slots: @@ -230,8 +234,8 @@ public slots: protected: friend class AvatarManager; - const float SMOOTH_TIME_POSITION = 0.125f; - const float SMOOTH_TIME_ORIENTATION = 0.075f; + const float SMOOTH_TIME_POSITION = 0.125f; + const float SMOOTH_TIME_ORIENTATION = 0.075f; virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send. QString _empty{}; @@ -301,15 +305,15 @@ protected: RateCounter<> _skeletonModelSimulationRate; RateCounter<> _jointDataSimulationRate; - // Smoothing data for blending from one position/orientation to another on remote agents. - float _smoothPositionTime; - float _smoothPositionTimer; - float _smoothOrientationTime; - float _smoothOrientationTimer; - glm::vec3 _smoothPositionInitial; - glm::vec3 _smoothPositionTarget; - glm::quat _smoothOrientationInitial; - glm::quat _smoothOrientationTarget; + // Smoothing data for blending from one position/orientation to another on remote agents. + float _smoothPositionTime; + float _smoothPositionTimer; + float _smoothOrientationTime; + float _smoothOrientationTimer; + glm::vec3 _smoothPositionInitial; + glm::vec3 _smoothPositionTarget; + glm::quat _smoothOrientationInitial; + glm::quat _smoothOrientationTarget; private: class AvatarEntityDataHash { From 584905a618f0abaaab12b38072b0d2c586ceb27a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 6 Apr 2017 15:41:35 -0700 Subject: [PATCH 5/5] fix warning --- interface/src/avatar/Avatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 4b427e8221..92b0d40f93 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -96,7 +96,6 @@ Avatar::Avatar(RigPointer rig) : _lastOrientation(), _worldUpDirection(DEFAULT_UP_DIRECTION), _moving(false), - _initialized(false), _smoothPositionTime(SMOOTH_TIME_POSITION), _smoothPositionTimer(std::numeric_limits::max()), _smoothOrientationTime(SMOOTH_TIME_ORIENTATION), @@ -105,6 +104,7 @@ Avatar::Avatar(RigPointer rig) : _smoothPositionTarget(), _smoothOrientationInitial(), _smoothOrientationTarget(), + _initialized(false), _voiceSphereID(GeometryCache::UNKNOWN_ID) { // we may have been created in the network thread, but we live in the main thread