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.
This commit is contained in:
Anthony J. Thibault 2015-08-04 16:03:08 -07:00
parent d8a20340a0
commit 559367db4a
4 changed files with 49 additions and 26 deletions

View file

@ -1221,7 +1221,7 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
joints.push_back(joint);
}
auto skeleton = make_shared<AnimSkeleton>(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<AnimClip>("clip", "https://hifi-public.s3.amazonaws.com/ozan/support/FightClubBotTest1/Animations/standard_idle.fbx", 0.0f, 90.0f, 1.0f, true);

View file

@ -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];
}
}
}

View file

@ -10,6 +10,8 @@
#include "AnimSkeleton.h"
#include "AnimationLogging.h"
#include "glmHelpers.h"
#include <glm/gtx/transform.hpp>
#include <glm/gtc/quaternion.hpp>
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<FBXJoint>& joints) {
_joints = joints;
@ -50,9 +53,31 @@ AnimSkeleton::AnimSkeleton(const std::vector<FBXJoint>& 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<FBXJoint>& 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) {

View file

@ -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) {