Merge pull request #5944 from AndrewMeadows/ik-repairs-007

fix bug: IK attenuates fast underpose animations
This commit is contained in:
Howard Stearns 2015-10-01 14:27:21 -07:00
commit 739545794f
4 changed files with 43 additions and 28 deletions

View file

@ -26,13 +26,14 @@
{ {
"jointName": "Neck", "jointName": "Neck",
"positionVar": "neckPosition", "positionVar": "neckPosition",
"rotationVar": "neckRotation" "rotationVar": "neckRotation",
"typeVar": "headAndNeckType"
}, },
{ {
"jointName": "Head", "jointName": "Head",
"positionVar": "headPosition", "positionVar": "headPosition",
"rotationVar": "headRotation", "rotationVar": "headRotation",
"typeVar": "headType" "typeVar": "headAndNeckType"
} }
] ]
}, },

View file

@ -89,7 +89,7 @@ static int findRootJointInSkeleton(AnimSkeleton::ConstPointer skeleton, int inde
return rootIndex; return rootIndex;
} }
void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets) { void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses) {
// build a list of valid targets from _targetVarVec and animVars // build a list of valid targets from _targetVarVec and animVars
_maxTargetIndex = -1; _maxTargetIndex = -1;
bool removeUnfoundJoints = false; bool removeUnfoundJoints = false;
@ -107,7 +107,7 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
} }
} else { } else {
IKTarget target; IKTarget target;
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, _relativePoses); AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
target.pose.trans = animVars.lookup(targetVar.positionVar, defaultPose.trans); target.pose.trans = animVars.lookup(targetVar.positionVar, defaultPose.trans);
target.pose.rot = animVars.lookup(targetVar.rotationVar, defaultPose.rot); target.pose.rot = animVars.lookup(targetVar.rotationVar, defaultPose.rot);
target.setType(animVars.lookup(targetVar.typeVar, QString(""))); target.setType(animVars.lookup(targetVar.typeVar, QString("")));
@ -154,7 +154,6 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
do { do {
int lowestMovedIndex = _relativePoses.size(); int lowestMovedIndex = _relativePoses.size();
for (auto& target: targets) { for (auto& target: targets) {
int tipIndex = target.index;
if (target.type == IKTarget::Type::RotationOnly) { if (target.type == IKTarget::Type::RotationOnly) {
// the final rotation will be enforced after the iterations // the final rotation will be enforced after the iterations
continue; continue;
@ -162,6 +161,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
AnimPose targetPose = target.pose; AnimPose targetPose = target.pose;
// cache tip absolute transform // cache tip absolute transform
int tipIndex = target.index;
glm::vec3 tipPosition = absolutePoses[tipIndex].trans; glm::vec3 tipPosition = absolutePoses[tipIndex].trans;
glm::quat tipRotation = absolutePoses[tipIndex].rot; glm::quat tipRotation = absolutePoses[tipIndex].rot;
@ -288,6 +288,17 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
} }
} while (numLoops < MAX_IK_LOOPS); } while (numLoops < MAX_IK_LOOPS);
/* KEEP: example code for measuring endeffector error of IK solution
for (uint32_t i = 0; i < targets.size(); ++i) {
auto& target = targets[i];
if (target.type == IKTarget::Type::RotationOnly) {
continue;
}
glm::vec3 tipPosition = absolutePoses[target.index].trans;
std::cout << i << " IK error = " << glm::distance(tipPosition, target.pose.trans) << std::endl; // adebug
}
*/
// finally set the relative rotation of each tip to agree with absolute target rotation // finally set the relative rotation of each tip to agree with absolute target rotation
for (auto& target: targets) { for (auto& target: targets) {
int tipIndex = target.index; int tipIndex = target.index;
@ -312,25 +323,8 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
//virtual //virtual
const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVars, float dt, AnimNode::Triggers& triggersOut) { const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVars, float dt, AnimNode::Triggers& triggersOut) {
if (!_relativePoses.empty()) { // don't call this function, call overlay() instead
// build a list of targets from _targetVarVec assert(false);
std::vector<IKTarget> targets;
computeTargets(animVars, targets);
if (targets.empty()) {
// no IK targets but still need to enforce constraints
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin();
while (constraintItr != _constraints.end()) {
int index = constraintItr->first;
glm::quat rotation = _relativePoses[index].rot;
constraintItr->second->apply(rotation);
_relativePoses[index].rot = rotation;
++constraintItr;
}
} else {
solveWithCyclicCoordinateDescent(targets);
}
}
return _relativePoses; return _relativePoses;
} }
@ -356,7 +350,27 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
} }
} }
} }
return evaluate(animVars, dt, triggersOut);
if (!_relativePoses.empty()) {
// build a list of targets from _targetVarVec
std::vector<IKTarget> targets;
computeTargets(animVars, targets, underPoses);
if (targets.empty()) {
// no IK targets but still need to enforce constraints
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin();
while (constraintItr != _constraints.end()) {
int index = constraintItr->first;
glm::quat rotation = _relativePoses[index].rot;
constraintItr->second->apply(rotation);
_relativePoses[index].rot = rotation;
++constraintItr;
}
} else {
solveWithCyclicCoordinateDescent(targets);
}
}
return _relativePoses;
} }
RotationConstraint* AnimInverseKinematics::getConstraint(int index) { RotationConstraint* AnimInverseKinematics::getConstraint(int index) {

View file

@ -50,7 +50,7 @@ protected:
void setType(const QString& typeVar) { type = ((typeVar == "RotationOnly") ? Type::RotationOnly : Type::RotationAndPosition); } void setType(const QString& typeVar) { type = ((typeVar == "RotationOnly") ? Type::RotationOnly : Type::RotationAndPosition); }
}; };
void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets); void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses);
void solveWithCyclicCoordinateDescent(const std::vector<IKTarget>& targets); void solveWithCyclicCoordinateDescent(const std::vector<IKTarget>& targets);
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton); virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton);

View file

@ -1088,7 +1088,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
_animVars.set("headPosition", headPos); _animVars.set("headPosition", headPos);
_animVars.set("headRotation", headRot); _animVars.set("headRotation", headRot);
_animVars.set("headType", QString("RotationAndPosition")); _animVars.set("headAndNeckType", QString("RotationAndPosition"));
_animVars.set("neckPosition", neckPos); _animVars.set("neckPosition", neckPos);
_animVars.set("neckRotation", neckRot); _animVars.set("neckRotation", neckRot);
@ -1101,7 +1101,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
_animVars.unset("headPosition"); _animVars.unset("headPosition");
_animVars.set("headRotation", realLocalHeadOrientation); _animVars.set("headRotation", realLocalHeadOrientation);
_animVars.set("headType", QString("RotationOnly")); _animVars.set("headAndNeckType", QString("RotationOnly"));
_animVars.unset("neckPosition"); _animVars.unset("neckPosition");
_animVars.unset("neckRotation"); _animVars.unset("neckRotation");
} }