From 3e126c051713ca19ca6dccad25f9c1f217f14e50 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 12 Jun 2017 17:14:13 +1200 Subject: [PATCH 1/3] Smoothly ease hands from uncontrolled to controlled positions --- libraries/animation/src/Rig.cpp | 59 ++++++++++++++++++++++++++++----- libraries/animation/src/Rig.h | 4 ++- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 20a2aab2b6..2fc8638d5f 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1164,9 +1164,32 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f bool bodySensorTrackingEnabled = params.isLeftFootEnabled || params.isRightFootEnabled; const float RELAX_DURATION = 0.6f; + const float CONTROL_DURATION = 0.4f; if (params.isLeftEnabled) { + if (!_isLeftHandControlled) { + _leftHandControlDuration = CONTROL_DURATION; + _isLeftHandControlled = true; + } + glm::vec3 handPosition = params.leftPosition; + glm::quat handRotation = params.leftOrientation; + + if (_leftHandControlDuration > 0.0f) { + // Move hand from non-controlled position to controlled position. + _leftHandControlDuration = std::max(_leftHandControlDuration - dt, 0.0f); + auto ikNode = getAnimInverseKinematicsNode(); + if (ikNode) { + AnimPose handPose(Vectors::ONE, handRotation, handPosition); + float alpha = 1.0f - _leftHandControlDuration / CONTROL_DURATION; + const AnimPose geometryToRigTransform(_geometryToRigTransform); + AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledLeftHandPose(); + ::blend(1, &uncontrolledHandPose, &handPose, alpha, &handPose); + handPosition = handPose.trans(); + handRotation = handPose.rot(); + } + } + if (!bodySensorTrackingEnabled) { // prevent the hand IK targets from intersecting the body capsule glm::vec3 displacement; @@ -1176,18 +1199,17 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f } _animVars.set("leftHandPosition", handPosition); - _animVars.set("leftHandRotation", params.leftOrientation); + _animVars.set("leftHandRotation", handRotation); _animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition); - _isLeftHandControlled = true; - _lastLeftHandControlledPose = AnimPose(glm::vec3(1.0f), params.leftOrientation, handPosition); + _lastLeftHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition); } else { if (_isLeftHandControlled) { _leftHandRelaxDuration = RELAX_DURATION; _isLeftHandControlled = false; } - if (_leftHandRelaxDuration > 0) { + if (_leftHandRelaxDuration > 0.0f) { // Move hand from controlled position to non-controlled position. _leftHandRelaxDuration = std::max(_leftHandRelaxDuration - dt, 0.0f); auto ikNode = getAnimInverseKinematicsNode(); @@ -1209,7 +1231,29 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f } if (params.isRightEnabled) { + if (!_isRightHandControlled) { + _rightHandControlDuration = CONTROL_DURATION; + _isRightHandControlled = true; + } + glm::vec3 handPosition = params.rightPosition; + glm::quat handRotation = params.rightOrientation; + + if (_rightHandControlDuration > 0.0f) { + // Move hand from non-controlled position to controlled position. + _rightHandControlDuration = std::max(_rightHandControlDuration - dt, 0.0f); + auto ikNode = getAnimInverseKinematicsNode(); + if (ikNode) { + AnimPose handPose(Vectors::ONE, handRotation, handPosition); + float alpha = 1.0f - _rightHandControlDuration / CONTROL_DURATION; + const AnimPose geometryToRigTransform(_geometryToRigTransform); + AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledRightHandPose(); + ::blend(1, &uncontrolledHandPose, &handPose, alpha, &handPose); + handPosition = handPose.trans(); + handRotation = handPose.rot(); + } + } + if (!bodySensorTrackingEnabled) { // prevent the hand IK targets from intersecting the body capsule glm::vec3 displacement; @@ -1219,18 +1263,17 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f } _animVars.set("rightHandPosition", handPosition); - _animVars.set("rightHandRotation", params.rightOrientation); + _animVars.set("rightHandRotation", handRotation); _animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition); - _isRightHandControlled = true; - _lastRightHandControlledPose = AnimPose(glm::vec3(1.0f), params.rightOrientation, handPosition); + _lastRightHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition); } else { if (_isRightHandControlled) { _rightHandRelaxDuration = RELAX_DURATION; _isRightHandControlled = false; } - if (_rightHandRelaxDuration > 0) { + if (_rightHandRelaxDuration > 0.0f) { // Move hand from controlled position to non-controlled position. _rightHandRelaxDuration = std::max(_rightHandRelaxDuration - dt, 0.0f); auto ikNode = getAnimInverseKinematicsNode(); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 994bd4b074..c8efd70a71 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -354,7 +354,9 @@ private: bool _isLeftHandControlled { false }; bool _isRightHandControlled { false }; - float _leftHandRelaxDuration { 0.0f }; + float _leftHandControlDuration{ 0.0f }; + float _rightHandControlDuration{ 0.0f }; + float _leftHandRelaxDuration{ 0.0f }; float _rightHandRelaxDuration { 0.0f }; AnimPose _lastLeftHandControlledPose; AnimPose _lastRightHandControlledPose; From 5eee2d83525687e7376e68e8db5c324b402b5eb3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 13 Jun 2017 12:39:46 +1200 Subject: [PATCH 2/3] Code review --- libraries/animation/src/Rig.cpp | 32 ++++++++++++++++---------------- libraries/animation/src/Rig.h | 8 ++++---- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 2fc8638d5f..0362c42b39 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1168,20 +1168,20 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f if (params.isLeftEnabled) { if (!_isLeftHandControlled) { - _leftHandControlDuration = CONTROL_DURATION; + _leftHandControlTimeRemaining = CONTROL_DURATION; _isLeftHandControlled = true; } glm::vec3 handPosition = params.leftPosition; glm::quat handRotation = params.leftOrientation; - if (_leftHandControlDuration > 0.0f) { + if (_leftHandControlTimeRemaining > 0.0f) { // Move hand from non-controlled position to controlled position. - _leftHandControlDuration = std::max(_leftHandControlDuration - dt, 0.0f); + _leftHandControlTimeRemaining = std::max(_leftHandControlTimeRemaining - dt, 0.0f); auto ikNode = getAnimInverseKinematicsNode(); if (ikNode) { AnimPose handPose(Vectors::ONE, handRotation, handPosition); - float alpha = 1.0f - _leftHandControlDuration / CONTROL_DURATION; + float alpha = 1.0f - _leftHandControlTimeRemaining / CONTROL_DURATION; const AnimPose geometryToRigTransform(_geometryToRigTransform); AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledLeftHandPose(); ::blend(1, &uncontrolledHandPose, &handPose, alpha, &handPose); @@ -1205,16 +1205,16 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f _lastLeftHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition); } else { if (_isLeftHandControlled) { - _leftHandRelaxDuration = RELAX_DURATION; + _leftHandRelaxTimeRemaining = RELAX_DURATION; _isLeftHandControlled = false; } - if (_leftHandRelaxDuration > 0.0f) { + if (_leftHandRelaxTimeRemaining > 0.0f) { // Move hand from controlled position to non-controlled position. - _leftHandRelaxDuration = std::max(_leftHandRelaxDuration - dt, 0.0f); + _leftHandRelaxTimeRemaining = std::max(_leftHandRelaxTimeRemaining - dt, 0.0f); auto ikNode = getAnimInverseKinematicsNode(); if (ikNode) { - float alpha = 1.0f - _leftHandRelaxDuration / RELAX_DURATION; + float alpha = 1.0f - _leftHandRelaxTimeRemaining / RELAX_DURATION; const AnimPose geometryToRigTransform(_geometryToRigTransform); AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledLeftHandPose(); AnimPose handPose; @@ -1232,20 +1232,20 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f if (params.isRightEnabled) { if (!_isRightHandControlled) { - _rightHandControlDuration = CONTROL_DURATION; + _rightHandControlTimeRemaining = CONTROL_DURATION; _isRightHandControlled = true; } glm::vec3 handPosition = params.rightPosition; glm::quat handRotation = params.rightOrientation; - if (_rightHandControlDuration > 0.0f) { + if (_rightHandControlTimeRemaining > 0.0f) { // Move hand from non-controlled position to controlled position. - _rightHandControlDuration = std::max(_rightHandControlDuration - dt, 0.0f); + _rightHandControlTimeRemaining = std::max(_rightHandControlTimeRemaining - dt, 0.0f); auto ikNode = getAnimInverseKinematicsNode(); if (ikNode) { AnimPose handPose(Vectors::ONE, handRotation, handPosition); - float alpha = 1.0f - _rightHandControlDuration / CONTROL_DURATION; + float alpha = 1.0f - _rightHandControlTimeRemaining / CONTROL_DURATION; const AnimPose geometryToRigTransform(_geometryToRigTransform); AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledRightHandPose(); ::blend(1, &uncontrolledHandPose, &handPose, alpha, &handPose); @@ -1269,16 +1269,16 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f _lastRightHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition); } else { if (_isRightHandControlled) { - _rightHandRelaxDuration = RELAX_DURATION; + _rightHandRelaxTimeRemaining = RELAX_DURATION; _isRightHandControlled = false; } - if (_rightHandRelaxDuration > 0.0f) { + if (_rightHandRelaxTimeRemaining > 0.0f) { // Move hand from controlled position to non-controlled position. - _rightHandRelaxDuration = std::max(_rightHandRelaxDuration - dt, 0.0f); + _rightHandRelaxTimeRemaining = std::max(_rightHandRelaxTimeRemaining - dt, 0.0f); auto ikNode = getAnimInverseKinematicsNode(); if (ikNode) { - float alpha = 1.0f - _rightHandRelaxDuration / RELAX_DURATION; + float alpha = 1.0f - _rightHandRelaxTimeRemaining / RELAX_DURATION; const AnimPose geometryToRigTransform(_geometryToRigTransform); AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledRightHandPose(); AnimPose handPose; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index c8efd70a71..1cb1dac4f3 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -354,10 +354,10 @@ private: bool _isLeftHandControlled { false }; bool _isRightHandControlled { false }; - float _leftHandControlDuration{ 0.0f }; - float _rightHandControlDuration{ 0.0f }; - float _leftHandRelaxDuration{ 0.0f }; - float _rightHandRelaxDuration { 0.0f }; + float _leftHandControlTimeRemaining { 0.0f }; + float _rightHandControlTimeRemaining { 0.0f }; + float _leftHandRelaxTimeRemaining { 0.0f }; + float _rightHandRelaxTimeRemaining { 0.0f }; AnimPose _lastLeftHandControlledPose; AnimPose _lastRightHandControlledPose; }; From 570ec8457d0f1e24dce30ac1e20e2984b6ad9406 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 14 Jun 2017 10:45:30 +1200 Subject: [PATCH 3/3] Refactor --- libraries/animation/src/Rig.cpp | 66 +++++++++++++++++++-------------- libraries/animation/src/Rig.h | 3 ++ 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 0362c42b39..fbb3d24298 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1165,6 +1165,10 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f const float RELAX_DURATION = 0.6f; const float CONTROL_DURATION = 0.4f; + const bool TO_CONTROLLED = true; + const bool FROM_CONTROLLED = false; + const bool LEFT_HAND = true; + const bool RIGHT_HAND = false; if (params.isLeftEnabled) { if (!_isLeftHandControlled) { @@ -1178,13 +1182,9 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f if (_leftHandControlTimeRemaining > 0.0f) { // Move hand from non-controlled position to controlled position. _leftHandControlTimeRemaining = std::max(_leftHandControlTimeRemaining - dt, 0.0f); - auto ikNode = getAnimInverseKinematicsNode(); - if (ikNode) { - AnimPose handPose(Vectors::ONE, handRotation, handPosition); - float alpha = 1.0f - _leftHandControlTimeRemaining / CONTROL_DURATION; - const AnimPose geometryToRigTransform(_geometryToRigTransform); - AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledLeftHandPose(); - ::blend(1, &uncontrolledHandPose, &handPose, alpha, &handPose); + AnimPose handPose(Vectors::ONE, handRotation, handPosition); + if (transitionHandPose(_leftHandControlTimeRemaining, CONTROL_DURATION, handPose, LEFT_HAND, TO_CONTROLLED, + handPose)) { handPosition = handPose.trans(); handRotation = handPose.rot(); } @@ -1212,13 +1212,9 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f if (_leftHandRelaxTimeRemaining > 0.0f) { // Move hand from controlled position to non-controlled position. _leftHandRelaxTimeRemaining = std::max(_leftHandRelaxTimeRemaining - dt, 0.0f); - auto ikNode = getAnimInverseKinematicsNode(); - if (ikNode) { - float alpha = 1.0f - _leftHandRelaxTimeRemaining / RELAX_DURATION; - const AnimPose geometryToRigTransform(_geometryToRigTransform); - AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledLeftHandPose(); - AnimPose handPose; - ::blend(1, &_lastLeftHandControlledPose, &uncontrolledHandPose, alpha, &handPose); + AnimPose handPose; + if (transitionHandPose(_leftHandRelaxTimeRemaining, RELAX_DURATION, _lastLeftHandControlledPose, LEFT_HAND, + FROM_CONTROLLED, handPose)) { _animVars.set("leftHandPosition", handPose.trans()); _animVars.set("leftHandRotation", handPose.rot()); _animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition); @@ -1242,13 +1238,9 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f if (_rightHandControlTimeRemaining > 0.0f) { // Move hand from non-controlled position to controlled position. _rightHandControlTimeRemaining = std::max(_rightHandControlTimeRemaining - dt, 0.0f); - auto ikNode = getAnimInverseKinematicsNode(); - if (ikNode) { - AnimPose handPose(Vectors::ONE, handRotation, handPosition); - float alpha = 1.0f - _rightHandControlTimeRemaining / CONTROL_DURATION; - const AnimPose geometryToRigTransform(_geometryToRigTransform); - AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledRightHandPose(); - ::blend(1, &uncontrolledHandPose, &handPose, alpha, &handPose); + AnimPose handPose(Vectors::ONE, handRotation, handPosition); + if (transitionHandPose(_rightHandControlTimeRemaining, CONTROL_DURATION, handPose, RIGHT_HAND, TO_CONTROLLED, + handPose)) { handPosition = handPose.trans(); handRotation = handPose.rot(); } @@ -1276,13 +1268,9 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f if (_rightHandRelaxTimeRemaining > 0.0f) { // Move hand from controlled position to non-controlled position. _rightHandRelaxTimeRemaining = std::max(_rightHandRelaxTimeRemaining - dt, 0.0f); - auto ikNode = getAnimInverseKinematicsNode(); - if (ikNode) { - float alpha = 1.0f - _rightHandRelaxTimeRemaining / RELAX_DURATION; - const AnimPose geometryToRigTransform(_geometryToRigTransform); - AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledRightHandPose(); - AnimPose handPose; - ::blend(1, &_lastRightHandControlledPose, &uncontrolledHandPose, alpha, &handPose); + AnimPose handPose; + if (transitionHandPose(_rightHandRelaxTimeRemaining, RELAX_DURATION, _lastRightHandControlledPose, RIGHT_HAND, + FROM_CONTROLLED, handPose)) { _animVars.set("rightHandPosition", handPose.trans()); _animVars.set("rightHandRotation", handPose.rot()); _animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition); @@ -1588,3 +1576,25 @@ void Rig::computeAvatarBoundingCapsule( glm::vec3 rigCenter = (geometryToRig * (0.5f * (totalExtents.maximum + totalExtents.minimum))); localOffsetOut = rigCenter - (geometryToRig * rootPosition); } + +bool Rig::transitionHandPose(float deltaTime, float totalDuration, AnimPose& controlledHandPose, bool isLeftHand, + bool isToControlled, AnimPose& returnHandPose) { + auto ikNode = getAnimInverseKinematicsNode(); + if (ikNode) { + float alpha = 1.0f - deltaTime / totalDuration; + const AnimPose geometryToRigTransform(_geometryToRigTransform); + AnimPose uncontrolledHandPose; + if (isLeftHand) { + uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledLeftHandPose(); + } else { + uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledRightHandPose(); + } + if (isToControlled) { + ::blend(1, &uncontrolledHandPose, &controlledHandPose, alpha, &returnHandPose); + } else { + ::blend(1, &controlledHandPose, &uncontrolledHandPose, alpha, &returnHandPose); + } + return true; + } + return false; +} diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 1cb1dac4f3..b5b69fc018 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -352,6 +352,9 @@ private: int _nextStateHandlerId { 0 }; QMutex _stateMutex; + bool transitionHandPose(float deltaTime, float totalDuration, AnimPose& controlledHandPose, bool isLeftHand, + bool isToControlled, AnimPose& returnHandPose); + bool _isLeftHandControlled { false }; bool _isRightHandControlled { false }; float _leftHandControlTimeRemaining { 0.0f };