move IKTarget into its own files

This commit is contained in:
Andrew Meadows 2015-10-10 11:15:51 -07:00
parent 56f038d5a7
commit bc48f70877
5 changed files with 112 additions and 51 deletions

View file

@ -96,13 +96,13 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
} else {
IKTarget target;
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
target.pose.trans = animVars.lookup(targetVar.positionVar, defaultPose.trans);
target.pose.rot = animVars.lookup(targetVar.rotationVar, defaultPose.rot);
target.setType(animVars.lookup(targetVar.typeVar, QString("")));
target.index = targetVar.jointIndex;
target.setPose(animVars.lookup(targetVar.rotationVar, defaultPose.rot),
animVars.lookup(targetVar.positionVar, defaultPose.trans));
target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::Unknown));
target.setIndex(targetVar.jointIndex);
targets.push_back(target);
if (target.index > _maxTargetIndex) {
_maxTargetIndex = target.index;
if (targetVar.jointIndex > _maxTargetIndex) {
_maxTargetIndex = targetVar.jointIndex;
}
}
}
@ -141,14 +141,13 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
do {
int lowestMovedIndex = _relativePoses.size();
for (auto& target: targets) {
if (target.type == IKTarget::Type::RotationOnly) {
if (target.getType() == IKTarget::Type::RotationOnly) {
// the final rotation will be enforced after the iterations
continue;
}
AnimPose targetPose = target.pose;
// cache tip absolute transform
int tipIndex = target.index;
int tipIndex = target.getIndex();
glm::vec3 tipPosition = absolutePoses[tipIndex].trans;
glm::quat tipRotation = absolutePoses[tipIndex].rot;
@ -166,7 +165,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
// compute the two lines that should be aligned
glm::vec3 jointPosition = absolutePoses[pivotIndex].trans;
glm::vec3 leverArm = tipPosition - jointPosition;
glm::vec3 targetLine = targetPose.trans - jointPosition;
glm::vec3 targetLine = target.getTranslation() - jointPosition;
// compute the swing that would get get tip closer
glm::vec3 axis = glm::cross(leverArm, targetLine);
@ -189,7 +188,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
// The swing will re-orient the tip but there will tend to be be a non-zero delta between the tip's
// new rotation and its target. We compute that delta here and rotate the tipJoint accordingly.
glm::quat tipRelativeRotation = glm::inverse(deltaRotation * tipParentRotation) * targetPose.rot;
glm::quat tipRelativeRotation = glm::inverse(deltaRotation * tipParentRotation) * target.getRotation();
// enforce tip's constraint
RotationConstraint* constraint = getConstraint(tipIndex);
@ -199,7 +198,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
// The tip's final parent-relative rotation violates its constraint
// so we try to twist this pivot to compensate.
glm::quat constrainedTipRotation = deltaRotation * tipParentRotation * tipRelativeRotation;
glm::quat missingRotation = targetPose.rot * glm::inverse(constrainedTipRotation);
glm::quat missingRotation = target.getRotation() * glm::inverse(constrainedTipRotation);
glm::quat swingPart;
glm::quat twistPart;
glm::vec3 axis = glm::normalize(deltaRotation * leverArm);
@ -278,23 +277,23 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
/* 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) {
if (target.getType() == IKTarget::Type::RotationOnly) {
continue;
}
glm::vec3 tipPosition = absolutePoses[target.index].trans;
std::cout << i << " IK error = " << glm::distance(tipPosition, target.pose.trans) << std::endl;
std::cout << i << " IK error = " << glm::distance(tipPosition, target.getTranslation()) << std::endl;
}
*/
// finally set the relative rotation of each tip to agree with absolute target rotation
for (auto& target: targets) {
int tipIndex = target.index;
int tipIndex = target.getIndex();
int parentIndex = _skeleton->getParentIndex(tipIndex);
if (parentIndex != -1) {
AnimPose targetPose = target.pose;
const glm::quat& targetRotation = target.getRotation();
// compute tip's new parent-relative rotation
// Q = Qp * q --> q' = Qp^ * Q
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetPose.rot;
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetRotation;
RotationConstraint* constraint = getConstraint(tipIndex);
if (constraint) {
constraint->apply(newRelativeRotation);
@ -303,7 +302,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
// to help this rotation target get met.
}
_relativePoses[tipIndex].rot = newRelativeRotation;
absolutePoses[tipIndex].rot = targetPose.rot;
absolutePoses[tipIndex].rot = targetRotation;
}
}
}
@ -369,31 +368,30 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
// compute the new target hips offset (for next frame)
// by looking for discrepancies between where a targeted endEffector is
// and where it wants to be (after IK solutions are done)
glm::vec3 newOffset = Vectors::ZERO;
glm::vec3 newHipsOffset = Vectors::ZERO;
for (auto& target: targets) {
if (target.index == _headIndex && _headIndex != -1) {
int targetIndex = target.getIndex();
if (targetIndex == _headIndex && _headIndex != -1) {
// special handling for headTarget
AnimPose headUnderPose = _skeleton->getAbsolutePose(_headIndex, underPoses);
AnimPose headOverPose = headUnderPose;
if (target.type == IKTarget::Type::RotationOnly) {
headOverPose = _skeleton->getAbsolutePose(_headIndex, _relativePoses);
} else if (target.type == IKTarget::Type::RotationAndPosition) {
headOverPose = target.pose;
glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans;
glm::vec3 over = under;
if (target.getType() == IKTarget::Type::RotationOnly) {
over = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans;
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
over = target.getTranslation();
}
glm::vec3 headOffset = headOverPose.trans - headUnderPose.trans;
const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f;
newOffset += HEAD_OFFSET_SLAVE_FACTOR * headOffset;
} else if (target.type == IKTarget::Type::RotationAndPosition) {
glm::vec3 actualPosition = _skeleton->getAbsolutePose(target.index, _relativePoses).trans;
glm::vec3 targetPosition = target.pose.trans;
newOffset += targetPosition - actualPosition;
newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (over - under);
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans;
glm::vec3 targetPosition = target.getTranslation();
newHipsOffset += targetPosition - actualPosition;
}
}
// smooth transitions by relaxing _hipsOffset toward the new value
const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f;
glm::vec3 deltaOffset = (newOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE);
_hipsOffset += deltaOffset;
_hipsOffset += (newHipsOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE);
}
}
return _relativePoses;

View file

@ -16,6 +16,7 @@
#include <vector>
#include "AnimNode.h"
#include "IKTarget.h"
#include "RotationAccumulator.h"
@ -37,18 +38,6 @@ public:
virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override;
protected:
struct IKTarget {
enum class Type {
RotationAndPosition,
RotationOnly
};
AnimPose pose;
int index;
Type type = Type::RotationAndPosition;
void setType(const QString& typeVar) { type = ((typeVar == "RotationOnly") ? Type::RotationOnly : Type::RotationAndPosition); }
};
void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses);
void solveWithCyclicCoordinateDescent(const std::vector<IKTarget>& targets);
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override;

View file

@ -0,0 +1,31 @@
//
// IKTarget.cpp
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "IKTarget.h"
void IKTarget::setPose(const glm::quat& rotation, const glm::vec3& translation) {
_pose.rot = rotation;
_pose.trans = translation;
}
void IKTarget::setType(int type) {
switch (type) {
case (int)Type::RotationAndPosition:
_type = Type::RotationAndPosition;
break;
case (int)Type::RotationOnly:
_type = Type::RotationOnly;
break;
case (int)Type::HmdHead:
_type = Type::HmdHead;
break;
default:
_type = Type::Unknown;
}
}

View file

@ -0,0 +1,42 @@
//
// IKTarget.h
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_IKTarget_h
#define hifi_IKTarget_h
#include "AnimSkeleton.h"
class IKTarget {
public:
enum class Type {
RotationAndPosition,
RotationOnly,
HmdHead,
Unknown,
};
IKTarget() {}
const glm::vec3& getTranslation() const { return _pose.trans; }
const glm::quat& getRotation() const { return _pose.rot; }
int getIndex() const { return _index; }
Type getType() const { return _type; }
void setPose(const glm::quat& rotation, const glm::vec3& translation);
void setIndex(int index) { _index = index; }
void setType(int);
private:
AnimPose _pose;
int _index = -1;
Type _type = Type::RotationAndPosition;
};
#endif // hifi_IKTarget_h

View file

@ -14,13 +14,14 @@
#include <glm/gtx/vector_angle.hpp>
#include <queue>
#include "NumericalConstants.h"
#include <NumericalConstants.h>
#include <DebugDraw.h>
#include "AnimationHandle.h"
#include "AnimationLogging.h"
#include "AnimSkeleton.h"
#include "DebugDraw.h"
#include "IKTarget.h"
#include "Rig.h"
void Rig::HeadParameters::dump() const {
qCDebug(animation, "HeadParameters =");
@ -1057,7 +1058,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
_animVars.set("headPosition", headPos);
_animVars.set("headRotation", headRot);
_animVars.set("headAndNeckType", QString("RotationAndPosition"));
_animVars.set("headAndNeckType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("neckPosition", neckPos);
_animVars.set("neckRotation", neckRot);
@ -1070,7 +1071,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
_animVars.unset("headPosition");
_animVars.set("headRotation", realLocalHeadOrientation);
_animVars.set("headAndNeckType", QString("RotationOnly"));
_animVars.set("headAndNeckType", (int)IKTarget::Type::RotationOnly);
_animVars.unset("neckPosition");
_animVars.unset("neckRotation");
}