mirror of
https://github.com/overte-org/overte.git
synced 2025-06-17 14:20:43 +02:00
move IKTarget into its own files
This commit is contained in:
parent
56f038d5a7
commit
bc48f70877
5 changed files with 112 additions and 51 deletions
|
@ -96,13 +96,13 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
|
||||||
} else {
|
} else {
|
||||||
IKTarget target;
|
IKTarget target;
|
||||||
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
|
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
|
||||||
target.pose.trans = animVars.lookup(targetVar.positionVar, defaultPose.trans);
|
target.setPose(animVars.lookup(targetVar.rotationVar, defaultPose.rot),
|
||||||
target.pose.rot = animVars.lookup(targetVar.rotationVar, defaultPose.rot);
|
animVars.lookup(targetVar.positionVar, defaultPose.trans));
|
||||||
target.setType(animVars.lookup(targetVar.typeVar, QString("")));
|
target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::Unknown));
|
||||||
target.index = targetVar.jointIndex;
|
target.setIndex(targetVar.jointIndex);
|
||||||
targets.push_back(target);
|
targets.push_back(target);
|
||||||
if (target.index > _maxTargetIndex) {
|
if (targetVar.jointIndex > _maxTargetIndex) {
|
||||||
_maxTargetIndex = target.index;
|
_maxTargetIndex = targetVar.jointIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,14 +141,13 @@ 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) {
|
||||||
if (target.type == IKTarget::Type::RotationOnly) {
|
if (target.getType() == IKTarget::Type::RotationOnly) {
|
||||||
// the final rotation will be enforced after the iterations
|
// the final rotation will be enforced after the iterations
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AnimPose targetPose = target.pose;
|
|
||||||
|
|
||||||
// cache tip absolute transform
|
// cache tip absolute transform
|
||||||
int tipIndex = target.index;
|
int tipIndex = target.getIndex();
|
||||||
glm::vec3 tipPosition = absolutePoses[tipIndex].trans;
|
glm::vec3 tipPosition = absolutePoses[tipIndex].trans;
|
||||||
glm::quat tipRotation = absolutePoses[tipIndex].rot;
|
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
|
// compute the two lines that should be aligned
|
||||||
glm::vec3 jointPosition = absolutePoses[pivotIndex].trans;
|
glm::vec3 jointPosition = absolutePoses[pivotIndex].trans;
|
||||||
glm::vec3 leverArm = tipPosition - jointPosition;
|
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
|
// compute the swing that would get get tip closer
|
||||||
glm::vec3 axis = glm::cross(leverArm, targetLine);
|
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
|
// 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.
|
// 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
|
// enforce tip's constraint
|
||||||
RotationConstraint* constraint = getConstraint(tipIndex);
|
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
|
// The tip's final parent-relative rotation violates its constraint
|
||||||
// so we try to twist this pivot to compensate.
|
// so we try to twist this pivot to compensate.
|
||||||
glm::quat constrainedTipRotation = deltaRotation * tipParentRotation * tipRelativeRotation;
|
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 swingPart;
|
||||||
glm::quat twistPart;
|
glm::quat twistPart;
|
||||||
glm::vec3 axis = glm::normalize(deltaRotation * leverArm);
|
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
|
/* KEEP: example code for measuring endeffector error of IK solution
|
||||||
for (uint32_t i = 0; i < targets.size(); ++i) {
|
for (uint32_t i = 0; i < targets.size(); ++i) {
|
||||||
auto& target = targets[i];
|
auto& target = targets[i];
|
||||||
if (target.type == IKTarget::Type::RotationOnly) {
|
if (target.getType() == IKTarget::Type::RotationOnly) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
glm::vec3 tipPosition = absolutePoses[target.index].trans;
|
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
|
// 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.getIndex();
|
||||||
int parentIndex = _skeleton->getParentIndex(tipIndex);
|
int parentIndex = _skeleton->getParentIndex(tipIndex);
|
||||||
if (parentIndex != -1) {
|
if (parentIndex != -1) {
|
||||||
AnimPose targetPose = target.pose;
|
const glm::quat& targetRotation = target.getRotation();
|
||||||
// compute tip's new parent-relative rotation
|
// compute tip's new parent-relative rotation
|
||||||
// Q = Qp * q --> q' = Qp^ * Q
|
// 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);
|
RotationConstraint* constraint = getConstraint(tipIndex);
|
||||||
if (constraint) {
|
if (constraint) {
|
||||||
constraint->apply(newRelativeRotation);
|
constraint->apply(newRelativeRotation);
|
||||||
|
@ -303,7 +302,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
|
||||||
// to help this rotation target get met.
|
// to help this rotation target get met.
|
||||||
}
|
}
|
||||||
_relativePoses[tipIndex].rot = newRelativeRotation;
|
_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)
|
// compute the new target hips offset (for next frame)
|
||||||
// by looking for discrepancies between where a targeted endEffector is
|
// by looking for discrepancies between where a targeted endEffector is
|
||||||
// and where it wants to be (after IK solutions are done)
|
// 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) {
|
for (auto& target: targets) {
|
||||||
if (target.index == _headIndex && _headIndex != -1) {
|
int targetIndex = target.getIndex();
|
||||||
|
if (targetIndex == _headIndex && _headIndex != -1) {
|
||||||
// special handling for headTarget
|
// special handling for headTarget
|
||||||
AnimPose headUnderPose = _skeleton->getAbsolutePose(_headIndex, underPoses);
|
glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans;
|
||||||
AnimPose headOverPose = headUnderPose;
|
glm::vec3 over = under;
|
||||||
if (target.type == IKTarget::Type::RotationOnly) {
|
if (target.getType() == IKTarget::Type::RotationOnly) {
|
||||||
headOverPose = _skeleton->getAbsolutePose(_headIndex, _relativePoses);
|
over = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans;
|
||||||
} else if (target.type == IKTarget::Type::RotationAndPosition) {
|
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
||||||
headOverPose = target.pose;
|
over = target.getTranslation();
|
||||||
}
|
}
|
||||||
glm::vec3 headOffset = headOverPose.trans - headUnderPose.trans;
|
|
||||||
const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f;
|
const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f;
|
||||||
newOffset += HEAD_OFFSET_SLAVE_FACTOR * headOffset;
|
newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (over - under);
|
||||||
} else if (target.type == IKTarget::Type::RotationAndPosition) {
|
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
||||||
glm::vec3 actualPosition = _skeleton->getAbsolutePose(target.index, _relativePoses).trans;
|
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans;
|
||||||
glm::vec3 targetPosition = target.pose.trans;
|
glm::vec3 targetPosition = target.getTranslation();
|
||||||
newOffset += targetPosition - actualPosition;
|
newHipsOffset += targetPosition - actualPosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// smooth transitions by relaxing _hipsOffset toward the new value
|
// smooth transitions by relaxing _hipsOffset toward the new value
|
||||||
const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f;
|
const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f;
|
||||||
glm::vec3 deltaOffset = (newOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE);
|
_hipsOffset += (newHipsOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE);
|
||||||
_hipsOffset += deltaOffset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _relativePoses;
|
return _relativePoses;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "AnimNode.h"
|
#include "AnimNode.h"
|
||||||
|
#include "IKTarget.h"
|
||||||
|
|
||||||
#include "RotationAccumulator.h"
|
#include "RotationAccumulator.h"
|
||||||
|
|
||||||
|
@ -37,18 +38,6 @@ public:
|
||||||
virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override;
|
virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override;
|
||||||
|
|
||||||
protected:
|
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 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) override;
|
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override;
|
||||||
|
|
31
libraries/animation/src/IKTarget.cpp
Normal file
31
libraries/animation/src/IKTarget.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
42
libraries/animation/src/IKTarget.h
Normal file
42
libraries/animation/src/IKTarget.h
Normal 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
|
|
@ -14,13 +14,14 @@
|
||||||
#include <glm/gtx/vector_angle.hpp>
|
#include <glm/gtx/vector_angle.hpp>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "NumericalConstants.h"
|
#include <NumericalConstants.h>
|
||||||
|
#include <DebugDraw.h>
|
||||||
|
|
||||||
#include "AnimationHandle.h"
|
#include "AnimationHandle.h"
|
||||||
#include "AnimationLogging.h"
|
#include "AnimationLogging.h"
|
||||||
#include "AnimSkeleton.h"
|
#include "AnimSkeleton.h"
|
||||||
#include "DebugDraw.h"
|
#include "IKTarget.h"
|
||||||
|
|
||||||
#include "Rig.h"
|
|
||||||
|
|
||||||
void Rig::HeadParameters::dump() const {
|
void Rig::HeadParameters::dump() const {
|
||||||
qCDebug(animation, "HeadParameters =");
|
qCDebug(animation, "HeadParameters =");
|
||||||
|
@ -1057,7 +1058,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("headAndNeckType", QString("RotationAndPosition"));
|
_animVars.set("headAndNeckType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
_animVars.set("neckPosition", neckPos);
|
_animVars.set("neckPosition", neckPos);
|
||||||
_animVars.set("neckRotation", neckRot);
|
_animVars.set("neckRotation", neckRot);
|
||||||
|
|
||||||
|
@ -1070,7 +1071,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("headAndNeckType", QString("RotationOnly"));
|
_animVars.set("headAndNeckType", (int)IKTarget::Type::RotationOnly);
|
||||||
_animVars.unset("neckPosition");
|
_animVars.unset("neckPosition");
|
||||||
_animVars.unset("neckRotation");
|
_animVars.unset("neckRotation");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue