WIP: initial implementation of flexCoefficients

This commit is contained in:
Anthony J. Thibault 2017-05-10 18:11:34 -07:00
parent 263e4de951
commit 67fbb15faa
7 changed files with 107 additions and 39 deletions

View file

@ -56,43 +56,50 @@
"jointName": "Hips", "jointName": "Hips",
"positionVar": "hipsPosition", "positionVar": "hipsPosition",
"rotationVar": "hipsRotation", "rotationVar": "hipsRotation",
"typeVar": "hipsType" "typeVar": "hipsType",
"flexCoefficients": [1]
}, },
{ {
"jointName": "RightHand", "jointName": "RightHand",
"positionVar": "rightHandPosition", "positionVar": "rightHandPosition",
"rotationVar": "rightHandRotation", "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", "jointName": "LeftHand",
"positionVar": "leftHandPosition", "positionVar": "leftHandPosition",
"rotationVar": "leftHandRotation", "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", "jointName": "RightFoot",
"positionVar": "rightFootPosition", "positionVar": "rightFootPosition",
"rotationVar": "rightFootRotation", "rotationVar": "rightFootRotation",
"typeVar": "rightFootType" "typeVar": "rightFootType",
"flexCoefficients": [1, 0.45, 0.45]
}, },
{ {
"jointName": "LeftFoot", "jointName": "LeftFoot",
"positionVar": "leftFootPosition", "positionVar": "leftFootPosition",
"rotationVar": "leftFootRotation", "rotationVar": "leftFootRotation",
"typeVar": "leftFootType" "typeVar": "leftFootType",
"flexCoefficients": [1, 0.45, 0.45]
}, },
{ {
"jointName": "Spine2", "jointName": "Spine2",
"positionVar": "spine2Position", "positionVar": "spine2Position",
"rotationVar": "spine2Rotation", "rotationVar": "spine2Rotation",
"typeVar": "spine2Type" "typeVar": "spine2Type",
"flexCoefficients": [0.45, 0.45]
}, },
{ {
"jointName": "Head", "jointName": "Head",
"positionVar": "headPosition", "positionVar": "headPosition",
"rotationVar": "headRotation", "rotationVar": "headRotation",
"typeVar": "headType" "typeVar": "headType",
"flexCoefficients": [1, 0.5, 0.25, 0.25, 0.25]
} }
] ]
}, },

View file

@ -21,6 +21,35 @@
#include "SwingTwistConstraint.h" #include "SwingTwistConstraint.h"
#include "AnimationLogging.h" #include "AnimationLogging.h"
AnimInverseKinematics::IKTargetVar::IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn,
const QString& typeVarIn, const std::vector<float>& 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) { AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimNode::Type::InverseKinematics, id) {
} }
@ -60,26 +89,22 @@ void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) con
} }
} }
void AnimInverseKinematics::setTargetVars( void AnimInverseKinematics::setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar,
const QString& jointName, const QString& typeVar, const std::vector<float>& flexCoefficients) {
const QString& positionVar, IKTargetVar targetVar(jointName, positionVar, rotationVar, typeVar, flexCoefficients);
const QString& rotationVar,
const QString& typeVar) {
// if there are dups, last one wins. // if there are dups, last one wins.
bool found = false; bool found = false;
for (auto& targetVar: _targetVarVec) { for (auto& targetVarIter: _targetVarVec) {
if (targetVar.jointName == jointName) { if (targetVarIter.jointName == jointName) {
// update existing targetVar targetVarIter = targetVar;
targetVar.positionVar = positionVar;
targetVar.rotationVar = rotationVar;
targetVar.typeVar = typeVar;
found = true; found = true;
break; break;
} }
} }
if (!found) { if (!found) {
// create a new entry // 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.setPose(rotation, translation);
target.setIndex(targetVar.jointIndex); target.setIndex(targetVar.jointIndex);
target.setFlexCoefficients(targetVar.numFlexCoefficients, targetVar.flexCoefficients);
targets.push_back(target); targets.push_back(target);
if (targetVar.jointIndex > _maxTargetIndex) { if (targetVar.jointIndex > _maxTargetIndex) {
_maxTargetIndex = targetVar.jointIndex; _maxTargetIndex = targetVar.jointIndex;
} }
@ -271,6 +299,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe
// cache tip absolute position // cache tip absolute position
glm::vec3 tipPosition = absolutePoses[tipIndex].trans(); glm::vec3 tipPosition = absolutePoses[tipIndex].trans();
int chainDepth = 1;
// descend toward root, pivoting each joint to get tip closer to target position // descend toward root, pivoting each joint to get tip closer to target position
while (pivotIndex != _hipsIndex && pivotsParentIndex != -1) { while (pivotIndex != _hipsIndex && pivotsParentIndex != -1) {
// compute the two lines that should be aligned // compute the two lines that should be aligned
@ -312,9 +342,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe
float angle = acosf(cosAngle); float angle = acosf(cosAngle);
const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f; const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f;
if (angle > MIN_ADJUSTMENT_ANGLE) { if (angle > MIN_ADJUSTMENT_ANGLE) {
// reduce angle by a fraction (for stability) // reduce angle by a flexCoefficient
const float STABILITY_FRACTION = 0.5f; angle *= target.getFlexCoefficient(chainDepth);
angle *= STABILITY_FRACTION;
deltaRotation = glm::angleAxis(angle, axis); 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 // 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; pivotIndex = pivotsParentIndex;
pivotsParentIndex = _skeleton->getParentIndex(pivotIndex); pivotsParentIndex = _skeleton->getParentIndex(pivotIndex);
chainDepth++;
} }
return lowestMovedIndex; return lowestMovedIndex;
} }

View file

@ -32,7 +32,8 @@ public:
void loadPoses(const AnimPoseVec& poses); void loadPoses(const AnimPoseVec& poses);
void computeAbsolutePoses(AnimPoseVec& absolutePoses) const; 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<float>& flexCoefficients);
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimNode::Triggers& triggersOut) override; 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; 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(const AnimInverseKinematics&) = delete;
AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete; AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete;
static const size_t MAX_FLEX_COEFFICIENTS = 10;
struct IKTargetVar { struct IKTargetVar {
IKTargetVar(const QString& jointNameIn, IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn,
const QString& positionVarIn, const QString& typeVarIn, const std::vector<float>& flexCoefficientsIn);
const QString& rotationVarIn, IKTargetVar(const IKTargetVar& orig);
const QString& typeVarIn) :
positionVar(positionVarIn),
rotationVar(rotationVarIn),
typeVar(typeVarIn),
jointName(jointNameIn),
jointIndex(-1)
{}
QString positionVar; QString positionVar;
QString rotationVar; QString rotationVar;
QString typeVar; QString typeVar;
QString jointName; QString jointName;
float flexCoefficients[MAX_FLEX_COEFFICIENTS];
size_t numFlexCoefficients;
int jointIndex; // cached joint index int jointIndex; // cached joint index
}; };

View file

@ -471,7 +471,18 @@ AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QS
READ_STRING(rotationVar, targetObj, id, jsonUrl, nullptr); READ_STRING(rotationVar, targetObj, id, jsonUrl, nullptr);
READ_OPTIONAL_STRING(typeVar, targetObj); 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<float> flexCoefficients;
for (const auto& value : flexCoefficientsArray) {
flexCoefficients.push_back((float)value.toDouble());
}
node->setTargetVars(jointName, positionVar, rotationVar, typeVar, flexCoefficients);
}; };
READ_OPTIONAL_STRING(solutionSource, jsonObj); READ_OPTIONAL_STRING(solutionSource, jsonObj);

View file

@ -14,6 +14,22 @@ void IKTarget::setPose(const glm::quat& rotation, const glm::vec3& translation)
_pose.trans() = 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) { void IKTarget::setType(int type) {
switch (type) { switch (type) {
case (int)Type::RotationAndPosition: case (int)Type::RotationAndPosition:

View file

@ -35,15 +35,19 @@ public:
void setPose(const glm::quat& rotation, const glm::vec3& translation); void setPose(const glm::quat& rotation, const glm::vec3& translation);
void setIndex(int index) { _index = index; } void setIndex(int index) { _index = index; }
void setType(int); 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 // HACK: give HmdHead targets more "weight" during IK algorithm
float getWeight() const { return _type == Type::HmdHead ? HACK_HMD_TARGET_WEIGHT : 1.0f; } float getWeight() const { return _type == Type::HmdHead ? HACK_HMD_TARGET_WEIGHT : 1.0f; }
static const size_t MAX_FLEX_COEFFICIENTS = 10;
private: private:
AnimPose _pose; AnimPose _pose;
int _index{-1}; int _index{-1};
Type _type{Type::RotationAndPosition}; Type _type{Type::RotationAndPosition};
float _flexCoefficients[MAX_FLEX_COEFFICIENTS];
size_t _numFlexCoefficients;
}; };
#endif // hifi_IKTarget_h #endif // hifi_IKTarget_h

View file

@ -1400,22 +1400,24 @@ void Rig::computeAvatarBoundingCapsule(
AnimInverseKinematics ikNode("boundingShape"); AnimInverseKinematics ikNode("boundingShape");
ikNode.setSkeleton(_animSkeleton); ikNode.setSkeleton(_animSkeleton);
// AJT: FIX ME!!!!! ensure that empty weights vector does something reasonable....
ikNode.setTargetVars("LeftHand", ikNode.setTargetVars("LeftHand",
"leftHandPosition", "leftHandPosition",
"leftHandRotation", "leftHandRotation",
"leftHandType"); "leftHandType", {});
ikNode.setTargetVars("RightHand", ikNode.setTargetVars("RightHand",
"rightHandPosition", "rightHandPosition",
"rightHandRotation", "rightHandRotation",
"rightHandType"); "rightHandType", {});
ikNode.setTargetVars("LeftFoot", ikNode.setTargetVars("LeftFoot",
"leftFootPosition", "leftFootPosition",
"leftFootRotation", "leftFootRotation",
"leftFootType"); "leftFootType", {});
ikNode.setTargetVars("RightFoot", ikNode.setTargetVars("RightFoot",
"rightFootPosition", "rightFootPosition",
"rightFootRotation", "rightFootRotation",
"rightFootType"); "rightFootType", {});
AnimPose geometryToRig = _modelOffset * _geometryOffset; AnimPose geometryToRig = _modelOffset * _geometryOffset;