From 1e276d113cf792305df60607479a07307fd3daab Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 12 May 2017 11:45:22 -0700 Subject: [PATCH] Added support for weights per target --- .../resources/avatar/avatar-animation.json | 20 ++++++++++++++++--- .../animation/src/AnimInverseKinematics.cpp | 14 +++++++++---- .../animation/src/AnimInverseKinematics.h | 6 ++++-- libraries/animation/src/AnimNodeLoader.cpp | 11 +++++++++- libraries/animation/src/IKTarget.cpp | 1 + libraries/animation/src/IKTarget.h | 5 +++-- libraries/animation/src/Rig.cpp | 10 ++++++---- 7 files changed, 51 insertions(+), 16 deletions(-) diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index a402358478..b18599d8a9 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -57,6 +57,8 @@ "positionVar": "hipsPosition", "rotationVar": "hipsRotation", "typeVar": "hipsType", + "weightVar": "hipsWeight", + "weight": 1.0, "flexCoefficients": [1] }, { @@ -64,20 +66,26 @@ "positionVar": "rightHandPosition", "rotationVar": "rightHandRotation", "typeVar": "rightHandType", - "flexCoefficients": [1, 0.5, 0.5, 0.5, 0.25, 0.1, 0.1, 0.1, 0.1] + "weightVar": "rightHandWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.5, 0.5, 0.25, 0.1, 0.05, 0.01, 0.0, 0.0] }, { "jointName": "LeftHand", "positionVar": "leftHandPosition", "rotationVar": "leftHandRotation", "typeVar": "leftHandType", - "flexCoefficients": [1, 0.5, 0.5, 0.5, 0.25, 0.1, 0.1, 0.1, 0.1] + "weightVar": "leftHandWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.5, 0.5, 0.25, 0.1, 0.05, 0.01, 0.0, 0.0] }, { "jointName": "RightFoot", "positionVar": "rightFootPosition", "rotationVar": "rightFootRotation", "typeVar": "rightFootType", + "weightVar": "rightFootWeight", + "weight": 1.0, "flexCoefficients": [1, 0.45, 0.45] }, { @@ -85,6 +93,8 @@ "positionVar": "leftFootPosition", "rotationVar": "leftFootRotation", "typeVar": "leftFootType", + "weightVar": "leftFootWeight", + "weight": 1.0, "flexCoefficients": [1, 0.45, 0.45] }, { @@ -92,6 +102,8 @@ "positionVar": "spine2Position", "rotationVar": "spine2Rotation", "typeVar": "spine2Type", + "weightVar": "spine2Weight", + "weight": 1.0, "flexCoefficients": [0.45, 0.45] }, { @@ -99,7 +111,9 @@ "positionVar": "headPosition", "rotationVar": "headRotation", "typeVar": "headType", - "flexCoefficients": [1, 0.5, 0.25, 0.25, 0.25] + "weightVar": "headWeight", + "weight": 4.0, + "flexCoefficients": [1, 0.5, 0.5, 0.5, 0.5] } ] }, diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 2ab4282177..11c143db23 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -22,10 +22,12 @@ #include "AnimationLogging.h" AnimInverseKinematics::IKTargetVar::IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn, - const QString& typeVarIn, const std::vector& flexCoefficientsIn) : + const QString& typeVarIn, const QString& weightVarIn, float weightIn, const std::vector& flexCoefficientsIn) : positionVar(positionVarIn), rotationVar(rotationVarIn), typeVar(typeVarIn), + weightVar(weightVarIn), + weight(weightIn), jointName(jointNameIn), numFlexCoefficients(flexCoefficientsIn.size()), jointIndex(-1) @@ -40,6 +42,8 @@ AnimInverseKinematics::IKTargetVar::IKTargetVar(const IKTargetVar& orig) : positionVar(orig.positionVar), rotationVar(orig.rotationVar), typeVar(orig.typeVar), + weightVar(orig.weightVar), + weight(orig.weight), jointName(orig.jointName), numFlexCoefficients(orig.numFlexCoefficients), jointIndex(orig.jointIndex) @@ -90,8 +94,8 @@ void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) con } 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); + const QString& typeVar, const QString& weightVar, float weight, const std::vector& flexCoefficients) { + IKTargetVar targetVar(jointName, positionVar, rotationVar, typeVar, weightVar, weight, flexCoefficients); // if there are dups, last one wins. bool found = false; @@ -132,9 +136,11 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses); glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, defaultPose.rot()); glm::vec3 translation = animVars.lookupRigToGeometry(targetVar.positionVar, defaultPose.trans()); + float weight = animVars.lookup(targetVar.weightVar, targetVar.weight); target.setPose(rotation, translation); target.setIndex(targetVar.jointIndex); + target.setWeight(weight); target.setFlexCoefficients(targetVar.numFlexCoefficients, targetVar.flexCoefficients); targets.push_back(target); @@ -837,7 +843,7 @@ void AnimInverseKinematics::initConstraints() { stConstraint->setTwistLimits(-MAX_SHOULDER_TWIST, MAX_SHOULDER_TWIST); std::vector minDots; - const float MAX_SHOULDER_SWING = PI / 20.0f; + const float MAX_SHOULDER_SWING = PI / 16.0f; minDots.push_back(cosf(MAX_SHOULDER_SWING)); stConstraint->setSwingLimits(minDots); diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index ddbb420012..b798319ca9 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -33,7 +33,7 @@ public: void computeAbsolutePoses(AnimPoseVec& absolutePoses) const; void setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar, - const QString& typeVar, const std::vector& flexCoefficients); + const QString& typeVar, const QString& weightVar, float weight, 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; @@ -81,13 +81,15 @@ protected: static const size_t MAX_FLEX_COEFFICIENTS = 10; struct IKTargetVar { IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn, - const QString& typeVarIn, const std::vector& flexCoefficientsIn); + const QString& typeVarIn, const QString& weightVarIn, float weightIn, const std::vector& flexCoefficientsIn); IKTargetVar(const IKTargetVar& orig); QString positionVar; QString rotationVar; QString typeVar; + QString weightVar; QString jointName; + float weight; 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 e4ffaec5b7..44ed8c6053 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -173,6 +173,13 @@ static NodeProcessFunc animNodeTypeToProcessFunc(AnimNode::Type type) { } \ float NAME = (float)NAME##_VAL.toDouble() +#define READ_OPTIONAL_FLOAT(NAME, JSON_OBJ, DEFAULT) \ + auto NAME##_VAL = JSON_OBJ.value(#NAME); \ + float NAME = (float)DEFAULT; \ + if (NAME##_VAL.isDouble()) { \ + NAME = (float)NAME##_VAL.toDouble(); \ + } \ + do {} while (0) static AnimNode::Pointer loadNode(const QJsonObject& jsonObj, const QUrl& jsonUrl) { auto idVal = jsonObj.value("id"); @@ -470,6 +477,8 @@ AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QS READ_STRING(positionVar, targetObj, id, jsonUrl, nullptr); READ_STRING(rotationVar, targetObj, id, jsonUrl, nullptr); READ_OPTIONAL_STRING(typeVar, targetObj); + READ_OPTIONAL_STRING(weightVar, targetObj); + READ_OPTIONAL_FLOAT(weight, targetObj, 1.0f); auto flexCoefficientsValue = targetObj.value("flexCoefficients"); if (!flexCoefficientsValue.isArray()) { @@ -482,7 +491,7 @@ AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QS flexCoefficients.push_back((float)value.toDouble()); } - node->setTargetVars(jointName, positionVar, rotationVar, typeVar, flexCoefficients); + node->setTargetVars(jointName, positionVar, rotationVar, typeVar, weightVar, weight, flexCoefficients); }; READ_OPTIONAL_STRING(solutionSource, jsonObj); diff --git a/libraries/animation/src/IKTarget.cpp b/libraries/animation/src/IKTarget.cpp index 868293fdb8..ae23d9548f 100644 --- a/libraries/animation/src/IKTarget.cpp +++ b/libraries/animation/src/IKTarget.cpp @@ -23,6 +23,7 @@ void IKTarget::setFlexCoefficients(size_t numFlexCoefficientsIn, const float* fl float IKTarget::getFlexCoefficient(int chainDepth) const { const float DEFAULT_FLEX_COEFFICIENT = 0.5f; + if (chainDepth >= 0 && chainDepth < _numFlexCoefficients) { return _flexCoefficients[chainDepth]; } else { diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h index 63a4b901a6..0e8bb614ea 100644 --- a/libraries/animation/src/IKTarget.h +++ b/libraries/animation/src/IKTarget.h @@ -38,14 +38,15 @@ public: 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; } + void setWeight(float weight) { _weight = weight; } + float getWeight() const { return _weight; } static const size_t MAX_FLEX_COEFFICIENTS = 10; private: AnimPose _pose; int _index{-1}; Type _type{Type::RotationAndPosition}; + float _weight; float _flexCoefficients[MAX_FLEX_COEFFICIENTS]; size_t _numFlexCoefficients; }; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index f5a9008ce1..23db05eb73 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1088,10 +1088,12 @@ void Rig::updateHeadAnimVars(const HeadParameters& params) { // Since there is an explicit hips ik target, switch the head to use the more generic RotationAndPosition IK chain type. // this will allow the spine to bend more, ensuring that it can reach the head target position. _animVars.set("headType", (int)IKTarget::Type::RotationAndPosition); + _animVars.unset("headWeight"); // use the default weight for this target. } else { // When there is no hips IK target, use the HmdHead IK chain type. This will make the spine very stiff, // but because the IK _hipsOffset is enabled, the hips will naturally follow underneath the head. _animVars.set("headType", (int)IKTarget::Type::HmdHead); + _animVars.set("headWeight", 8.0f); } } else { _animVars.unset("headPosition"); @@ -1405,19 +1407,19 @@ void Rig::computeAvatarBoundingCapsule( ikNode.setTargetVars("LeftHand", "leftHandPosition", "leftHandRotation", - "leftHandType", {}); + "leftHandType", "leftHandWeight", 1.0f, {}); ikNode.setTargetVars("RightHand", "rightHandPosition", "rightHandRotation", - "rightHandType", {}); + "rightHandType", "rightHandWeight", 1.0f, {}); ikNode.setTargetVars("LeftFoot", "leftFootPosition", "leftFootRotation", - "leftFootType", {}); + "leftFootType", "leftFootWeight", 1.0f, {}); ikNode.setTargetVars("RightFoot", "rightFootPosition", "rightFootRotation", - "rightFootType", {}); + "rightFootType", "rightFootWeight", 1.0f, {}); AnimPose geometryToRig = _modelOffset * _geometryOffset;