From 03eaa9525836518c854f49b1d77eb763bfa609fe Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 8 Oct 2015 16:39:25 -0700 Subject: [PATCH 01/11] initial hip translation from IK works for 2D 3rd person but probably not well for HMD --- .../defaultAvatar_full/avatar-animation.json | 12 ++++ .../animation/src/AnimInverseKinematics.cpp | 62 +++++++++++++++++-- .../animation/src/AnimInverseKinematics.h | 11 +++- 3 files changed, 77 insertions(+), 8 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index dceecddfe0..e930f583f6 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -23,6 +23,18 @@ "positionVar": "leftHandPosition", "rotationVar": "leftHandRotation" }, + { + "jointName": "RightFoot", + "positionVar": "rightToePosition", + "rotationVar": "rightToeRotation", + "typeVar": "rightToeType" + }, + { + "jointName": "LeftFoot", + "positionVar": "leftToePosition", + "rotationVar": "leftToeRotation", + "typeVar": "leftToeType" + }, { "jointName": "Neck", "positionVar": "neckPosition", diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 8a9971f362..54ec2d839b 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -343,7 +343,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars // build a list of targets from _targetVarVec std::vector targets; computeTargets(animVars, targets, underPoses); - + if (targets.empty()) { // no IK targets but still need to enforce constraints std::map::iterator constraintItr = _constraints.begin(); @@ -355,7 +355,45 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars ++constraintItr; } } else { + // shift the hips according to the offset from the previous frame + float offsetLength = glm::length(_actualHipsOffset); + const float MIN_OFFSET_LENGTH = 0.03f; + if (offsetLength > MIN_OFFSET_LENGTH) { + // but only if actual offset is long enough + float scaleFactor = ((offsetLength - MIN_OFFSET_LENGTH) / offsetLength); + _relativePoses[0].trans = underPoses[0].trans + scaleFactor * _actualHipsOffset; + } + solveWithCyclicCoordinateDescent(targets); + + // 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) + _targetHipsOffset = Vectors::ZERO; + for (auto& target: targets) { + if (target.index == _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 headOffset = headOverPose.trans - headUnderPose.trans; + const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; + _targetHipsOffset += 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; + _targetHipsOffset += targetPosition - actualPosition; + } + } + + // smooth transitions by relaxing targetHipsOffset onto actualHipsOffset over some timescale + const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f; + glm::vec3 deltaOffset = (_targetHipsOffset - _actualHipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE); + _actualHipsOffset += deltaOffset; } } return _relativePoses; @@ -477,7 +515,7 @@ void AnimInverseKinematics::initConstraints() { stConstraint->setSwingLimits(minDots); constraint = static_cast(stConstraint); - } else if (0 == baseName.compare("UpLegXXX", Qt::CaseInsensitive)) { + } else if (0 == baseName.compare("UpLeg", Qt::CaseInsensitive)) { SwingTwistConstraint* stConstraint = new SwingTwistConstraint(); stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot); stConstraint->setTwistLimits(-PI / 4.0f, PI / 4.0f); @@ -581,7 +619,7 @@ void AnimInverseKinematics::initConstraints() { } else if (0 == baseName.compare("Neck", Qt::CaseInsensitive)) { SwingTwistConstraint* stConstraint = new SwingTwistConstraint(); stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot); - const float MAX_NECK_TWIST = PI / 2.0f; + const float MAX_NECK_TWIST = PI / 4.0f; stConstraint->setTwistLimits(-MAX_NECK_TWIST, MAX_NECK_TWIST); std::vector minDots; @@ -589,6 +627,18 @@ void AnimInverseKinematics::initConstraints() { minDots.push_back(cosf(MAX_NECK_SWING)); stConstraint->setSwingLimits(minDots); + constraint = static_cast(stConstraint); + } else if (0 == baseName.compare("Head", Qt::CaseInsensitive)) { + SwingTwistConstraint* stConstraint = new SwingTwistConstraint(); + stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot); + const float MAX_HEAD_TWIST = PI / 4.0f; + stConstraint->setTwistLimits(-MAX_HEAD_TWIST, MAX_HEAD_TWIST); + + std::vector minDots; + const float MAX_HEAD_SWING = PI / 4.0f; + minDots.push_back(cosf(MAX_HEAD_SWING)); + stConstraint->setSwingLimits(minDots); + constraint = static_cast(stConstraint); } else if (0 == baseName.compare("ForeArm", Qt::CaseInsensitive)) { // The elbow joint rotates about the parent-frame's zAxis (-zAxis) for the Right (Left) arm. @@ -621,7 +671,7 @@ void AnimInverseKinematics::initConstraints() { eConstraint->setAngleLimits(minAngle, maxAngle); constraint = static_cast(eConstraint); - } else if (0 == baseName.compare("LegXXX", Qt::CaseInsensitive)) { + } else if (0 == baseName.compare("Leg", Qt::CaseInsensitive)) { // The knee joint rotates about the parent-frame's -xAxis. ElbowConstraint* eConstraint = new ElbowConstraint(); glm::quat referenceRotation = _defaultRelativePoses[i].rot; @@ -652,7 +702,7 @@ void AnimInverseKinematics::initConstraints() { eConstraint->setAngleLimits(minAngle, maxAngle); constraint = static_cast(eConstraint); - } else if (0 == baseName.compare("FootXXX", Qt::CaseInsensitive)) { + } else if (0 == baseName.compare("Foot", Qt::CaseInsensitive)) { SwingTwistConstraint* stConstraint = new SwingTwistConstraint(); stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot); stConstraint->setTwistLimits(-PI / 4.0f, PI / 4.0f); @@ -697,7 +747,9 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele if (skeleton) { initConstraints(); + _headIndex = _skeleton->nameToJointIndex("Head"); } else { clearConstraints(); + _headIndex = -1; } } diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index 0ef81f8b3c..634c71cea9 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -60,6 +60,10 @@ protected: void clearConstraints(); void initConstraints(); + // no copies + AnimInverseKinematics(const AnimInverseKinematics&) = delete; + AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete; + struct IKTargetVar { IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, @@ -85,9 +89,10 @@ protected: AnimPoseVec _defaultRelativePoses; // poses of the relaxed state AnimPoseVec _relativePoses; // current relative poses - // no copies - AnimInverseKinematics(const AnimInverseKinematics&) = delete; - AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete; + // experimental data for moving hips during IK + int _headIndex = -1; + glm::vec3 _targetHipsOffset = Vectors::ZERO; // offset we want + glm::vec3 _actualHipsOffset = Vectors::ZERO; // offset we have // _maxTargetIndex is tracked to help optimize the recalculation of absolute poses // during the the cyclic coordinate descent algorithm From 56f038d5a7409e16dd4c97a7ed39a830c824b0b8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 10 Oct 2015 10:13:33 -0700 Subject: [PATCH 02/11] simpler logic for tracking hips offset --- .../animation/src/AnimInverseKinematics.cpp | 16 ++++++++-------- libraries/animation/src/AnimInverseKinematics.h | 3 +-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 54ec2d839b..247a7c8409 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -356,12 +356,12 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars } } else { // shift the hips according to the offset from the previous frame - float offsetLength = glm::length(_actualHipsOffset); + float offsetLength = glm::length(_hipsOffset); const float MIN_OFFSET_LENGTH = 0.03f; if (offsetLength > MIN_OFFSET_LENGTH) { // but only if actual offset is long enough float scaleFactor = ((offsetLength - MIN_OFFSET_LENGTH) / offsetLength); - _relativePoses[0].trans = underPoses[0].trans + scaleFactor * _actualHipsOffset; + _relativePoses[0].trans = underPoses[0].trans + scaleFactor * _hipsOffset; } solveWithCyclicCoordinateDescent(targets); @@ -369,7 +369,7 @@ 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) - _targetHipsOffset = Vectors::ZERO; + glm::vec3 newOffset = Vectors::ZERO; for (auto& target: targets) { if (target.index == _headIndex && _headIndex != -1) { // special handling for headTarget @@ -382,18 +382,18 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars } glm::vec3 headOffset = headOverPose.trans - headUnderPose.trans; const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; - _targetHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * headOffset; + 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; - _targetHipsOffset += targetPosition - actualPosition; + newOffset += targetPosition - actualPosition; } } - // smooth transitions by relaxing targetHipsOffset onto actualHipsOffset over some timescale + // smooth transitions by relaxing _hipsOffset toward the new value const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f; - glm::vec3 deltaOffset = (_targetHipsOffset - _actualHipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE); - _actualHipsOffset += deltaOffset; + glm::vec3 deltaOffset = (newOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE); + _hipsOffset += deltaOffset; } } return _relativePoses; diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index 634c71cea9..8fc03b7a0a 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -91,8 +91,7 @@ protected: // experimental data for moving hips during IK int _headIndex = -1; - glm::vec3 _targetHipsOffset = Vectors::ZERO; // offset we want - glm::vec3 _actualHipsOffset = Vectors::ZERO; // offset we have + glm::vec3 _hipsOffset = Vectors::ZERO; // _maxTargetIndex is tracked to help optimize the recalculation of absolute poses // during the the cyclic coordinate descent algorithm From bc48f70877190f4542a53006d4671745ee3fbb99 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 10 Oct 2015 11:15:51 -0700 Subject: [PATCH 03/11] move IKTarget into its own files --- .../animation/src/AnimInverseKinematics.cpp | 66 +++++++++---------- .../animation/src/AnimInverseKinematics.h | 13 +--- libraries/animation/src/IKTarget.cpp | 31 +++++++++ libraries/animation/src/IKTarget.h | 42 ++++++++++++ libraries/animation/src/Rig.cpp | 11 ++-- 5 files changed, 112 insertions(+), 51 deletions(-) create mode 100644 libraries/animation/src/IKTarget.cpp create mode 100644 libraries/animation/src/IKTarget.h diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 247a7c8409..00a752c69b 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -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& targets, const AnimPoseVec& underPoses); void solveWithCyclicCoordinateDescent(const std::vector& targets); virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override; diff --git a/libraries/animation/src/IKTarget.cpp b/libraries/animation/src/IKTarget.cpp new file mode 100644 index 0000000000..a7e3296d35 --- /dev/null +++ b/libraries/animation/src/IKTarget.cpp @@ -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; + } +} diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h new file mode 100644 index 0000000000..fa920d1511 --- /dev/null +++ b/libraries/animation/src/IKTarget.h @@ -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 diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 7f300fc84a..3a1dafa10c 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -14,13 +14,14 @@ #include #include -#include "NumericalConstants.h" +#include +#include + #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"); } From 6a96d5f0c5d9b52a7e4c84a2555c0788637e4f9b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 10 Oct 2015 14:37:19 -0700 Subject: [PATCH 04/11] don't bother to create targets with bad types --- .../animation/src/AnimInverseKinematics.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 00a752c69b..c9f0960a4f 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -95,14 +95,16 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: } } else { IKTarget target; - AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses); - 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 (targetVar.jointIndex > _maxTargetIndex) { - _maxTargetIndex = targetVar.jointIndex; + target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition)); + if (target.getType() != IKTarget::Type::Unknown) { + AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses); + target.setPose(animVars.lookup(targetVar.rotationVar, defaultPose.rot), + animVars.lookup(targetVar.positionVar, defaultPose.trans)); + target.setIndex(targetVar.jointIndex); + targets.push_back(target); + if (targetVar.jointIndex > _maxTargetIndex) { + _maxTargetIndex = targetVar.jointIndex; + } } } } From 5f1068c404facaf50389606946413b2b75265b2b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 10 Oct 2015 15:53:03 -0700 Subject: [PATCH 05/11] cleanup and optimization of IK loop --- .../animation/src/AnimInverseKinematics.cpp | 183 +++++++++--------- 1 file changed, 90 insertions(+), 93 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index c9f0960a4f..0d1868d955 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -143,106 +143,114 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vectorgetParentIndex(tipIndex); + if (pivotIndex == -1) { + continue; + } + int pivotsParentIndex = _skeleton->getParentIndex(pivotIndex); + if (pivotsParentIndex == -1) { + // TODO?: handle case where tip's parent is root? + continue; + } + glm::vec3 tipPosition = absolutePoses[tipIndex].trans; - glm::quat tipRotation = absolutePoses[tipIndex].rot; + //glm::quat tipRotation = absolutePoses[tipIndex].rot; // cache tip's parent's absolute rotation so we can recompute the tip's parent-relative // as we proceed walking down the joint chain - int pivotIndex = _skeleton->getParentIndex(tipIndex); - glm::quat tipParentRotation; - if (pivotIndex != -1) { - tipParentRotation = absolutePoses[pivotIndex].rot; - } + glm::quat tipParentRotation = absolutePoses[pivotIndex].rot; // descend toward root, pivoting each joint to get tip closer to target - int ancestorCount = 1; - while (pivotIndex != -1) { + while (pivotsParentIndex != -1) { // compute the two lines that should be aligned glm::vec3 jointPosition = absolutePoses[pivotIndex].trans; glm::vec3 leverArm = tipPosition - jointPosition; - glm::vec3 targetLine = target.getTranslation() - jointPosition; - // compute the swing that would get get tip closer - glm::vec3 axis = glm::cross(leverArm, targetLine); - float axisLength = glm::length(axis); glm::quat deltaRotation; - const float MIN_AXIS_LENGTH = 1.0e-4f; - if (axisLength > MIN_AXIS_LENGTH) { - // compute deltaRotation for alignment (swings tip closer to target) - axis /= axisLength; - float angle = acosf(glm::dot(leverArm, targetLine) / (glm::length(leverArm) * glm::length(targetLine))); - - // NOTE: even when axisLength is not zero (e.g. lever-arm and pivot-arm are not quite aligned) it is - // still possible for the angle to be zero so we also check that to avoid unnecessary calculations. - const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f; - if (angle > MIN_ADJUSTMENT_ANGLE) { - // reduce angle by a fraction (reduces IK swing contribution of this joint) - angle /= (float)ancestorCount; - 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 - // new rotation and its target. We compute that delta here and rotate the tipJoint accordingly. - glm::quat tipRelativeRotation = glm::inverse(deltaRotation * tipParentRotation) * target.getRotation(); - - // enforce tip's constraint - RotationConstraint* constraint = getConstraint(tipIndex); - if (constraint) { - bool constrained = constraint->apply(tipRelativeRotation); - if (constrained) { - // 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 = target.getRotation() * glm::inverse(constrainedTipRotation); - glm::quat swingPart; - glm::quat twistPart; - glm::vec3 axis = glm::normalize(deltaRotation * leverArm); - swingTwistDecomposition(missingRotation, axis, swingPart, twistPart); - deltaRotation = twistPart * deltaRotation; - } - // we update the tip rotation here to rotate it as close to its target orientation as possible - // before moving on to next pivot - tipRotation = tipParentRotation * tipRelativeRotation; - } - } - ++ancestorCount; - - int parentIndex = _skeleton->getParentIndex(pivotIndex); - if (parentIndex == -1) { - // TODO? apply constraints to root? - // TODO? harvest the root's transform as movement of entire skeleton? - } else { - // compute joint's new parent-relative rotation after swing - // Q' = dQ * Q and Q = Qp * q --> q' = Qp^ * dQ * Q - glm::quat newRot = glm::normalize(glm::inverse( - absolutePoses[parentIndex].rot) * - deltaRotation * - absolutePoses[pivotIndex].rot); - - // enforce pivot's constraint - RotationConstraint* constraint = getConstraint(pivotIndex); - if (constraint) { - bool constrained = constraint->apply(newRot); - if (constrained) { - // the constraint will modify the movement of the tip so we have to compute the modified - // model-frame deltaRotation - // Q' = Qp^ * dQ * Q --> dQ = Qp * Q' * Q^ - deltaRotation = absolutePoses[parentIndex].rot * - newRot * - glm::inverse(absolutePoses[pivotIndex].rot); + if (targetType == IKTarget::Type::RotationAndPosition) { + // compute the swing that would get get tip closer + glm::vec3 targetLine = target.getTranslation() - jointPosition; + glm::vec3 axis = glm::cross(leverArm, targetLine); + float axisLength = glm::length(axis); + const float MIN_AXIS_LENGTH = 1.0e-4f; + if (axisLength > MIN_AXIS_LENGTH) { + // compute deltaRotation for alignment (swings tip closer to target) + axis /= axisLength; + float angle = acosf(glm::dot(leverArm, targetLine) / (glm::length(leverArm) * glm::length(targetLine))); + + // NOTE: even when axisLength is not zero (e.g. lever-arm and pivot-arm are not quite aligned) it is + // still possible for the angle to be zero so we also check that to avoid unnecessary calculations. + const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f; + if (angle > MIN_ADJUSTMENT_ANGLE) { + // reduce angle by a fraction (for stability) + const float fraction = 0.5f; + angle *= fraction; + 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 + // new rotation and its target. This is the final parent-relative rotation that the tip joint have + // make to achieve its target rotation. + glm::quat tipRelativeRotation = glm::inverse(deltaRotation * tipParentRotation) * target.getRotation(); + + // enforce tip's constraint + RotationConstraint* constraint = getConstraint(tipIndex); + if (constraint) { + bool constrained = constraint->apply(tipRelativeRotation); + if (constrained) { + // The tip's final parent-relative rotation would violate its constraint + // so we try to pre-twist this pivot to compensate. + glm::quat constrainedTipRotation = deltaRotation * tipParentRotation * tipRelativeRotation; + glm::quat missingRotation = target.getRotation() * glm::inverse(constrainedTipRotation); + glm::quat swingPart; + glm::quat twistPart; + glm::vec3 axis = glm::normalize(deltaRotation * leverArm); + swingTwistDecomposition(missingRotation, axis, swingPart, twistPart); + float dotSign = copysignf(1.0f, twistPart.w); + deltaRotation = glm::normalize(glm::lerp(glm::quat(), dotSign * twistPart, fraction)) * deltaRotation; + } + } } } - - // store the rotation change in the accumulator - _accumulators[pivotIndex].add(newRot); + } else if (targetType == IKTarget::Type::HmdHead) { + /* TODO: implement this + // An HmdHead target slaves the orientation of the end-effector by distributing rotation + // deltas up the hierarchy. Its target position is enforced later by shifting the hips. + deltaRotation = target.getRotation() * glm::inverse(tipRotation); + */ } + + // compute joint's new parent-relative rotation after swing + // Q' = dQ * Q and Q = Qp * q --> q' = Qp^ * dQ * Q + glm::quat newRot = glm::normalize(glm::inverse( + absolutePoses[pivotsParentIndex].rot) * + deltaRotation * + absolutePoses[pivotIndex].rot); + + // enforce pivot's constraint + RotationConstraint* constraint = getConstraint(pivotIndex); + if (constraint) { + bool constrained = constraint->apply(newRot); + if (constrained) { + // the constraint will modify the movement of the tip so we have to compute the modified + // model-frame deltaRotation + // Q' = Qp^ * dQ * Q --> dQ = Qp * Q' * Q^ + deltaRotation = absolutePoses[pivotsParentIndex].rot * + newRot * + glm::inverse(absolutePoses[pivotIndex].rot); + } + } + + // store the rotation change in the accumulator + _accumulators[pivotIndex].add(newRot); + // this joint has been changed so we check to see if it has the lowest index if (pivotIndex < lowestMovedIndex) { lowestMovedIndex = pivotIndex; @@ -250,10 +258,10 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vectorgetParentIndex(pivotIndex); + pivotIndex = pivotsParentIndex; + pivotsParentIndex = _skeleton->getParentIndex(pivotIndex); } } ++numLoops; @@ -276,17 +284,6 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector Date: Sat, 10 Oct 2015 19:23:21 -0700 Subject: [PATCH 07/11] experimental HMD hips tracking --- .../defaultAvatar_full/avatar-animation.json | 12 +++--- interface/src/avatar/MyAvatar.cpp | 4 +- .../animation/src/AnimInverseKinematics.cpp | 40 ++++++++++++++----- libraries/animation/src/IKTarget.cpp | 3 ++ libraries/animation/src/IKTarget.h | 1 + libraries/animation/src/Rig.cpp | 10 ++++- 6 files changed, 53 insertions(+), 17 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index e930f583f6..737a27be02 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -16,12 +16,14 @@ { "jointName": "RightHand", "positionVar": "rightHandPosition", - "rotationVar": "rightHandRotation" + "rotationVar": "rightHandRotation", + "typeVar": "rightHandType" }, { "jointName": "LeftHand", "positionVar": "leftHandPosition", - "rotationVar": "leftHandRotation" + "rotationVar": "leftHandRotation", + "typeVar": "leftHandType" }, { "jointName": "RightFoot", @@ -39,13 +41,13 @@ "jointName": "Neck", "positionVar": "neckPosition", "rotationVar": "neckRotation", - "typeVar": "headAndNeckType" + "typeVar": "neckType" }, { "jointName": "Head", "positionVar": "headPosition", "rotationVar": "headRotation", - "typeVar": "headAndNeckType" + "typeVar": "headType" } ] }, @@ -63,7 +65,7 @@ "id": "spineLean", "type": "manipulator", "data": { - "alpha": 1.0, + "alpha": 0.0, "joints": [ { "var": "lean", "jointName": "Spine" } ] diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 22816e9001..41e067c047 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -337,16 +337,18 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { const float STRAIGHTENING_LEAN_DURATION = 0.5f; // seconds // define a vertical capsule + static float adebug = 1.0f; // adebug const float STRAIGHTENING_LEAN_CAPSULE_RADIUS = 0.2f; // meters const float STRAIGHTENING_LEAN_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters. auto newBodySensorMatrix = deriveBodyFromHMDSensor(); glm::vec3 diff = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix); - if (!_straighteningLean && (capsuleCheck(diff, STRAIGHTENING_LEAN_CAPSULE_LENGTH, STRAIGHTENING_LEAN_CAPSULE_RADIUS) || hmdIsAtRest)) { + if (!_straighteningLean && (capsuleCheck(diff, adebug * STRAIGHTENING_LEAN_CAPSULE_LENGTH, adebug * STRAIGHTENING_LEAN_CAPSULE_RADIUS) || hmdIsAtRest)) { // begin homing toward derived body position. _straighteningLean = true; _straighteningLeanAlpha = 0.0f; + adebug = 1000.0f; // adebug } else if (_straighteningLean) { diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 80c8152e3a..7e677abcba 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -98,8 +98,14 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition)); if (target.getType() != IKTarget::Type::Unknown) { AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses); - target.setPose(animVars.lookup(targetVar.rotationVar, defaultPose.rot), - animVars.lookup(targetVar.positionVar, defaultPose.trans)); + glm::quat rotation = animVars.lookup(targetVar.rotationVar, defaultPose.rot); + glm::vec3 translation = animVars.lookup(targetVar.positionVar, defaultPose.trans); + if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) { + translation += _hipsOffset; + // HACK to test whether lifting idle hands will release the shoulders + translation.y += 0.10f; + } + target.setPose(rotation, translation); target.setIndex(targetVar.jointIndex); targets.push_back(target); if (targetVar.jointIndex > _maxTargetIndex) { @@ -125,6 +131,10 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: } } } + static int adebug = 0; ++adebug; bool verbose = (0 == (adebug % 100)); + if (verbose) { + std::cout << "adebug num targets = " << targets.size() << std::endl; // adebug + } } void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector& targets) { @@ -175,7 +185,8 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vectorgetAbsolutePose(_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(); + // we want to shift the hips to bring the underpose closer + // to where the head happens to be (overpose) + glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans; + glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans; + const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; + newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under); + } else if (target.getType() == IKTarget::Type::HmdHead) { + // we want to shift the hips to bring the head to its designated position + glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans; + hmdHipsOffset = _hipsOffset + target.getTranslation() - actual; } - const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; - 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(); @@ -392,6 +408,10 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars // smooth transitions by relaxing _hipsOffset toward the new value const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f; _hipsOffset += (newHipsOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE); + //_hipsOffset *= 0.0f; // adebug + if (glm::length2(hmdHipsOffset) < 100.0f) { + _hipsOffset = hmdHipsOffset; + } } } return _relativePoses; diff --git a/libraries/animation/src/IKTarget.cpp b/libraries/animation/src/IKTarget.cpp index a7e3296d35..b17f186b47 100644 --- a/libraries/animation/src/IKTarget.cpp +++ b/libraries/animation/src/IKTarget.cpp @@ -25,6 +25,9 @@ void IKTarget::setType(int type) { case (int)Type::HmdHead: _type = Type::HmdHead; break; + case (int)Type::HipsRelativeRotationAndPosition: + _type = Type::HipsRelativeRotationAndPosition; + break; default: _type = Type::Unknown; } diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h index fa920d1511..983eafd9cb 100644 --- a/libraries/animation/src/IKTarget.h +++ b/libraries/animation/src/IKTarget.h @@ -18,6 +18,7 @@ public: RotationAndPosition, RotationOnly, HmdHead, + HipsRelativeRotationAndPosition, Unknown, }; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 3a1dafa10c..340c09060a 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1058,9 +1058,11 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) { _animVars.set("headPosition", headPos); _animVars.set("headRotation", headRot); - _animVars.set("headAndNeckType", (int)IKTarget::Type::RotationAndPosition); + _animVars.set("headType", (int)IKTarget::Type::HmdHead); _animVars.set("neckPosition", neckPos); _animVars.set("neckRotation", neckRot); + //_animVars.set("neckType", (int)IKTarget::Type::RotationOnly); + _animVars.set("neckType", (int)IKTarget::Type::Unknown); // 'Unknown' disables the target } else { @@ -1072,8 +1074,10 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) { _animVars.unset("headPosition"); _animVars.set("headRotation", realLocalHeadOrientation); _animVars.set("headAndNeckType", (int)IKTarget::Type::RotationOnly); + _animVars.set("headType", (int)IKTarget::Type::RotationOnly); _animVars.unset("neckPosition"); _animVars.unset("neckRotation"); + _animVars.set("neckType", (int)IKTarget::Type::RotationOnly); } } else if (!_enableAnimGraph) { @@ -1131,16 +1135,20 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) { if (params.isLeftEnabled) { _animVars.set("leftHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.leftPosition); _animVars.set("leftHandRotation", rootBindPose.rot * yFlipHACK * params.leftOrientation); + _animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition); } else { _animVars.unset("leftHandPosition"); _animVars.unset("leftHandRotation"); + _animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); } if (params.isRightEnabled) { _animVars.set("rightHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.rightPosition); _animVars.set("rightHandRotation", rootBindPose.rot * yFlipHACK * params.rightOrientation); + _animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition); } else { _animVars.unset("rightHandPosition"); _animVars.unset("rightHandRotation"); + _animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); } // set leftHand grab vars From 44243aaa523b424d257d282f03be6936819d88af Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 12 Oct 2015 11:34:07 -0700 Subject: [PATCH 08/11] remove some debug code --- libraries/animation/src/AnimInverseKinematics.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 7e677abcba..fd25705660 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -131,10 +131,6 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: } } } - static int adebug = 0; ++adebug; bool verbose = (0 == (adebug % 100)); - if (verbose) { - std::cout << "adebug num targets = " << targets.size() << std::endl; // adebug - } } void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector& targets) { @@ -408,7 +404,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars // smooth transitions by relaxing _hipsOffset toward the new value const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f; _hipsOffset += (newHipsOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE); - //_hipsOffset *= 0.0f; // adebug if (glm::length2(hmdHipsOffset) < 100.0f) { _hipsOffset = hmdHipsOffset; } From e1a5afcff317bf58190c8a52b34af624aebaa449 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 12 Oct 2015 11:42:03 -0700 Subject: [PATCH 09/11] re-enable avatar position update when moving HMD --- interface/src/avatar/MyAvatar.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 41e067c047..22816e9001 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -337,18 +337,16 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { const float STRAIGHTENING_LEAN_DURATION = 0.5f; // seconds // define a vertical capsule - static float adebug = 1.0f; // adebug const float STRAIGHTENING_LEAN_CAPSULE_RADIUS = 0.2f; // meters const float STRAIGHTENING_LEAN_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters. auto newBodySensorMatrix = deriveBodyFromHMDSensor(); glm::vec3 diff = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix); - if (!_straighteningLean && (capsuleCheck(diff, adebug * STRAIGHTENING_LEAN_CAPSULE_LENGTH, adebug * STRAIGHTENING_LEAN_CAPSULE_RADIUS) || hmdIsAtRest)) { + if (!_straighteningLean && (capsuleCheck(diff, STRAIGHTENING_LEAN_CAPSULE_LENGTH, STRAIGHTENING_LEAN_CAPSULE_RADIUS) || hmdIsAtRest)) { // begin homing toward derived body position. _straighteningLean = true; _straighteningLeanAlpha = 0.0f; - adebug = 1000.0f; // adebug } else if (_straighteningLean) { From 22786dea7d3d3438888fe46cbadc15215b5b5fce Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 12 Oct 2015 13:35:26 -0700 Subject: [PATCH 10/11] cleanup --- .../defaultAvatar_full/avatar-animation.json | 12 +++++------ .../animation/src/AnimInverseKinematics.cpp | 20 ++++++++----------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 737a27be02..682e0be1bf 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -27,15 +27,15 @@ }, { "jointName": "RightFoot", - "positionVar": "rightToePosition", - "rotationVar": "rightToeRotation", - "typeVar": "rightToeType" + "positionVar": "rightFootPosition", + "rotationVar": "rightFootRotation", + "typeVar": "rightFootType" }, { "jointName": "LeftFoot", - "positionVar": "leftToePosition", - "rotationVar": "leftToeRotation", - "typeVar": "leftToeType" + "positionVar": "leftFootPosition", + "rotationVar": "leftFootRotation", + "typeVar": "leftFootType" }, { "jointName": "Neck", diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index fd25705660..a1c6848b0c 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -102,8 +102,6 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: glm::vec3 translation = animVars.lookup(targetVar.positionVar, defaultPose.trans); if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) { translation += _hipsOffset; - // HACK to test whether lifting idle hands will release the shoulders - translation.y += 0.10f; } target.setPose(rotation, translation); target.setIndex(targetVar.jointIndex); @@ -363,20 +361,18 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars } else { // shift the hips according to the offset from the previous frame float offsetLength = glm::length(_hipsOffset); - const float MIN_OFFSET_LENGTH = 0.03f; - if (offsetLength > MIN_OFFSET_LENGTH) { - // but only if actual offset is long enough - float scaleFactor = ((offsetLength - MIN_OFFSET_LENGTH) / offsetLength); + const float MIN_HIPS_OFFSET_LENGTH = 0.03f; + if (offsetLength > MIN_HIPS_OFFSET_LENGTH) { + // but only if offset is long enough + float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength); _relativePoses[0].trans = underPoses[0].trans + scaleFactor * _hipsOffset; } solveWithCyclicCoordinateDescent(targets); - // 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 hmdHipsOffset(100.0f); glm::vec3 newHipsOffset = Vectors::ZERO; for (auto& target: targets) { int targetIndex = target.getIndex(); @@ -392,7 +388,10 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars } else if (target.getType() == IKTarget::Type::HmdHead) { // we want to shift the hips to bring the head to its designated position glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans; - hmdHipsOffset = _hipsOffset + target.getTranslation() - actual; + _hipsOffset += target.getTranslation() - actual; + // and ignore all other targets + newHipsOffset = _hipsOffset; + break; } } else if (target.getType() == IKTarget::Type::RotationAndPosition) { glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans; @@ -404,9 +403,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars // smooth transitions by relaxing _hipsOffset toward the new value const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f; _hipsOffset += (newHipsOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE); - if (glm::length2(hmdHipsOffset) < 100.0f) { - _hipsOffset = hmdHipsOffset; - } } } return _relativePoses; From 8ebdd25b7123e9620545471ac9783ca9a66e4c79 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 12 Oct 2015 14:07:23 -0700 Subject: [PATCH 11/11] more cleanup --- .../animation/src/AnimInverseKinematics.cpp | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index a1c6848b0c..17a1af1969 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -56,9 +56,9 @@ void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) con } void AnimInverseKinematics::setTargetVars( - const QString& jointName, - const QString& positionVar, - const QString& rotationVar, + const QString& jointName, + const QString& positionVar, + const QString& rotationVar, const QString& typeVar) { // if there are dups, last one wins. bool found = false; @@ -98,7 +98,7 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition)); if (target.getType() != IKTarget::Type::Unknown) { AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses); - glm::quat rotation = animVars.lookup(targetVar.rotationVar, defaultPose.rot); + glm::quat rotation = animVars.lookup(targetVar.rotationVar, defaultPose.rot); glm::vec3 translation = animVars.lookup(targetVar.positionVar, defaultPose.trans); if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) { translation += _hipsOffset; @@ -168,7 +168,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vectorapply(tipRelativeRotation); if (constrained) { - // The tip's final parent-relative rotation would violate its constraint + // The tip's final parent-relative rotation would violate its constraint // so we try to pre-twist this pivot to compensate. glm::quat constrainedTipRotation = deltaRotation * tipParentRotation * tipRelativeRotation; glm::quat missingRotation = target.getRotation() * glm::inverse(constrainedTipRotation); @@ -225,11 +225,12 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vectorgetAbsolutePose(_headIndex, underPoses).trans; glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans;