mirror of
https://github.com/overte-org/overte.git
synced 2025-05-28 00:50:30 +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 {
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
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 <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");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue