Normalize scale on AnimSkeleton bind pose.

This commit is contained in:
Anthony J. Thibault 2015-08-31 17:27:23 -07:00
parent 9786954585
commit 0d98ab3365
4 changed files with 53 additions and 12 deletions

View file

@ -1240,25 +1240,26 @@ void MyAvatar::setupNewAnimationSystem() {
for (auto& joint : geom.joints) {
joints.push_back(joint);
}
_animSkeleton = make_shared<AnimSkeleton>(joints);
AnimPose geometryOffset(_skeletonModel.getGeometry()->getFBXGeometry().offset);
_animSkeleton = make_shared<AnimSkeleton>(joints, geometryOffset);
// add skeleton to the debug renderer, so we can see it.
/*
AnimPose xform(_skeletonModel.getScale(), glm::quat(), _skeletonModel.getOffset());
AnimDebugDraw::getInstance().addSkeleton("my-avatar", _animSkeleton, xform);
*/
AnimDebugDraw::getInstance().addSkeleton("my-avatar-skeleton", _animSkeleton, AnimPose::identity);
//_animSkeleton->dump();
qCDebug(interfaceapp) << "geomOffset =" << geometryOffset;
// load the anim graph
// https://gist.github.com/hyperlogic/7d6a0892a7319c69e2b9
// python2 -m SimpleHTTPServer&
//auto graphUrl = QUrl("http://localhost:8000/avatar.json");
auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/7d6a0892a7319c69e2b9/raw/403651948de088ca4dcdda4f873e225b091c779a/avatar.json");
auto graphUrl = QUrl("http://localhost:8000/avatar.json");
//auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/7d6a0892a7319c69e2b9/raw/403651948de088ca4dcdda4f873e225b091c779a/avatar.json");
_animLoader.reset(new AnimNodeLoader(graphUrl));
connect(_animLoader.get(), &AnimNodeLoader::success, [this](AnimNode::Pointer nodeIn) {
_animNode = nodeIn;
_animNode->setSkeleton(_animSkeleton);
AnimPose xform(_skeletonModel.getScale() / 10.0f, glm::quat(), _skeletonModel.getOffset() + glm::vec3(0, 0, 1));
AnimDebugDraw::getInstance().addAnimNode("node", _animNode, xform);
AnimPose xform(glm::vec3(1), glm::quat(), glm::vec3(0, 0, -1));
AnimDebugDraw::getInstance().addAnimNode("my-avatar-animation", _animNode, xform);
});
connect(_animLoader.get(), &AnimNodeLoader::error, [this, graphUrl](int error, QString str) {
qCCritical(interfaceapp) << "Error loading" << graphUrl << "code = " << error << "str =" << str;
@ -1266,6 +1267,8 @@ void MyAvatar::setupNewAnimationSystem() {
}
void MyAvatar::teardownNewAnimationSystem() {
AnimDebugDraw::getInstance().removeSkeleton("my-avatar-skeleton");
AnimDebugDraw::getInstance().removeAnimNode("my-avatar-animation");
_animSkeleton = nullptr;
_animLoader = nullptr;
_animNode = nullptr;

View file

@ -62,13 +62,14 @@ static bool matrixIsIdentity(const glm::mat4& m) {
return m == IDENTITY;
}
AnimSkeleton::AnimSkeleton(const std::vector<FBXJoint>& joints) {
AnimSkeleton::AnimSkeleton(const std::vector<FBXJoint>& joints, const AnimPose& geometryOffset) {
_joints = joints;
// build a cache of bind poses
_absoluteBindPoses.reserve(joints.size());
_relativeBindPoses.reserve(joints.size());
// iterate over FBXJoints and extract the bind pose information.
for (size_t i = 0; i < joints.size(); i++) {
if (_joints[i].bindTransformIsValid) {
// Use the FBXJoint::bindTransform, which is absolute model coordinates
@ -97,6 +98,23 @@ AnimSkeleton::AnimSkeleton(const std::vector<FBXJoint>& joints) {
}
}
}
// now we want to normalize scale from geometryOffset to all poses.
// This will ensure our bone translations will be in meters, even if the model was authored with some other unit of mesure.
for (auto& absPose : _absoluteBindPoses) {
absPose.trans = (geometryOffset * absPose).trans;
absPose.scale = vec3(1, 1, 1);
}
// re-compute relative poses based on the modified absolute poses.
for (size_t i = 0; i < _relativeBindPoses.size(); i++) {
int parentIndex = getParentIndex(i);
if (parentIndex >= 0) {
_relativeBindPoses[i] = _absoluteBindPoses[parentIndex].inverse() * _absoluteBindPoses[i];
} else {
_relativeBindPoses[i] = _absoluteBindPoses[i];
}
}
}
int AnimSkeleton::nameToJointIndex(const QString& jointName) const {
@ -127,3 +145,20 @@ int AnimSkeleton::getParentIndex(int jointIndex) const {
const QString& AnimSkeleton::getJointName(int jointIndex) const {
return _joints[jointIndex].name;
}
#ifndef NDEBUG
void AnimSkeleton::dump() const {
qCDebug(animation) << "[";
for (int i = 0; i < getNumJoints(); i++) {
qCDebug(animation) << " {";
qCDebug(animation) << " name =" << getJointName(i);
qCDebug(animation) << " absBindPose =" << getAbsoluteBindPose(i);
qCDebug(animation) << " relBindPose =" << getRelativeBindPose(i);
if (getParentIndex(i) >= 0) {
qCDebug(animation) << " parent =" << getJointName(getParentIndex(i));
}
qCDebug(animation) << " },";
}
qCDebug(animation) << "]";
}
#endif

View file

@ -46,7 +46,7 @@ public:
using Pointer = std::shared_ptr<AnimSkeleton>;
using ConstPointer = std::shared_ptr<const AnimSkeleton>;
AnimSkeleton(const std::vector<FBXJoint>& joints);
AnimSkeleton(const std::vector<FBXJoint>& joints, const AnimPose& geometryOffset);
int nameToJointIndex(const QString& jointName) const;
const QString& getJointName(int jointIndex) const;
int getNumJoints() const;
@ -59,6 +59,10 @@ public:
int getParentIndex(int jointIndex) const;
#ifndef NDEBUG
void dump() const;
#endif
protected:
std::vector<FBXJoint> _joints;
AnimPoseVec _absoluteBindPoses;

View file

@ -44,7 +44,6 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, fl
switchState(animVars, desiredState);
}
assert(_currentState);
auto currentStateNode = _currentState->getNode();
assert(currentStateNode);