From 54408a9c879aa8cf79bb96efef40c4636b7d4619 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 20 Nov 2015 18:29:17 -0800 Subject: [PATCH] AnimVars are now in avatar/rig space This makes it much simpler for code out side of the rig to manipulate AnimVars * Removed mat4 type from AnimVars * AnimVariantMap now has a _rigToGeometryTransform matrix used to transform positions and rotations into the correct coordinate frame. * Moved AnimPose code to extract a quat from a scaled matrix into GLMHelpers --- interface/src/avatar/MyAvatar.cpp | 22 ++--- .../animation/src/AnimInverseKinematics.cpp | 4 +- libraries/animation/src/AnimManipulator.cpp | 8 +- libraries/animation/src/AnimPose.cpp | 10 +- libraries/animation/src/AnimVariant.cpp | 2 +- libraries/animation/src/AnimVariant.h | 36 +++++--- libraries/animation/src/Rig.cpp | 92 +++++++++---------- libraries/animation/src/Rig.h | 14 +-- libraries/shared/src/GLMHelpers.cpp | 14 ++- libraries/shared/src/GLMHelpers.h | 1 + 10 files changed, 102 insertions(+), 101 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 99bcf64161..e53eec95c1 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1749,12 +1749,10 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { const glm::vec3 DEFAULT_NECK_POS(0.0f, 1.70f, 0.0f); const glm::vec3 DEFAULT_HIPS_POS(0.0f, 1.05f, 0.0f); - AnimPose geometryOffset = _rig->getGeometryOffset(); vec3 localEyes, localNeck; if (!_debugDrawSkeleton) { - const glm::quat rotY180 = glm::angleAxis((float)PI, glm::vec3(0.0f, 1.0f, 0.0f)); - localEyes = rotY180 * (((DEFAULT_RIGHT_EYE_POS + DEFAULT_LEFT_EYE_POS) / 2.0f) - DEFAULT_HIPS_POS); - localNeck = rotY180 * (DEFAULT_NECK_POS - DEFAULT_HIPS_POS); + localEyes = (((DEFAULT_RIGHT_EYE_POS + DEFAULT_LEFT_EYE_POS) / 2.0f) - DEFAULT_HIPS_POS); + localNeck = (DEFAULT_NECK_POS - DEFAULT_HIPS_POS); } else { // TODO: At the moment MyAvatar does not have access to the rig, which has the skeleton, which has the bind poses. // for now use the _debugDrawSkeleton, which is initialized with the same FBX model as the rig. @@ -1765,17 +1763,13 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { int neckIndex = _debugDrawSkeleton->nameToJointIndex("Neck"); int hipsIndex = _debugDrawSkeleton->nameToJointIndex("Hips"); - // AJT: TODO: perhaps expose default gets from rig? - // so this can become _rig->getAbsoluteDefaultPose(rightEyeIndex)... + glm::vec3 absRightEyePos = rightEyeIndex != -1 ? _rig->getAbsoluteDefaultPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS; + glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? _rig->getAbsoluteDefaultPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS; + glm::vec3 absNeckPos = neckIndex != -1 ? _rig->getAbsoluteDefaultPose(neckIndex).trans : DEFAULT_NECK_POS; + glm::vec3 absHipsPos = neckIndex != -1 ? _rig->getAbsoluteDefaultPose(hipsIndex).trans : DEFAULT_HIPS_POS; - glm::vec3 absRightEyePos = rightEyeIndex != -1 ? geometryOffset * _debugDrawSkeleton->getAbsoluteBindPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS; - glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? geometryOffset * _debugDrawSkeleton->getAbsoluteBindPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS; - glm::vec3 absNeckPos = neckIndex != -1 ? geometryOffset * _debugDrawSkeleton->getAbsoluteBindPose(neckIndex).trans : DEFAULT_NECK_POS; - glm::vec3 absHipsPos = neckIndex != -1 ? geometryOffset * _debugDrawSkeleton->getAbsoluteBindPose(hipsIndex).trans : DEFAULT_HIPS_POS; - - const glm::quat rotY180 = glm::angleAxis((float)PI, glm::vec3(0.0f, 1.0f, 0.0f)); - localEyes = rotY180 * (((absRightEyePos + absLeftEyePos) / 2.0f) - absHipsPos); - localNeck = rotY180 * (absNeckPos - absHipsPos); + localEyes = (((absRightEyePos + absLeftEyePos) / 2.0f) - absHipsPos); + localNeck = (absNeckPos - absHipsPos); } // apply simplistic head/neck model diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index d5728b79b4..c057147c03 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -98,8 +98,8 @@ 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::vec3 translation = animVars.lookup(targetVar.positionVar, defaultPose.trans); + glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, defaultPose.rot); + glm::vec3 translation = animVars.lookupRigToGeometry(targetVar.positionVar, defaultPose.trans); if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) { translation += _hipsOffset; } diff --git a/libraries/animation/src/AnimManipulator.cpp b/libraries/animation/src/AnimManipulator.cpp index e8f796f4dd..3eedec5dbd 100644 --- a/libraries/animation/src/AnimManipulator.cpp +++ b/libraries/animation/src/AnimManipulator.cpp @@ -103,9 +103,9 @@ AnimPose AnimManipulator::computeRelativePoseFromJointVar(const AnimVariantMap& if (jointVar.type == JointVar::Type::AbsoluteRotation || jointVar.type == JointVar::Type::AbsolutePosition) { if (jointVar.type == JointVar::Type::AbsoluteRotation) { - defaultAbsPose.rot = animVars.lookup(jointVar.var, defaultAbsPose.rot); + defaultAbsPose.rot = animVars.lookupRigToGeometry(jointVar.var, defaultAbsPose.rot); } else if (jointVar.type == JointVar::Type::AbsolutePosition) { - defaultAbsPose.trans = animVars.lookup(jointVar.var, defaultAbsPose.trans); + defaultAbsPose.trans = animVars.lookupRigToGeometry(jointVar.var, defaultAbsPose.trans); } // because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose. @@ -123,9 +123,9 @@ AnimPose AnimManipulator::computeRelativePoseFromJointVar(const AnimVariantMap& // override the default rel pose AnimPose relPose = defaultRelPose; if (jointVar.type == JointVar::Type::RelativeRotation) { - relPose.rot = animVars.lookup(jointVar.var, defaultRelPose.rot); + relPose.rot = animVars.lookupRigToGeometry(jointVar.var, defaultRelPose.rot); } else if (jointVar.type == JointVar::Type::RelativePosition) { - relPose.trans = animVars.lookup(jointVar.var, defaultRelPose.trans); + relPose.trans = animVars.lookupRigToGeometry(jointVar.var, defaultRelPose.trans); } return relPose; diff --git a/libraries/animation/src/AnimPose.cpp b/libraries/animation/src/AnimPose.cpp index 1fe1e21ba8..5914031a3a 100644 --- a/libraries/animation/src/AnimPose.cpp +++ b/libraries/animation/src/AnimPose.cpp @@ -10,7 +10,6 @@ #include "AnimPose.h" #include -#include #include const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f), @@ -19,14 +18,7 @@ const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f), AnimPose::AnimPose(const glm::mat4& mat) { scale = extractScale(mat); - float maxScale = std::max(std::max(scale.x, scale.y), scale.z); - if (maxScale > 1.01f || maxScale <= 0.99f) { - // quat_cast doesn't work so well with scaled matrices, so cancel it out. - mat4 tmp = glm::scale(mat, 1.0f / scale); - rot = glm::normalize(glm::quat_cast(tmp)); - } else { - rot = glm::normalize(glm::quat_cast(mat)); - } + rot = glmExtractRotation(mat); trans = extractTranslation(mat); } diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index 234e9cef09..118d2e8ce9 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -43,7 +43,7 @@ QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine, target.setProperty(name, quatToScriptValue(engine, value.getQuat())); break; default: - // Note that we don't do mat4 in Javascript currently, and there's not yet a reason to start now. + // Unknown type assert(QString("AnimVariant::Type") == QString("valid")); } }; diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index 0d7c657058..0cd7fb29ac 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -18,8 +18,9 @@ #include #include #include +#include +#include #include "AnimationLogging.h" -#include "StreamUtils.h" class AnimVariant { public: @@ -29,7 +30,6 @@ public: Float, Vec3, Quat, - Mat4, String, NumTypes }; @@ -40,7 +40,6 @@ public: AnimVariant(float value) : _type(Type::Float) { _val.floats[0] = value; } AnimVariant(const glm::vec3& value) : _type(Type::Vec3) { *reinterpret_cast(&_val) = value; } AnimVariant(const glm::quat& value) : _type(Type::Quat) { *reinterpret_cast(&_val) = value; } - AnimVariant(const glm::mat4& value) : _type(Type::Mat4) { *reinterpret_cast(&_val) = value; } AnimVariant(const QString& value) : _type(Type::String) { _stringVal = value; } bool isBool() const { return _type == Type::Bool; } @@ -48,7 +47,6 @@ public: bool isFloat() const { return _type == Type::Float; } bool isVec3() const { return _type == Type::Vec3; } bool isQuat() const { return _type == Type::Quat; } - bool isMat4() const { return _type == Type::Mat4; } bool isString() const { return _type == Type::String; } Type getType() const { return _type; } @@ -57,7 +55,6 @@ public: void setFloat(float value) { assert(_type == Type::Float); _val.floats[0] = value; } void setVec3(const glm::vec3& value) { assert(_type == Type::Vec3); *reinterpret_cast(&_val) = value; } void setQuat(const glm::quat& value) { assert(_type == Type::Quat); *reinterpret_cast(&_val) = value; } - void setMat4(const glm::mat4& value) { assert(_type == Type::Mat4); *reinterpret_cast(&_val) = value; } void setString(const QString& value) { assert(_type == Type::String); _stringVal = value; } bool getBool() const { assert(_type == Type::Bool); return _val.boolVal; } @@ -66,7 +63,6 @@ public: const glm::vec3& getVec3() const { assert(_type == Type::Vec3); return *reinterpret_cast(&_val); } const glm::quat& getQuat() const { assert(_type == Type::Quat); return *reinterpret_cast(&_val); } - const glm::mat4& getMat4() const { assert(_type == Type::Mat4); return *reinterpret_cast(&_val); } const QString& getString() const { assert(_type == Type::String); return _stringVal; } protected: @@ -112,7 +108,7 @@ public: } } - const glm::vec3& lookup(const QString& key, const glm::vec3& defaultValue) const { + const glm::vec3& lookupRaw(const QString& key, const glm::vec3& defaultValue) const { if (key.isEmpty()) { return defaultValue; } else { @@ -121,7 +117,16 @@ public: } } - const glm::quat& lookup(const QString& key, const glm::quat& defaultValue) const { + glm::vec3 lookupRigToGeometry(const QString& key, const glm::vec3& defaultValue) const { + if (key.isEmpty()) { + return defaultValue; + } else { + auto iter = _map.find(key); + return iter != _map.end() ? transformPoint(_rigToGeometryMat, iter->second.getVec3()) : defaultValue; + } + } + + const glm::quat& lookupRaw(const QString& key, const glm::quat& defaultValue) const { if (key.isEmpty()) { return defaultValue; } else { @@ -130,12 +135,12 @@ public: } } - const glm::mat4& lookup(const QString& key, const glm::mat4& defaultValue) const { + glm::quat lookupRigToGeometry(const QString& key, const glm::quat& defaultValue) const { if (key.isEmpty()) { return defaultValue; } else { auto iter = _map.find(key); - return iter != _map.end() ? iter->second.getMat4() : defaultValue; + return iter != _map.end() ? _rigToGeometryRot * iter->second.getQuat() : defaultValue; } } @@ -153,13 +158,17 @@ public: void set(const QString& key, float value) { _map[key] = AnimVariant(value); } void set(const QString& key, const glm::vec3& value) { _map[key] = AnimVariant(value); } void set(const QString& key, const glm::quat& value) { _map[key] = AnimVariant(value); } - void set(const QString& key, const glm::mat4& value) { _map[key] = AnimVariant(value); } void set(const QString& key, const QString& value) { _map[key] = AnimVariant(value); } void unset(const QString& key) { _map.erase(key); } void setTrigger(const QString& key) { _triggers.insert(key); } void clearTriggers() { _triggers.clear(); } + void setRigToGeometryTransform(const glm::mat4& rigToGeometry) { + _rigToGeometryMat = rigToGeometry; + _rigToGeometryRot = glmExtractRotation(rigToGeometry); + } + void clearMap() { _map.clear(); } bool hasKey(const QString& key) const { return _map.find(key) != _map.end(); } @@ -189,9 +198,6 @@ public: case AnimVariant::Type::Quat: qCDebug(animation) << " " << pair.first << "=" << pair.second.getQuat(); break; - case AnimVariant::Type::Mat4: - qCDebug(animation) << " " << pair.first << "=" << pair.second.getMat4(); - break; case AnimVariant::Type::String: qCDebug(animation) << " " << pair.first << "=" << pair.second.getString(); break; @@ -205,6 +211,8 @@ public: protected: std::map _map; std::set _triggers; + glm::mat4 _rigToGeometryMat; + glm::quat _rigToGeometryRot; }; typedef std::function AnimVariantResultHandler; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 2f2b1309ba..2442c0b8b4 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -236,12 +236,17 @@ int Rig::getJointStateCount() const { return _relativePoses.size(); } -int Rig::indexOfJoint(const QString& jointName) { +int Rig::indexOfJoint(const QString& jointName) const { return _animSkeleton->nameToJointIndex(jointName); } void Rig::setModelOffset(const glm::mat4& modelOffset) { _modelOffset = AnimPose(modelOffset); + + // compute geometryToAvatarTransforms + glm::quat yFlip180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + _geometryToRigTransform = AnimPose(glm::vec3(1), yFlip180, glm::vec3()) * _modelOffset * _geometryOffset; + _rigToGeometryTransform = glm::inverse(_geometryToRigTransform); } bool Rig::getJointStateRotation(int index, glm::quat& rotation) const { @@ -322,9 +327,9 @@ void Rig::restoreJointTranslation(int index, float fraction, float priority) { // AJT: NOTE old code did not have 180 flip! bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, glm::vec3 translation, glm::quat rotation) const { - glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); if (jointIndex >= 0 && jointIndex < (int)_absolutePoses.size()) { - position = (rotation * yFlip * _absolutePoses[jointIndex].trans) + translation; + glm::quat yFlip180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + position = (rotation * yFlip180 * _absolutePoses[jointIndex].trans) + translation; return true; } else { return false; @@ -333,9 +338,9 @@ bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, glm: // AJT: NOTE old code did not have 180 flip! bool Rig::getJointPosition(int jointIndex, glm::vec3& position) const { - glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); if (jointIndex >= 0 && jointIndex < (int)_absolutePoses.size()) { - position = yFlip * _absolutePoses[jointIndex].trans; + glm::quat yFlip180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + position = yFlip180 * _absolutePoses[jointIndex].trans; return true; } else { return false; @@ -419,6 +424,14 @@ void Rig::computeEyesInRootFrame(const AnimPoseVec& poses) { } } +AnimPose Rig::getAbsoluteDefaultPose(int index) const { + if (_animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints()) { + return AnimPose(_geometryToRigTransform) * _animSkeleton->getAbsoluteDefaultPose(index); + } else { + return AnimPose::identity; + } +} + // animation reference speeds. static const std::vector FORWARD_SPEEDS = { 0.4f, 1.4f, 4.5f }; // m/s static const std::vector BACKWARD_SPEEDS = { 0.6f, 1.45f }; // m/s @@ -682,13 +695,14 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) { if (_animNode) { updateAnimationStateHandlers(); + _animVars.setRigToGeometryTransform(_rigToGeometryTransform); // evaluate the animation AnimNode::Triggers triggersOut; _relativePoses = _animNode->evaluate(_animVars, deltaTime, triggersOut); if ((int)_relativePoses.size() != _animSkeleton->getNumJoints()) { // animations haven't fully loaded yet. - _relativePoses = _animSkeleton->getRelativeBindPoses(); + _relativePoses = _animSkeleton->getRelativeDefaultPoses(); } _animVars.clearTriggers(); for (auto& trigger : triggersOut) { @@ -781,27 +795,23 @@ void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, floa } } -static void computeHeadNeckAnimVars(AnimSkeleton::ConstPointer skeleton, const AnimPose& geometryHMDPose, - glm::vec3& headPositionOut, glm::quat& headOrientationOut, - glm::vec3& neckPositionOut, glm::quat& neckOrientationOut) { +void Rig::computeHeadNeckAnimVars(const AnimPose& hmdPose, glm::vec3& headPositionOut, glm::quat& headOrientationOut, + glm::vec3& neckPositionOut, glm::quat& neckOrientationOut) const { - // the input hmd values are in avatar space - // we need to transform them into bone space. - AnimPose hmdPose = geometryHMDPose; + // the input hmd values are in avatar/rig space const glm::vec3 hmdPosition = hmdPose.trans; const glm::quat hmdOrientation = hmdPose.rot; // TODO: cache jointIndices - int rightEyeIndex = skeleton->nameToJointIndex("RightEye"); - int leftEyeIndex = skeleton->nameToJointIndex("LeftEye"); - int headIndex = skeleton->nameToJointIndex("Head"); - int neckIndex = skeleton->nameToJointIndex("Neck"); + int rightEyeIndex = indexOfJoint("RightEye"); + int leftEyeIndex = indexOfJoint("LeftEye"); + int headIndex = indexOfJoint("Head"); + int neckIndex = indexOfJoint("Neck"); - // Use absolute bindPose positions just in case the relBindPose have rotations we don't expect. - glm::vec3 absRightEyePos = rightEyeIndex != -1 ? skeleton->getAbsoluteBindPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS; - glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? skeleton->getAbsoluteBindPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS; - glm::vec3 absHeadPos = headIndex != -1 ? skeleton->getAbsoluteBindPose(headIndex).trans : DEFAULT_HEAD_POS; - glm::vec3 absNeckPos = neckIndex != -1 ? skeleton->getAbsoluteBindPose(neckIndex).trans : DEFAULT_NECK_POS; + glm::vec3 absRightEyePos = rightEyeIndex != -1 ? getAbsoluteDefaultPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS; + glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? getAbsoluteDefaultPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS; + glm::vec3 absHeadPos = headIndex != -1 ? getAbsoluteDefaultPose(headIndex).trans : DEFAULT_HEAD_POS; + glm::vec3 absNeckPos = neckIndex != -1 ? getAbsoluteDefaultPose(neckIndex).trans : DEFAULT_NECK_POS; glm::vec3 absCenterEyePos = (absRightEyePos + absLeftEyePos) / 2.0f; glm::vec3 eyeOffset = absCenterEyePos - absHeadPos; @@ -816,18 +826,19 @@ static void computeHeadNeckAnimVars(AnimSkeleton::ConstPointer skeleton, const A // neck neckPositionOut = hmdPosition - hmdOrientation * (headOffset + eyeOffset); - // slerp between bind orientation and hmdOrientation - neckOrientationOut = safeMix(hmdOrientation, skeleton->getRelativeBindPose(skeleton->nameToJointIndex("Neck")).rot, 0.5f); + // slerp between default orientation and hmdOrientation + neckOrientationOut = safeMix(hmdOrientation, _animSkeleton->getRelativeDefaultPose(neckIndex).rot, 0.5f); } void Rig::updateNeckJoint(int index, const HeadParameters& params) { if (_animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints()) { + glm::quat yFlip180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); if (params.isInHMD) { glm::vec3 headPos, neckPos; glm::quat headRot, neckRot; - AnimPose hmdPose(glm::vec3(1.0f), avatarToGeometryNegZForward(params.localHeadOrientation), avatarToGeometry(params.localHeadPosition)); - computeHeadNeckAnimVars(_animSkeleton, hmdPose, headPos, headRot, neckPos, neckRot); + AnimPose hmdPose(glm::vec3(1.0f), params.localHeadOrientation * yFlip180, params.localHeadPosition); + computeHeadNeckAnimVars(hmdPose, headPos, headRot, neckPos, neckRot); // debug rendering #ifdef DEBUG_RENDERING @@ -852,7 +863,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) { } else { _animVars.unset("headPosition"); - _animVars.set("headRotation", avatarToGeometryNegZForward(params.localHeadOrientation)); + _animVars.set("headRotation", params.localHeadOrientation * yFlip180); _animVars.set("headAndNeckType", (int)IKTarget::Type::RotationOnly); _animVars.set("headType", (int)IKTarget::Type::RotationOnly); _animVars.unset("neckPosition"); @@ -886,31 +897,12 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm */ } -glm::vec3 Rig::avatarToGeometry(const glm::vec3& pos) const { - glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - AnimPose geometryToAvatarTransform = AnimPose(glm::vec3(1), yFlip, glm::vec3()) * _modelOffset * _geometryOffset; - glm::vec3 result = geometryToAvatarTransform.inverse() * pos; - return result; -} - -glm::quat Rig::avatarToGeometryNegZForward(const glm::quat& quat) const { - AnimPose yFlip(glm::vec3(1), glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)), glm::vec3()); - AnimPose geometryToAvatarTransform = yFlip * _modelOffset * _geometryOffset; - return (geometryToAvatarTransform.inverse() * AnimPose(glm::vec3(1), quat, glm::vec3()) * yFlip).rot; -} - -glm::quat Rig::avatarToGeometryZForward(const glm::quat& quat) const { - AnimPose yFlip(glm::vec3(1), glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)), glm::vec3()); - AnimPose geometryToAvatarTransform = yFlip * _modelOffset * _geometryOffset; - return (geometryToAvatarTransform.inverse() * AnimPose(glm::vec3(1), quat, glm::vec3())).rot; -} - void Rig::updateFromHandParameters(const HandParameters& params, float dt) { if (_animSkeleton && _animNode) { if (params.isLeftEnabled) { - _animVars.set("leftHandPosition", avatarToGeometry(params.leftPosition)); - _animVars.set("leftHandRotation", avatarToGeometryZForward(params.leftOrientation)); + _animVars.set("leftHandPosition", params.leftPosition); + _animVars.set("leftHandRotation", params.leftOrientation); _animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition); } else { _animVars.unset("leftHandPosition"); @@ -918,8 +910,8 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) { _animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); } if (params.isRightEnabled) { - _animVars.set("rightHandPosition", avatarToGeometry(params.rightPosition)); - _animVars.set("rightHandRotation", avatarToGeometryZForward(params.rightOrientation)); + _animVars.set("rightHandPosition", params.rightPosition); + _animVars.set("rightHandRotation", params.rightOrientation); _animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition); } else { _animVars.unset("rightHandPosition"); @@ -986,7 +978,7 @@ void Rig::initAnimGraph(const QUrl& url) { bool Rig::getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const { if (_animSkeleton && _rootJointIndex >= 0) { - modelRegistrationPointOut = _geometryOffset * -_animSkeleton->getAbsoluteBindPose(_rootJointIndex).trans; + modelRegistrationPointOut = _geometryOffset * -_animSkeleton->getAbsoluteDefaultPose(_rootJointIndex).trans; return true; } else { return false; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 35d9e5747a..6d5ce26df1 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -85,10 +85,9 @@ public: void reset(const FBXGeometry& geometry); bool jointStatesEmpty(); int getJointStateCount() const; - int indexOfJoint(const QString& jointName); + int indexOfJoint(const QString& jointName) const; void setModelOffset(const glm::mat4& modelOffset); - const AnimPose& getGeometryOffset() const { return _geometryOffset; } bool getJointStateRotation(int index, glm::quat& rotation) const; bool getJointStateTranslation(int index, glm::vec3& translation) const; @@ -146,6 +145,8 @@ public: const glm::vec3& getEyesInRootFrame() const { return _eyesInRootFrame; } + AnimPose getAbsoluteDefaultPose(int index) const; // avatar space + void copyJointsIntoJointData(QVector& jointDataVec) const; void copyJointsFromJointData(const QVector& jointDataVec); @@ -156,15 +157,13 @@ public: void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist); void updateNeckJoint(int index, const HeadParameters& params); + void computeHeadNeckAnimVars(const AnimPose& hmdPose, glm::vec3& headPositionOut, glm::quat& headOrientationOut, + glm::vec3& neckPositionOut, glm::quat& neckOrientationOut) const; void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade); void calcAnimAlpha(float speed, const std::vector& referenceSpeeds, float* alphaOut) const; void computeEyesInRootFrame(const AnimPoseVec& poses); - glm::vec3 avatarToGeometry(const glm::vec3& pos) const; - glm::quat avatarToGeometryZForward(const glm::quat& quat) const; - glm::quat avatarToGeometryNegZForward(const glm::quat& quat) const; - AnimPose _modelOffset; // model to avatar space (without 180 flip) AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets) AnimPoseVec _relativePoses; // geometry space relative to parent. @@ -172,6 +171,9 @@ public: AnimPoseVec _overridePoses; // geometry space relative to parent. std::vector _overrideFlags; + glm::mat4 _geometryToRigTransform; + glm::mat4 _rigToGeometryTransform; + int _rootJointIndex { -1 }; int _leftHandJointIndex { -1 }; diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index fa010a85bd..2199fefbce 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -10,7 +10,7 @@ // #include "GLMHelpers.h" - +#include #include "NumericalConstants.h" const vec3 Vectors::UNIT_X{ 1.0f, 0.0f, 0.0f }; @@ -276,6 +276,18 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { 0.5f * sqrtf(z2) * (upper[0][1] >= upper[1][0] ? 1.0f : -1.0f))); } +glm::quat glmExtractRotation(const glm::mat4& matrix) { + glm::vec3 scale = extractScale(matrix); + float maxScale = std::max(std::max(scale.x, scale.y), scale.z); + if (maxScale > 1.01f || maxScale <= 0.99f) { + // quat_cast doesn't work so well with scaled matrices, so cancel it out. + glm::mat4 tmp = glm::scale(matrix, 1.0f / scale); + return glm::normalize(glm::quat_cast(tmp)); + } else { + return glm::normalize(glm::quat_cast(matrix)); + } +} + glm::vec3 extractScale(const glm::mat4& matrix) { return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2])); } diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 8d3410aaf2..54d422e465 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -131,6 +131,7 @@ glm::vec3 extractTranslation(const glm::mat4& matrix); void setTranslation(glm::mat4& matrix, const glm::vec3& translation); glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal = false); +glm::quat glmExtractRotation(const glm::mat4& matrix); glm::vec3 extractScale(const glm::mat4& matrix);