From 559367db4a138ba789493ec3a47f0e0b01c7da3f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 4 Aug 2015 16:03:08 -0700 Subject: [PATCH] Got to the bottom of the bind pose question. When TRUST_BIND_TRANSFORM is defined in AnimSkeleton, the bind pose is taken from the FBXJoint::bindTransform field, which is correct for all joints bound to actual geometry. Basically it's not trust worthy for bones NOT bound to anything. When TRUST_BIND_TRANSFORM is not defined, the bind pose is taken from the other FBXJoint fields. Unfortunatly these poses are NOT the bind pose, but instead are taken from the FBX files 'resting' pose. i.e. frame 0. --- interface/src/avatar/MyAvatar.cpp | 2 +- libraries/animation/src/AnimClip.cpp | 6 +-- libraries/animation/src/AnimSkeleton.cpp | 45 +++++++++++++++----- libraries/render-utils/src/AnimDebugDraw.cpp | 22 +++++----- 4 files changed, 49 insertions(+), 26 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 99b634dec1..88f8a64830 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1221,7 +1221,7 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { joints.push_back(joint); } auto skeleton = make_shared(joints); - AnimPose xform(glm::vec3(1.0f), glm::quat(), glm::vec3(0.0)); + AnimPose xform(_skeletonModel.getScale(), glm::quat(), _skeletonModel.getOffset()); AnimDebugDraw::getInstance().addSkeleton("my-avatar", skeleton, xform); _animNode = make_shared("clip", "https://hifi-public.s3.amazonaws.com/ozan/support/FightClubBotTest1/Animations/standard_idle.fbx", 0.0f, 90.0f, 1.0f, true); diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index dbb241d484..9f97602ed1 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -138,10 +138,10 @@ void AnimClip::copyFromNetworkAnim() { _anim.resize(frameCount); for (int i = 0; i < frameCount; i++) { - // init all joints in animation to identity + // init all joints in animation to bind pose _anim[i].reserve(skeletonJointCount); for (int j = 0; j < skeletonJointCount; j++) { - _anim[i].push_back(AnimPose::identity); + _anim[i].push_back(_skeleton->getRelativeBindPose(j)); } // init over all joint animations @@ -149,7 +149,7 @@ void AnimClip::copyFromNetworkAnim() { int k = jointMap[j]; if (k >= 0 && k < skeletonJointCount) { // currently FBX animations only have rotation. - _anim[i][k].rot = geom.animationFrames[i].rotations[j]; + _anim[i][k].rot = _skeleton->getRelativeBindPose(j).rot * geom.animationFrames[i].rotations[j]; } } } diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index feaa1828ce..27556c6930 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -10,6 +10,8 @@ #include "AnimSkeleton.h" #include "AnimationLogging.h" #include "glmHelpers.h" +#include +#include const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f), glm::quat(), @@ -17,7 +19,7 @@ const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f), AnimPose::AnimPose(const glm::mat4& mat) { scale = extractScale(mat); - rot = glm::normalize(glm::quat_cast(mat)); + rot = extractRotation(mat); trans = extractTranslation(mat); } @@ -41,6 +43,7 @@ AnimPose::operator glm::mat4() const { glm::vec4(zAxis, 0.0f), glm::vec4(trans, 1.0f)); } +//#define TRUST_BIND_TRANSFORM AnimSkeleton::AnimSkeleton(const std::vector& joints) { _joints = joints; @@ -50,9 +53,31 @@ AnimSkeleton::AnimSkeleton(const std::vector& joints) { _relativeBindPoses.reserve(joints.size()); for (size_t i = 0; i < joints.size(); i++) { + /* + // AJT: dump the skeleton, because wtf. + qCDebug(animation) << getJointName(i); + qCDebug(animation) << " isFree =" << _joints[i].isFree; + qCDebug(animation) << " freeLineage =" << _joints[i].freeLineage; + qCDebug(animation) << " parentIndex =" << _joints[i].parentIndex; + qCDebug(animation) << " boneRadius =" << _joints[i].boneRadius; + qCDebug(animation) << " translation =" << _joints[i].translation; + qCDebug(animation) << " preTransform =" << _joints[i].preTransform; + qCDebug(animation) << " preRotation =" << _joints[i].preRotation; + qCDebug(animation) << " rotation =" << _joints[i].rotation; + qCDebug(animation) << " postRotation =" << _joints[i].postRotation; + qCDebug(animation) << " postTransform =" << _joints[i].postTransform; + qCDebug(animation) << " transform =" << _joints[i].transform; + qCDebug(animation) << " rotationMin =" << _joints[i].rotationMin << ", rotationMax =" << _joints[i].rotationMax; + qCDebug(animation) << " inverseDefaultRotation" << _joints[i].inverseDefaultRotation; + qCDebug(animation) << " inverseBindRotation" << _joints[i].inverseBindRotation; + qCDebug(animation) << " bindTransform" << _joints[i].bindTransform; + qCDebug(animation) << " isSkeletonJoint" << _joints[i].isSkeletonJoint; + */ + +#ifdef TRUST_BIND_TRANSFORM + // trust FBXJoint::bindTransform (which is wrong for joints NOT bound to anything) AnimPose absoluteBindPose(_joints[i].bindTransform); _absoluteBindPoses.push_back(absoluteBindPose); - int parentIndex = getParentIndex(i); if (parentIndex >= 0) { AnimPose inverseParentAbsoluteBindPose = _absoluteBindPoses[parentIndex].inverse(); @@ -60,24 +85,24 @@ AnimSkeleton::AnimSkeleton(const std::vector& joints) { } else { _relativeBindPoses.push_back(absoluteBindPose); } - - // AJT: - // Attempt to use relative bind pose.. but it's not working. - /* - AnimPose relBindPose(glm::vec3(1.0f), _joints[i].rotation, _joints[i].translation); +#else + // trust FBXJoint's local transforms (which is not really the bind pose, but the default pose in the fbx) + glm::mat4 rotTransform = glm::mat4_cast(_joints[i].preRotation * _joints[i].rotation * _joints[i].postRotation); + glm::mat4 relBindMat = glm::translate(_joints[i].translation) * _joints[i].preTransform * rotTransform * _joints[i].postTransform; + AnimPose relBindPose(relBindMat); _relativeBindPoses.push_back(relBindPose); int parentIndex = getParentIndex(i); if (parentIndex >= 0) { - AnimPose parentAbsBindPose = _absoluteBindPoses[parentIndex]; - _absoluteBindPoses.push_back(parentAbsBindPose * relBindPose); + _absoluteBindPoses.push_back(_absoluteBindPoses[parentIndex] * relBindPose); } else { _absoluteBindPoses.push_back(relBindPose); } - */ +#endif } } + int AnimSkeleton::nameToJointIndex(const QString& jointName) const { for (size_t i = 0; i < _joints.size(); i++) { if (_joints[i].name == jointName) { diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 8a9877ca12..7bfe7be98d 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -167,27 +167,29 @@ static const uint32_t cyan = toRGBA(0, 128, 128, 255); static void addWireframeSphereWithAxes(const AnimPose& rootPose, const AnimPose& pose, float radius, Vertex*& v) { + glm::vec3 base = rootPose * pose.trans; + // x-axis - v->pos = rootPose * pose.trans; + v->pos = base; v->rgba = red; v++; - v->pos = rootPose * (pose.trans + pose.rot * glm::vec3(radius * 2.0f, 0.0f, 0.0f)); + v->pos = rootPose * (pose.trans + pose.rot * glm::vec3(radius, 0.0f, 0.0f)); v->rgba = red; v++; // y-axis - v->pos = rootPose * pose.trans; + v->pos = base; v->rgba = green; v++; - v->pos = rootPose * (pose.trans + pose.rot * glm::vec3(0.0f, radius * 2.0f, 0.0f)); + v->pos = rootPose * (pose.trans + pose.rot * glm::vec3(0.0f, radius, 0.0f)); v->rgba = green; v++; // z-axis - v->pos = rootPose * pose.trans; + v->pos = base; v->rgba = blue; v++; - v->pos = rootPose * (pose.trans + pose.rot * glm::vec3(0.0f, 0.0f, radius * 2.0f)); + v->pos = rootPose * (pose.trans + pose.rot * glm::vec3(0.0f, 0.0f, radius)); v->rgba = blue; v++; } @@ -250,16 +252,12 @@ void AnimDebugDraw::update() { AnimPose pose = skeleton->getAbsoluteBindPose(i); // draw axes - const float radius = 0.01f; + const float radius = 0.1f; addWireframeSphereWithAxes(rootPose, pose, radius, v); // line to parent. auto parentIndex = skeleton->getParentIndex(i); - //qCDebug(renderutils) << skeleton->getJointName(i) << " index = " << i; - //qCDebug(renderutils) << " absPose =" << skeleton->getAbsoluteBindPose(i); - //qCDebug(renderutils) << " relPose =" << skeleton->getRelativeBindPose(i); if (parentIndex >= 0) { - //qCDebug(renderutils) << " parent =" << parentIndex; assert(parentIndex < skeleton->getNumJoints()); AnimPose parentPose = skeleton->getAbsoluteBindPose(parentIndex); addWireframeBoneAxis(rootPose, pose, parentPose, radius, v); @@ -287,7 +285,7 @@ void AnimDebugDraw::update() { } // draw axes - const float radius = 0.01f; + const float radius = 0.1f; addWireframeSphereWithAxes(rootPose, absAnimPose[i], radius, v); if (parentIndex >= 0) {