From 67fbb15faab1e5547ae8899f1cce067760771005 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 10 May 2017 18:11:34 -0700 Subject: [PATCH] WIP: initial implementation of flexCoefficients --- .../resources/avatar/avatar-animation.json | 21 ++++--- .../animation/src/AnimInverseKinematics.cpp | 61 ++++++++++++++----- .../animation/src/AnimInverseKinematics.h | 19 +++--- libraries/animation/src/AnimNodeLoader.cpp | 13 +++- libraries/animation/src/IKTarget.cpp | 16 +++++ libraries/animation/src/IKTarget.h | 6 +- libraries/animation/src/Rig.cpp | 10 +-- 7 files changed, 107 insertions(+), 39 deletions(-) diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index eb8403634a..a402358478 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -56,43 +56,50 @@ "jointName": "Hips", "positionVar": "hipsPosition", "rotationVar": "hipsRotation", - "typeVar": "hipsType" + "typeVar": "hipsType", + "flexCoefficients": [1] }, { "jointName": "RightHand", "positionVar": "rightHandPosition", "rotationVar": "rightHandRotation", - "typeVar": "rightHandType" + "typeVar": "rightHandType", + "flexCoefficients": [1, 0.5, 0.5, 0.5, 0.25, 0.1, 0.1, 0.1, 0.1] }, { "jointName": "LeftHand", "positionVar": "leftHandPosition", "rotationVar": "leftHandRotation", - "typeVar": "leftHandType" + "typeVar": "leftHandType", + "flexCoefficients": [1, 0.5, 0.5, 0.5, 0.25, 0.1, 0.1, 0.1, 0.1] }, { "jointName": "RightFoot", "positionVar": "rightFootPosition", "rotationVar": "rightFootRotation", - "typeVar": "rightFootType" + "typeVar": "rightFootType", + "flexCoefficients": [1, 0.45, 0.45] }, { "jointName": "LeftFoot", "positionVar": "leftFootPosition", "rotationVar": "leftFootRotation", - "typeVar": "leftFootType" + "typeVar": "leftFootType", + "flexCoefficients": [1, 0.45, 0.45] }, { "jointName": "Spine2", "positionVar": "spine2Position", "rotationVar": "spine2Rotation", - "typeVar": "spine2Type" + "typeVar": "spine2Type", + "flexCoefficients": [0.45, 0.45] }, { "jointName": "Head", "positionVar": "headPosition", "rotationVar": "headRotation", - "typeVar": "headType" + "typeVar": "headType", + "flexCoefficients": [1, 0.5, 0.25, 0.25, 0.25] } ] }, diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 5e6927afcb..2ab4282177 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -21,6 +21,35 @@ #include "SwingTwistConstraint.h" #include "AnimationLogging.h" +AnimInverseKinematics::IKTargetVar::IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn, + const QString& typeVarIn, const std::vector& flexCoefficientsIn) : + positionVar(positionVarIn), + rotationVar(rotationVarIn), + typeVar(typeVarIn), + jointName(jointNameIn), + numFlexCoefficients(flexCoefficientsIn.size()), + jointIndex(-1) +{ + numFlexCoefficients = std::min(numFlexCoefficients, MAX_FLEX_COEFFICIENTS); + for (size_t i = 0; i < numFlexCoefficients; i++) { + flexCoefficients[i] = flexCoefficientsIn[i]; + } +} + +AnimInverseKinematics::IKTargetVar::IKTargetVar(const IKTargetVar& orig) : + positionVar(orig.positionVar), + rotationVar(orig.rotationVar), + typeVar(orig.typeVar), + jointName(orig.jointName), + numFlexCoefficients(orig.numFlexCoefficients), + jointIndex(orig.jointIndex) +{ + numFlexCoefficients = std::min(numFlexCoefficients, MAX_FLEX_COEFFICIENTS); + for (size_t i = 0; i < numFlexCoefficients; i++) { + flexCoefficients[i] = orig.flexCoefficients[i]; + } +} + AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimNode::Type::InverseKinematics, id) { } @@ -60,26 +89,22 @@ void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) con } } -void AnimInverseKinematics::setTargetVars( - const QString& jointName, - const QString& positionVar, - const QString& rotationVar, - const QString& typeVar) { +void AnimInverseKinematics::setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar, + const QString& typeVar, const std::vector& flexCoefficients) { + IKTargetVar targetVar(jointName, positionVar, rotationVar, typeVar, flexCoefficients); + // if there are dups, last one wins. bool found = false; - for (auto& targetVar: _targetVarVec) { - if (targetVar.jointName == jointName) { - // update existing targetVar - targetVar.positionVar = positionVar; - targetVar.rotationVar = rotationVar; - targetVar.typeVar = typeVar; + for (auto& targetVarIter: _targetVarVec) { + if (targetVarIter.jointName == jointName) { + targetVarIter = targetVar; found = true; break; } } if (!found) { // create a new entry - _targetVarVec.push_back(IKTargetVar(jointName, positionVar, rotationVar, typeVar)); + _targetVarVec.push_back(targetVar); } } @@ -110,7 +135,10 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: target.setPose(rotation, translation); target.setIndex(targetVar.jointIndex); + target.setFlexCoefficients(targetVar.numFlexCoefficients, targetVar.flexCoefficients); + targets.push_back(target); + if (targetVar.jointIndex > _maxTargetIndex) { _maxTargetIndex = targetVar.jointIndex; } @@ -271,6 +299,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe // cache tip absolute position glm::vec3 tipPosition = absolutePoses[tipIndex].trans(); + int chainDepth = 1; + // descend toward root, pivoting each joint to get tip closer to target position while (pivotIndex != _hipsIndex && pivotsParentIndex != -1) { // compute the two lines that should be aligned @@ -312,9 +342,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe float angle = acosf(cosAngle); const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f; if (angle > MIN_ADJUSTMENT_ANGLE) { - // reduce angle by a fraction (for stability) - const float STABILITY_FRACTION = 0.5f; - angle *= STABILITY_FRACTION; + // reduce angle by a flexCoefficient + angle *= target.getFlexCoefficient(chainDepth); deltaRotation = glm::angleAxis(angle, axis); // The swing will re-orient the tip but there will tend to be be a non-zero delta between the tip's @@ -385,6 +414,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe pivotIndex = pivotsParentIndex; pivotsParentIndex = _skeleton->getParentIndex(pivotIndex); + + chainDepth++; } return lowestMovedIndex; } diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index f73ed95935..ddbb420012 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -32,7 +32,8 @@ public: void loadPoses(const AnimPoseVec& poses); void computeAbsolutePoses(AnimPoseVec& absolutePoses) const; - void setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar, const QString& typeVar); + void setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar, + const QString& typeVar, const std::vector& flexCoefficients); 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; @@ -77,22 +78,18 @@ protected: AnimInverseKinematics(const AnimInverseKinematics&) = delete; AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete; + static const size_t MAX_FLEX_COEFFICIENTS = 10; struct IKTargetVar { - IKTargetVar(const QString& jointNameIn, - const QString& positionVarIn, - const QString& rotationVarIn, - const QString& typeVarIn) : - positionVar(positionVarIn), - rotationVar(rotationVarIn), - typeVar(typeVarIn), - jointName(jointNameIn), - jointIndex(-1) - {} + IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn, + const QString& typeVarIn, const std::vector& flexCoefficientsIn); + IKTargetVar(const IKTargetVar& orig); QString positionVar; QString rotationVar; QString typeVar; QString jointName; + float flexCoefficients[MAX_FLEX_COEFFICIENTS]; + size_t numFlexCoefficients; int jointIndex; // cached joint index }; diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index 6bc7342d7f..e4ffaec5b7 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -471,7 +471,18 @@ AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QS READ_STRING(rotationVar, targetObj, id, jsonUrl, nullptr); READ_OPTIONAL_STRING(typeVar, targetObj); - node->setTargetVars(jointName, positionVar, rotationVar, typeVar); + auto flexCoefficientsValue = targetObj.value("flexCoefficients"); + if (!flexCoefficientsValue.isArray()) { + qCCritical(animation) << "AnimNodeLoader, bad or missing flexCoefficients array in \"targets\", id =" << id << ", url =" << jsonUrl.toDisplayString(); + return nullptr; + } + auto flexCoefficientsArray = flexCoefficientsValue.toArray(); + std::vector flexCoefficients; + for (const auto& value : flexCoefficientsArray) { + flexCoefficients.push_back((float)value.toDouble()); + } + + node->setTargetVars(jointName, positionVar, rotationVar, typeVar, flexCoefficients); }; READ_OPTIONAL_STRING(solutionSource, jsonObj); diff --git a/libraries/animation/src/IKTarget.cpp b/libraries/animation/src/IKTarget.cpp index fa4030ca6d..868293fdb8 100644 --- a/libraries/animation/src/IKTarget.cpp +++ b/libraries/animation/src/IKTarget.cpp @@ -14,6 +14,22 @@ void IKTarget::setPose(const glm::quat& rotation, const glm::vec3& translation) _pose.trans() = translation; } +void IKTarget::setFlexCoefficients(size_t numFlexCoefficientsIn, const float* flexCoefficientsIn) { + _numFlexCoefficients = std::min(numFlexCoefficientsIn, MAX_FLEX_COEFFICIENTS); + for (size_t i = 0; i < _numFlexCoefficients; i++) { + _flexCoefficients[i] = flexCoefficientsIn[i]; + } +} + +float IKTarget::getFlexCoefficient(int chainDepth) const { + const float DEFAULT_FLEX_COEFFICIENT = 0.5f; + if (chainDepth >= 0 && chainDepth < _numFlexCoefficients) { + return _flexCoefficients[chainDepth]; + } else { + return DEFAULT_FLEX_COEFFICIENT; + } +} + void IKTarget::setType(int type) { switch (type) { case (int)Type::RotationAndPosition: diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h index acb01d9861..63a4b901a6 100644 --- a/libraries/animation/src/IKTarget.h +++ b/libraries/animation/src/IKTarget.h @@ -35,15 +35,19 @@ public: void setPose(const glm::quat& rotation, const glm::vec3& translation); void setIndex(int index) { _index = index; } void setType(int); + void setFlexCoefficients(size_t numFlexCoefficientsIn, const float* flexCoefficientsIn); + float getFlexCoefficient(int chainDepth) const; // HACK: give HmdHead targets more "weight" during IK algorithm float getWeight() const { return _type == Type::HmdHead ? HACK_HMD_TARGET_WEIGHT : 1.0f; } + static const size_t MAX_FLEX_COEFFICIENTS = 10; private: AnimPose _pose; int _index{-1}; Type _type{Type::RotationAndPosition}; - + float _flexCoefficients[MAX_FLEX_COEFFICIENTS]; + size_t _numFlexCoefficients; }; #endif // hifi_IKTarget_h diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index cb5aebe930..f5a9008ce1 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1400,22 +1400,24 @@ void Rig::computeAvatarBoundingCapsule( AnimInverseKinematics ikNode("boundingShape"); ikNode.setSkeleton(_animSkeleton); + + // AJT: FIX ME!!!!! ensure that empty weights vector does something reasonable.... ikNode.setTargetVars("LeftHand", "leftHandPosition", "leftHandRotation", - "leftHandType"); + "leftHandType", {}); ikNode.setTargetVars("RightHand", "rightHandPosition", "rightHandRotation", - "rightHandType"); + "rightHandType", {}); ikNode.setTargetVars("LeftFoot", "leftFootPosition", "leftFootRotation", - "leftFootType"); + "leftFootType", {}); ikNode.setTargetVars("RightFoot", "rightFootPosition", "rightFootRotation", - "rightFootType"); + "rightFootType", {}); AnimPose geometryToRig = _modelOffset * _geometryOffset;