From 217145f4c562c78785715d8068cd9179cd162b93 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 22 Feb 2019 17:16:50 -0800 Subject: [PATCH 1/3] This pr addresses two issues related to avatars that have parents joints above their hip joints. First on the IK side this prevents parent joints from being included in the accumulators in AnimInverseKinematics. Second in AnimClip the boneLengthScale now takes into account translation and scale on these extra parent joints. --- libraries/animation/src/AnimClip.cpp | 41 ++++++++++++++++++- .../animation/src/AnimInverseKinematics.cpp | 6 +-- libraries/animation/src/AnimSkeleton.cpp | 3 ++ libraries/animation/src/AnimSkeleton.h | 2 + 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index a35e0237d0..109be27b58 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -151,12 +151,49 @@ void AnimClip::copyFromNetworkAnim() { const glm::vec3& animZeroTrans = animModel.animationFrames[0].translations[animJointIndex]; float boneLengthScale = 1.0f; const float EPSILON = 0.0001f; - if (fabsf(glm::length(animZeroTrans)) > EPSILON) { - boneLengthScale = glm::length(avatarDefaultPose.trans()) / glm::length(animZeroTrans); + + const int avatarHipsParentIndex = avatarSkeleton->getParentIndex(avatarSkeleton->nameToJointIndex("Hips")); + if (avatarJointIndex == avatarSkeleton->nameToJointIndex("Hips") && (avatarHipsParentIndex >= 0)) { + + const AnimPose& animHipsAbsoluteDefaultPose = animSkeleton.getAbsoluteDefaultPose(animSkeleton.nameToJointIndex("Hips")); + const AnimPose& avatarHipsAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarSkeleton->nameToJointIndex("Hips")); + const AnimPose& avatarHipsParentAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarHipsParentIndex); + + // the get the units and the heights for the animation and the avatar + const float animationUnitScale = extractScale(animModel.offset).y; + const float avatarUnitScale = extractScale(avatarSkeleton->getGeometryOffset()).y; + const float avatarHeightInMeters = avatarUnitScale * avatarHipsAbsoluteDefaultPose.trans().y; + const float animHeightInMeters = animationUnitScale * animHipsAbsoluteDefaultPose.trans().y; + + // get the parent scales for the avatar and the animation + const float avatarHipsParentScale = avatarHipsParentAbsoluteDefaultPose.scale().y; + float animHipsParentScale = 1.0f; + const int animHipsParentIndex = animSkeleton.getParentIndex(animSkeleton.nameToJointIndex("Hips")); + // also, check to see if the animation hips have a scaled parent. + if (animHipsParentIndex >= 0) { + const AnimPose& animationHipsParentAbsoluteDefaultPose = animSkeleton.getAbsoluteDefaultPose(animHipsParentIndex); + animHipsParentScale = animationHipsParentAbsoluteDefaultPose.scale().y; + } + + // compute the ratios for the units, the heights in meters, and the parent scales + if ((fabsf(animHeightInMeters) > EPSILON) && (animationUnitScale > EPSILON) && (animHipsParentScale > EPSILON)) { + const float avatarToAnimationHeightRatio = avatarHeightInMeters / animHeightInMeters; + const float unitsRatio = 1.0f / (avatarUnitScale / animationUnitScale); + const float parentScaleRatio = 1.0f / (avatarHipsParentScale / animHipsParentScale); + + boneLengthScale = avatarToAnimationHeightRatio * unitsRatio * parentScaleRatio; + } + } else { + + if (fabsf(glm::length(animZeroTrans)) > EPSILON) { + boneLengthScale = glm::length(avatarDefaultPose.trans()) / glm::length(animZeroTrans); + } } + AnimPose animTransPose = AnimPose(glm::vec3(1.0f), glm::quat(), avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans)); _anim[frame][avatarJointIndex] = animTransPose * animPreRotPose * animRotPose * animPostRotPose; + } } } diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index d710e9d8ff..8da2ddde3e 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -298,10 +298,8 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector< } // harvest accumulated rotations and apply the average - for (int i = 0; i < (int)_relativePoses.size(); ++i) { - if (i == _hipsIndex) { - continue; // don't apply accumulators to hips - } + // don't apply accumulators to hips, or parents of hips + for (int i = (_hipsIndex+1); i < (int)_relativePoses.size(); ++i) { if (_rotationAccumulators[i].size() > 0) { _relativePoses[i].rot() = _rotationAccumulators[i].getAverage(); _rotationAccumulators[i].clear(); diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index 03e3ac6ebd..f7b5fa8c83 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -17,6 +17,9 @@ #include "AnimationLogging.h" AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) { + + _geometryOffset = hfmModel.offset; + // convert to std::vector of joints std::vector joints; joints.reserve(hfmModel.joints.size()); diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index 0eefbf973e..dcb35ac9cb 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -36,6 +36,7 @@ public: const AnimPoseVec& getRelativeDefaultPoses() const { return _relativeDefaultPoses; } const AnimPose& getAbsoluteDefaultPose(int jointIndex) const; const AnimPoseVec& getAbsoluteDefaultPoses() const { return _absoluteDefaultPoses; } + const glm::mat4& getGeometryOffset() const { return _geometryOffset; } // get pre transform which should include FBX pre potations const AnimPose& getPreRotationPose(int jointIndex) const; @@ -83,6 +84,7 @@ protected: std::vector _mirrorMap; QHash _jointIndicesByName; std::vector> _clusterBindMatrixOriginalValues; + glm::mat4 _geometryOffset; // no copies AnimSkeleton(const AnimSkeleton&) = delete; From 54f14b2772b9abc8fbdf54dbe77801a83330d97b Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 1 Mar 2019 12:41:05 -0800 Subject: [PATCH 2/3] added the case where my avatar has no parent of hips, but the animation does --- libraries/animation/src/AnimClip.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index 109be27b58..da5e9b6508 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -153,11 +153,11 @@ void AnimClip::copyFromNetworkAnim() { const float EPSILON = 0.0001f; const int avatarHipsParentIndex = avatarSkeleton->getParentIndex(avatarSkeleton->nameToJointIndex("Hips")); - if (avatarJointIndex == avatarSkeleton->nameToJointIndex("Hips") && (avatarHipsParentIndex >= 0)) { + const int animHipsParentIndex = animSkeleton.getParentIndex(animSkeleton.nameToJointIndex("Hips")); + if (avatarJointIndex == avatarSkeleton->nameToJointIndex("Hips") && (avatarHipsParentIndex >= 0) || (animHipsParentIndex >= 0)) { const AnimPose& animHipsAbsoluteDefaultPose = animSkeleton.getAbsoluteDefaultPose(animSkeleton.nameToJointIndex("Hips")); const AnimPose& avatarHipsAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarSkeleton->nameToJointIndex("Hips")); - const AnimPose& avatarHipsParentAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarHipsParentIndex); // the get the units and the heights for the animation and the avatar const float animationUnitScale = extractScale(animModel.offset).y; @@ -166,10 +166,12 @@ void AnimClip::copyFromNetworkAnim() { const float animHeightInMeters = animationUnitScale * animHipsAbsoluteDefaultPose.trans().y; // get the parent scales for the avatar and the animation - const float avatarHipsParentScale = avatarHipsParentAbsoluteDefaultPose.scale().y; + float avatarHipsParentScale = 1.0f; float animHipsParentScale = 1.0f; - const int animHipsParentIndex = animSkeleton.getParentIndex(animSkeleton.nameToJointIndex("Hips")); - // also, check to see if the animation hips have a scaled parent. + if (avatarHipsParentIndex >= 0) { + const AnimPose& avatarHipsParentAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarHipsParentIndex); + avatarHipsParentScale = avatarHipsParentAbsoluteDefaultPose.scale().y; + } if (animHipsParentIndex >= 0) { const AnimPose& animationHipsParentAbsoluteDefaultPose = animSkeleton.getAbsoluteDefaultPose(animHipsParentIndex); animHipsParentScale = animationHipsParentAbsoluteDefaultPose.scale().y; From c046b8ffd35c5aaffd953999eca5c3828d97b2c5 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 1 Mar 2019 15:12:37 -0800 Subject: [PATCH 3/3] made is so the boneLengthScale is only computed once per animation clip --- libraries/animation/src/AnimClip.cpp | 80 +++++++++++++--------------- 1 file changed, 36 insertions(+), 44 deletions(-) diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index 9b87d058fd..4fe02e9307 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -123,6 +123,42 @@ void AnimClip::copyFromNetworkAnim() { const int animFrameCount = animModel.animationFrames.size(); _anim.resize(animFrameCount); + // find the size scale factor for translation in the animation. + const int avatarHipsParentIndex = avatarSkeleton->getParentIndex(avatarSkeleton->nameToJointIndex("Hips")); + const int animHipsParentIndex = animSkeleton.getParentIndex(animSkeleton.nameToJointIndex("Hips")); + const AnimPose& avatarHipsAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarSkeleton->nameToJointIndex("Hips")); + const AnimPose& animHipsAbsoluteDefaultPose = animSkeleton.getAbsoluteDefaultPose(animSkeleton.nameToJointIndex("Hips")); + + // the get the units and the heights for the animation and the avatar + const float avatarUnitScale = extractScale(avatarSkeleton->getGeometryOffset()).y; + const float animationUnitScale = extractScale(animModel.offset).y; + const float avatarHeightInMeters = avatarUnitScale * avatarHipsAbsoluteDefaultPose.trans().y; + const float animHeightInMeters = animationUnitScale * animHipsAbsoluteDefaultPose.trans().y; + + // get the parent scales for the avatar and the animation + float avatarHipsParentScale = 1.0f; + if (avatarHipsParentIndex >= 0) { + const AnimPose& avatarHipsParentAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarHipsParentIndex); + avatarHipsParentScale = avatarHipsParentAbsoluteDefaultPose.scale().y; + } + float animHipsParentScale = 1.0f; + if (animHipsParentIndex >= 0) { + const AnimPose& animationHipsParentAbsoluteDefaultPose = animSkeleton.getAbsoluteDefaultPose(animHipsParentIndex); + animHipsParentScale = animationHipsParentAbsoluteDefaultPose.scale().y; + } + + const float EPSILON = 0.0001f; + float boneLengthScale = 1.0f; + // compute the ratios for the units, the heights in meters, and the parent scales + if ((fabsf(animHeightInMeters) > EPSILON) && (animationUnitScale > EPSILON) && (animHipsParentScale > EPSILON)) { + const float avatarToAnimationHeightRatio = avatarHeightInMeters / animHeightInMeters; + const float unitsRatio = 1.0f / (avatarUnitScale / animationUnitScale); + const float parentScaleRatio = 1.0f / (avatarHipsParentScale / animHipsParentScale); + + boneLengthScale = avatarToAnimationHeightRatio * unitsRatio * parentScaleRatio; + } + + for (int frame = 0; frame < animFrameCount; frame++) { const HFMAnimationFrame& animFrame = animModel.animationFrames[frame]; @@ -162,7 +198,6 @@ void AnimClip::copyFromNetworkAnim() { avatarSkeleton->convertAbsoluteRotationsToRelative(avatarRotations); _anim[frame].reserve(avatarJointCount); - for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) { const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex); @@ -177,49 +212,6 @@ void AnimClip::copyFromNetworkAnim() { // retarget translation from animation to avatar const glm::vec3& animZeroTrans = animModel.animationFrames[0].translations[animJointIndex]; - float boneLengthScale = 1.0f; - const float EPSILON = 0.0001f; - - const int avatarHipsParentIndex = avatarSkeleton->getParentIndex(avatarSkeleton->nameToJointIndex("Hips")); - const int animHipsParentIndex = animSkeleton.getParentIndex(animSkeleton.nameToJointIndex("Hips")); - if (avatarJointIndex == avatarSkeleton->nameToJointIndex("Hips") && (avatarHipsParentIndex >= 0) || (animHipsParentIndex >= 0)) { - - const AnimPose& animHipsAbsoluteDefaultPose = animSkeleton.getAbsoluteDefaultPose(animSkeleton.nameToJointIndex("Hips")); - const AnimPose& avatarHipsAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarSkeleton->nameToJointIndex("Hips")); - - // the get the units and the heights for the animation and the avatar - const float animationUnitScale = extractScale(animModel.offset).y; - const float avatarUnitScale = extractScale(avatarSkeleton->getGeometryOffset()).y; - const float avatarHeightInMeters = avatarUnitScale * avatarHipsAbsoluteDefaultPose.trans().y; - const float animHeightInMeters = animationUnitScale * animHipsAbsoluteDefaultPose.trans().y; - - // get the parent scales for the avatar and the animation - float avatarHipsParentScale = 1.0f; - float animHipsParentScale = 1.0f; - if (avatarHipsParentIndex >= 0) { - const AnimPose& avatarHipsParentAbsoluteDefaultPose = avatarSkeleton->getAbsoluteDefaultPose(avatarHipsParentIndex); - avatarHipsParentScale = avatarHipsParentAbsoluteDefaultPose.scale().y; - } - if (animHipsParentIndex >= 0) { - const AnimPose& animationHipsParentAbsoluteDefaultPose = animSkeleton.getAbsoluteDefaultPose(animHipsParentIndex); - animHipsParentScale = animationHipsParentAbsoluteDefaultPose.scale().y; - } - - // compute the ratios for the units, the heights in meters, and the parent scales - if ((fabsf(animHeightInMeters) > EPSILON) && (animationUnitScale > EPSILON) && (animHipsParentScale > EPSILON)) { - const float avatarToAnimationHeightRatio = avatarHeightInMeters / animHeightInMeters; - const float unitsRatio = 1.0f / (avatarUnitScale / animationUnitScale); - const float parentScaleRatio = 1.0f / (avatarHipsParentScale / animHipsParentScale); - - boneLengthScale = avatarToAnimationHeightRatio * unitsRatio * parentScaleRatio; - } - } else { - - if (fabsf(glm::length(animZeroTrans)) > EPSILON) { - boneLengthScale = glm::length(avatarDefaultPose.trans()) / glm::length(animZeroTrans); - } - } - relativeTranslation = avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans); } else { // This joint is NOT in the animation at all.