diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index 914fe8ba69..c9552a3ead 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -87,7 +87,8 @@ "weightVar": "rightFootWeight", "weight": 1.0, "flexCoefficients": [1, 0.45, 0.45], - "poleJointNameVar": "rightFootPoleJointName", + "poleVectorEnabledVar": "rightFootPoleVectorEnabled", + "poleReferenceVectorVar": "rightFootPoleReferenceVector", "poleVectorVar": "rightFootPoleVector" }, { @@ -98,7 +99,8 @@ "weightVar": "leftFootWeight", "weight": 1.0, "flexCoefficients": [1, 0.45, 0.45], - "poleJointNameVar": "leftFootPoleJointName", + "poleVectorEnabledVar": "leftFootPoleVectorEnabled", + "poleReferenceVectorVar": "leftFootPoleReferenceVector", "poleVectorVar": "leftFootPoleVector" }, { diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 57fa6fd1e3..2a493a96ab 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -48,13 +48,14 @@ float easeOutExpo(float t) { AnimInverseKinematics::IKTargetVar::IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn, const QString& typeVarIn, const QString& weightVarIn, float weightIn, const std::vector& flexCoefficientsIn, - const QString& poleJointNameVarIn, const QString& poleVectorVarIn) : + const QString& poleVectorEnabledVarIn, const QString& poleReferenceVectorVarIn, const QString& poleVectorVarIn) : jointName(jointNameIn), positionVar(positionVarIn), rotationVar(rotationVarIn), typeVar(typeVarIn), weightVar(weightVarIn), - poleJointNameVar(poleJointNameVarIn), + poleVectorEnabledVar(poleVectorEnabledVarIn), + poleReferenceVectorVar(poleReferenceVectorVarIn), poleVectorVar(poleVectorVarIn), weight(weightIn), numFlexCoefficients(flexCoefficientsIn.size()), @@ -72,7 +73,8 @@ AnimInverseKinematics::IKTargetVar::IKTargetVar(const IKTargetVar& orig) : rotationVar(orig.rotationVar), typeVar(orig.typeVar), weightVar(orig.weightVar), - poleJointNameVar(orig.poleJointNameVar), + poleVectorEnabledVar(orig.poleVectorEnabledVar), + poleReferenceVectorVar(orig.poleReferenceVectorVar), poleVectorVar(orig.poleVectorVar), weight(orig.weight), numFlexCoefficients(orig.numFlexCoefficients), @@ -128,8 +130,8 @@ void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) con void AnimInverseKinematics::setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar, const QString& typeVar, const QString& weightVar, float weight, const std::vector& flexCoefficients, - const QString& poleJointNameVar, const QString& poleVectorVar) { - IKTargetVar targetVar(jointName, positionVar, rotationVar, typeVar, weightVar, weight, flexCoefficients, poleJointNameVar, poleVectorVar); + const QString& poleVectorEnabledVar, const QString& poleReferenceVectorVar, const QString& poleVectorVar) { + IKTargetVar targetVar(jointName, positionVar, rotationVar, typeVar, weightVar, weight, flexCoefficients, poleVectorEnabledVar, poleReferenceVectorVar, poleVectorVar); // if there are dups, last one wins. bool found = false; @@ -177,14 +179,15 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: target.setWeight(weight); target.setFlexCoefficients(targetVar.numFlexCoefficients, targetVar.flexCoefficients); - // AJT: TODO: cache the pole joint index. - QString poleJointName = animVars.lookup(targetVar.poleJointNameVar, QString("")); - int poleJointIndex = _skeleton->nameToJointIndex(poleJointName); - target.setPoleIndex(poleJointIndex); + bool poleVectorEnabled = animVars.lookup(targetVar.poleVectorEnabledVar, false); + target.setPoleVectorEnabled(poleVectorEnabled); glm::vec3 poleVector = animVars.lookupRigToGeometryVector(targetVar.poleVectorVar, Vectors::UNIT_Z); target.setPoleVector(glm::normalize(poleVector)); + glm::vec3 poleReferenceVector = animVars.lookupRigToGeometryVector(targetVar.poleReferenceVectorVar, Vectors::UNIT_Z); + target.setPoleReferenceVector(glm::normalize(poleReferenceVector)); + targets.push_back(target); if (targetVar.jointIndex > _maxTargetIndex) { @@ -488,9 +491,8 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const chainDepth++; } - if (target.getPoleIndex() != -1) { - - int topJointIndex = target.getPoleIndex(); + if (target.getPoleVectorEnabled()) { + int topJointIndex = target.getIndex(); int midJointIndex = _skeleton->getParentIndex(topJointIndex); if (midJointIndex != -1) { int baseJointIndex = _skeleton->getParentIndex(midJointIndex); @@ -525,17 +527,16 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const float dLen = glm::length(d); if (dLen > EPSILON) { glm::vec3 dUnit = d / dLen; - glm::vec3 e = midPose.trans() - basePose.trans(); + glm::vec3 e = midPose.xformVector(target.getPoleReferenceVector()); glm::vec3 p = target.getPoleVector(); glm::vec3 eProj = e - glm::dot(e, dUnit) * dUnit; glm::vec3 pProj = p - glm::dot(p, dUnit) * dUnit; float eProjLen = glm::length(eProj); float pProjLen = glm::length(pProj); - const float MIN_E_PROJ_LEN = 0.2f; // cm - if (eProjLen > MIN_E_PROJ_LEN && pProjLen > EPSILON) { + if (eProjLen > EPSILON && pProjLen > EPSILON) { - // as eProjLen and pProjLen become orthognal to d, reduce the amount of rotation. - float magnitude = easeOutExpo(glm::min(eProjLen, pProjLen)); + // as pProjLen become orthognal to d, reduce the amount of rotation. + float magnitude = easeOutExpo(pProjLen); float dot = glm::clamp(glm::dot(eProj / eProjLen, pProj / pProjLen), 0.0f, 1.0f); float theta = acosf(dot); @@ -558,7 +559,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const AnimPose geomToWorldPose = AnimPose(context.getRigToWorldMatrix() * context.getGeometryToRigMatrix()); glm::vec3 dUnit = d / dLen; - glm::vec3 e = midPose.trans() - basePose.trans(); + glm::vec3 e = midPose.xformVector(target.getPoleReferenceVector()); glm::vec3 p = target.getPoleVector(); glm::vec3 eProj = e - glm::dot(e, dUnit) * dUnit; glm::vec3 pProj = p - glm::dot(p, dUnit) * dUnit; diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index 946c23883e..016317aee3 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -43,7 +43,7 @@ public: void setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar, const QString& typeVar, const QString& weightVar, float weight, const std::vector& flexCoefficients, - const QString& poleJointNameVar, const QString& poleVectorVar); + const QString& poleVectorEnabledVar, const QString& poleReferenceVectorVar, const QString& poleVectorVar); virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimNode::Triggers& triggersOut) override; virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override; @@ -110,7 +110,7 @@ protected: struct IKTargetVar { IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn, const QString& typeVarIn, const QString& weightVarIn, float weightIn, const std::vector& flexCoefficientsIn, - const QString& poleJointNameVar, const QString& poleVectorVar); + const QString& poleVectorEnabledVar, const QString& poleReferenceVectorVar, const QString& poleVectorVar); IKTargetVar(const IKTargetVar& orig); QString jointName; @@ -118,7 +118,8 @@ protected: QString rotationVar; QString typeVar; QString weightVar; - QString poleJointNameVar; + QString poleVectorEnabledVar; + QString poleReferenceVectorVar; QString poleVectorVar; float weight; float flexCoefficients[MAX_FLEX_COEFFICIENTS]; diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index c4a149a35b..2a1978127d 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -479,7 +479,8 @@ AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QS READ_OPTIONAL_STRING(typeVar, targetObj); READ_OPTIONAL_STRING(weightVar, targetObj); READ_OPTIONAL_FLOAT(weight, targetObj, 1.0f); - READ_OPTIONAL_STRING(poleJointNameVar, targetObj); + READ_OPTIONAL_STRING(poleVectorEnabledVar, targetObj); + READ_OPTIONAL_STRING(poleReferenceVectorVar, targetObj); READ_OPTIONAL_STRING(poleVectorVar, targetObj); auto flexCoefficientsValue = targetObj.value("flexCoefficients"); @@ -493,7 +494,7 @@ AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QS flexCoefficients.push_back((float)value.toDouble()); } - node->setTargetVars(jointName, positionVar, rotationVar, typeVar, weightVar, weight, flexCoefficients, poleJointNameVar, poleVectorVar); + node->setTargetVars(jointName, positionVar, rotationVar, typeVar, weightVar, weight, flexCoefficients, poleVectorEnabledVar, poleReferenceVectorVar, poleVectorVar); }; READ_OPTIONAL_STRING(solutionSource, jsonObj); diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h index c476e9c9da..5567539659 100644 --- a/libraries/animation/src/IKTarget.h +++ b/libraries/animation/src/IKTarget.h @@ -31,13 +31,15 @@ public: const glm::quat& getRotation() const { return _pose.rot(); } const AnimPose& getPose() const { return _pose; } glm::vec3 getPoleVector() const { return _poleVector; } - int getPoleIndex() const { return _poleIndex; } + glm::vec3 getPoleReferenceVector() const { return _poleReferenceVector; } + bool getPoleVectorEnabled() const { return _poleVectorEnabled; } int getIndex() const { return _index; } Type getType() const { return _type; } void setPose(const glm::quat& rotation, const glm::vec3& translation); void setPoleVector(const glm::vec3& poleVector) { _poleVector = poleVector; } - void setPoleIndex(int poleIndex) { _poleIndex = poleIndex; } + void setPoleReferenceVector(const glm::vec3& poleReferenceVector) { _poleReferenceVector = poleReferenceVector; } + void setPoleVectorEnabled(bool poleVectorEnabled) { _poleVectorEnabled = poleVectorEnabled; } void setIndex(int index) { _index = index; } void setType(int); void setFlexCoefficients(size_t numFlexCoefficientsIn, const float* flexCoefficientsIn); @@ -51,7 +53,8 @@ public: private: AnimPose _pose; glm::vec3 _poleVector; - int _poleIndex { -1 }; + glm::vec3 _poleReferenceVector; + bool _poleVectorEnabled { false }; int _index { -1 }; Type _type { Type::RotationAndPosition }; float _weight; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 2966e882d2..1e6965faf5 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1261,6 +1261,8 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f } } + const float POLE_VECTOR_BLEND_FACTOR = 0.9f; + if (params.isLeftFootEnabled) { _animVars.set("leftFootPosition", params.leftFootPosition); _animVars.set("leftFootRotation", params.leftFootOrientation); @@ -1274,16 +1276,16 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f _prevLeftFootPoleVectorValid = true; _prevLeftFootPoleVector = poleVector; } - const float POLE_VECTOR_BLEND_FACTOR = 0.9f; _prevLeftFootPoleVector = lerp(poleVector, _prevLeftFootPoleVector, POLE_VECTOR_BLEND_FACTOR); + _animVars.set("leftFootPoleVectorEnabled", true); + _animVars.set("leftFootPoleReferenceVector", Vectors::UNIT_Z); _animVars.set("leftFootPoleVector", _prevLeftFootPoleVector); - _animVars.set("leftFootPoleJointName", QString("LeftFoot")); - } else { _animVars.unset("leftFootPosition"); _animVars.unset("leftFootRotation"); _animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition); + _animVars.set("leftFootPoleVectorEnabled", false); _prevLeftFootPoleVectorValid = false; } @@ -1300,14 +1302,15 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f _prevRightFootPoleVectorValid = true; _prevRightFootPoleVector = poleVector; } - const float POLE_VECTOR_BLEND_FACTOR = 0.9f; _prevRightFootPoleVector = lerp(poleVector, _prevRightFootPoleVector, POLE_VECTOR_BLEND_FACTOR); + _animVars.set("rightFootPoleVectorEnabled", true); + _animVars.set("rightFootPoleReferenceVector", Vectors::UNIT_Z); _animVars.set("rightFootPoleVector", _prevRightFootPoleVector); - _animVars.set("rightFootPoleJointName", QString("RightFoot")); } else { _animVars.unset("rightFootPosition"); _animVars.unset("rightFootRotation"); + _animVars.set("rightFootPoleVectorEnabled", false); _animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition); } } @@ -1497,16 +1500,16 @@ void Rig::computeAvatarBoundingCapsule( ikNode.setTargetVars("LeftHand", "leftHandPosition", "leftHandRotation", "leftHandType", "leftHandWeight", 1.0f, {}, - "leftHandPoleJointName", "leftHandPoleVector"); + QString(), QString(), QString()); ikNode.setTargetVars("RightHand", "rightHandPosition", "rightHandRotation", "rightHandType", "rightHandWeight", 1.0f, {}, - "rightHandPoleJointName", "rightHandPoleVector"); + QString(), QString(), QString()); ikNode.setTargetVars("LeftFoot", "leftFootPosition", "leftFootRotation", "leftFootType", "leftFootWeight", 1.0f, {}, - "leftFootPoleJointName", "leftFootPoleVector"); + QString(), QString(), QString()); ikNode.setTargetVars("RightFoot", "rightFootPosition", "rightFootRotation", "rightFootType", "rightFootWeight", 1.0f, {}, - "rightFootPoleJointName", "rightFootPoleVector"); + QString(), QString(), QString()); AnimPose geometryToRig = _modelOffset * _geometryOffset;