From fe5ea471a1bd6faefe6ff90c5f80388ae89a10b7 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 1 Oct 2015 16:10:33 -0700 Subject: [PATCH] AnimClip: read in translations from fbx file and pre-process them Do the following things to the translations 1. scale by the model offset, this should move the translations into the correct units (meters). 2. compute the ratio between the bone length in the animation and the skeleton. 3. subtract the anim translation from the first translation frame in the animation effectively turning it into a bind pose delta translation. 4. apply bone length ratio to the resulting delta. 5. set the final translation to be the skeleton rel bind pose + this scaled delta translation --- libraries/animation/src/AnimClip.cpp | 47 +++++++++++++++++++--------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index f33c958fa8..c432b3b9ac 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -135,29 +135,46 @@ void AnimClip::copyFromNetworkAnim() { const int frameCount = geom.animationFrames.size(); const int skeletonJointCount = _skeleton->getNumJoints(); _anim.resize(frameCount); - for (int i = 0; i < frameCount; i++) { + + const glm::vec3 offsetScale = extractScale(geom.offset); + + for (int frame = 0; frame < frameCount; frame++) { // init all joints in animation to bind pose - _anim[i].reserve(skeletonJointCount); - for (int j = 0; j < skeletonJointCount; j++) { - _anim[i].push_back(_skeleton->getRelativeBindPose(j)); + // this will give us a resonable result for bones in the skeleton but not in the animation. + _anim[frame].reserve(skeletonJointCount); + for (int skeletonJoint = 0; skeletonJoint < skeletonJointCount; skeletonJoint++) { + _anim[frame].push_back(_skeleton->getRelativeBindPose(skeletonJoint)); } - // init over all joint animations - for (int j = 0; j < animJointCount; j++) { - int k = jointMap[j]; - if (k >= 0 && k < skeletonJointCount) { - _anim[i][k].rot = _skeleton->getRelativeBindPose(k).rot * geom.animationFrames[i].rotations[j]; + for (int animJoint = 0; animJoint < animJointCount; animJoint++) { - // TODO -- why does applying all the joint translations make a mutant? - if (animJoints[j].parentIndex == -1) { - _anim[i][k].trans = geom.animationFrames[i].translations[j] * extractScale(geom.offset); - } else { - _anim[i][k].trans = _skeleton->getRelativeBindPose(k).trans; - } + int skeletonJoint = jointMap[animJoint]; + + // skip joints that are in the animation but not in the skeleton. + if (skeletonJoint >= 0 && skeletonJoint < skeletonJointCount) { + + const glm::vec3& fbxZeroTrans = geom.animationFrames[0].translations[animJoint] * offsetScale; + const AnimPose& relBindPose = _skeleton->getRelativeBindPose(skeletonJoint); + + // used to adjust translation offsets, so large translation animatons on the reference skeleton + // will be adjusted when played on a skeleton with short limbs. + float limbLengthScale = fabs(glm::length(fbxZeroTrans)) <= 0.0001f ? 1.0f : (glm::length(relBindPose.trans) / glm::length(fbxZeroTrans)); + + AnimPose& pose = _anim[frame][skeletonJoint]; + const FBXAnimationFrame& fbxAnimFrame = geom.animationFrames[frame]; + + // rotation in fbxAnimationFrame is a delta from a reference skeleton bind pose. + pose.rot = relBindPose.rot * fbxAnimFrame.rotations[animJoint]; + + // translation in fbxAnimationFrame is not a delta. + // convert it into a delta by subtracting from the first frame. + const glm::vec3& fbxTrans = fbxAnimFrame.translations[animJoint] * offsetScale; + pose.trans = relBindPose.trans + limbLengthScale * (fbxTrans - fbxZeroTrans); } } } + _poses.resize(skeletonJointCount); }