mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-10 16:38:39 +02:00
254 lines
10 KiB
C++
254 lines
10 KiB
C++
//
|
|
// AnimSkeleton.cpp
|
|
//
|
|
// Created by Anthony J. Thibault on 9/2/15.
|
|
// Copyright (c) 2015 High Fidelity, Inc. All rights reserved.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#include "AnimSkeleton.h"
|
|
|
|
#include <glm/gtx/transform.hpp>
|
|
|
|
#include <GLMHelpers.h>
|
|
|
|
#include "AnimationLogging.h"
|
|
|
|
AnimSkeleton::AnimSkeleton(const FBXGeometry& fbxGeometry) {
|
|
// convert to std::vector of joints
|
|
std::vector<FBXJoint> joints;
|
|
joints.reserve(fbxGeometry.joints.size());
|
|
for (auto& joint : fbxGeometry.joints) {
|
|
joints.push_back(joint);
|
|
}
|
|
buildSkeletonFromJoints(joints);
|
|
}
|
|
|
|
AnimSkeleton::AnimSkeleton(const std::vector<FBXJoint>& joints) {
|
|
buildSkeletonFromJoints(joints);
|
|
}
|
|
|
|
int AnimSkeleton::nameToJointIndex(const QString& jointName) const {
|
|
for (int i = 0; i < (int)_joints.size(); i++) {
|
|
if (_joints[i].name == jointName) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int AnimSkeleton::getNumJoints() const {
|
|
return (int)_joints.size();
|
|
}
|
|
|
|
const AnimPose& AnimSkeleton::getAbsoluteBindPose(int jointIndex) const {
|
|
return _absoluteBindPoses[jointIndex];
|
|
}
|
|
|
|
const AnimPose& AnimSkeleton::getRelativeBindPose(int jointIndex) const {
|
|
return _relativeBindPoses[jointIndex];
|
|
}
|
|
|
|
const AnimPose& AnimSkeleton::getRelativeDefaultPose(int jointIndex) const {
|
|
return _relativeDefaultPoses[jointIndex];
|
|
}
|
|
|
|
const AnimPose& AnimSkeleton::getAbsoluteDefaultPose(int jointIndex) const {
|
|
return _absoluteDefaultPoses[jointIndex];
|
|
}
|
|
|
|
// get pre multiplied transform which should include FBX pre potations
|
|
const AnimPose& AnimSkeleton::getPreRotationPose(int jointIndex) const {
|
|
return _relativePreRotationPoses[jointIndex];
|
|
}
|
|
|
|
// get post multiplied transform which might include FBX offset transformations
|
|
const AnimPose& AnimSkeleton::getPostRotationPose(int jointIndex) const {
|
|
return _relativePostRotationPoses[jointIndex];
|
|
}
|
|
|
|
int AnimSkeleton::getParentIndex(int jointIndex) const {
|
|
return _joints[jointIndex].parentIndex;
|
|
}
|
|
|
|
const QString& AnimSkeleton::getJointName(int jointIndex) const {
|
|
return _joints[jointIndex].name;
|
|
}
|
|
|
|
AnimPose AnimSkeleton::getAbsolutePose(int jointIndex, const AnimPoseVec& poses) const {
|
|
if (jointIndex < 0 || jointIndex >= (int)poses.size() || jointIndex >= (int)_joints.size()) {
|
|
return AnimPose::identity;
|
|
} else {
|
|
return getAbsolutePose(_joints[jointIndex].parentIndex, poses) * poses[jointIndex];
|
|
}
|
|
}
|
|
|
|
void AnimSkeleton::convertRelativePosesToAbsolute(AnimPoseVec& poses) const {
|
|
// poses start off relative and leave in absolute frame
|
|
int lastIndex = std::min((int)poses.size(), (int)_joints.size());
|
|
for (int i = 0; i < lastIndex; ++i) {
|
|
int parentIndex = _joints[i].parentIndex;
|
|
if (parentIndex != -1) {
|
|
poses[i] = poses[parentIndex] * poses[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
void AnimSkeleton::convertAbsolutePosesToRelative(AnimPoseVec& poses) const {
|
|
// poses start off absolute and leave in relative frame
|
|
int lastIndex = std::min((int)poses.size(), (int)_joints.size());
|
|
for (int i = lastIndex - 1; i >= 0; --i) {
|
|
int parentIndex = _joints[i].parentIndex;
|
|
if (parentIndex != -1) {
|
|
poses[i] = poses[parentIndex].inverse() * poses[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
void AnimSkeleton::mirrorRelativePoses(AnimPoseVec& poses) const {
|
|
convertRelativePosesToAbsolute(poses);
|
|
mirrorAbsolutePoses(poses);
|
|
convertAbsolutePosesToRelative(poses);
|
|
}
|
|
|
|
void AnimSkeleton::mirrorAbsolutePoses(AnimPoseVec& poses) const {
|
|
AnimPoseVec temp = poses;
|
|
for (int i = 0; i < (int)poses.size(); i++) {
|
|
poses[_mirrorMap[i]] = temp[i].mirror();
|
|
}
|
|
}
|
|
|
|
void AnimSkeleton::buildSkeletonFromJoints(const std::vector<FBXJoint>& joints) {
|
|
_joints = joints;
|
|
|
|
// build a cache of bind poses
|
|
_absoluteBindPoses.reserve(joints.size());
|
|
_relativeBindPoses.reserve(joints.size());
|
|
|
|
// build a chache of default poses
|
|
_absoluteDefaultPoses.reserve(joints.size());
|
|
_relativeDefaultPoses.reserve(joints.size());
|
|
_relativePreRotationPoses.reserve(joints.size());
|
|
_relativePostRotationPoses.reserve(joints.size());
|
|
|
|
// iterate over FBXJoints and extract the bind pose information.
|
|
for (int i = 0; i < (int)joints.size(); i++) {
|
|
|
|
// build pre and post transforms
|
|
glm::mat4 preRotationTransform = _joints[i].preTransform * glm::mat4_cast(_joints[i].preRotation);
|
|
glm::mat4 postRotationTransform = glm::mat4_cast(_joints[i].postRotation) * _joints[i].postTransform;
|
|
_relativePreRotationPoses.push_back(AnimPose(preRotationTransform));
|
|
_relativePostRotationPoses.push_back(AnimPose(postRotationTransform));
|
|
|
|
// build relative and absolute default poses
|
|
glm::mat4 relDefaultMat = glm::translate(_joints[i].translation) * preRotationTransform * glm::mat4_cast(_joints[i].rotation) * postRotationTransform;
|
|
AnimPose relDefaultPose(relDefaultMat);
|
|
_relativeDefaultPoses.push_back(relDefaultPose);
|
|
int parentIndex = getParentIndex(i);
|
|
if (parentIndex >= 0) {
|
|
_absoluteDefaultPoses.push_back(_absoluteDefaultPoses[parentIndex] * relDefaultPose);
|
|
} else {
|
|
_absoluteDefaultPoses.push_back(relDefaultPose);
|
|
}
|
|
|
|
// build relative and absolute bind poses
|
|
if (_joints[i].bindTransformFoundInCluster) {
|
|
// Use the FBXJoint::bindTransform, which is absolute model coordinates
|
|
// i.e. not relative to it's parent.
|
|
AnimPose absoluteBindPose(_joints[i].bindTransform);
|
|
_absoluteBindPoses.push_back(absoluteBindPose);
|
|
if (parentIndex >= 0) {
|
|
AnimPose inverseParentAbsoluteBindPose = _absoluteBindPoses[parentIndex].inverse();
|
|
_relativeBindPoses.push_back(inverseParentAbsoluteBindPose * absoluteBindPose);
|
|
} else {
|
|
_relativeBindPoses.push_back(absoluteBindPose);
|
|
}
|
|
} else {
|
|
// use default transform instead
|
|
_relativeBindPoses.push_back(relDefaultPose);
|
|
if (parentIndex >= 0) {
|
|
_absoluteBindPoses.push_back(_absoluteBindPoses[parentIndex] * relDefaultPose);
|
|
} else {
|
|
_absoluteBindPoses.push_back(relDefaultPose);
|
|
}
|
|
}
|
|
}
|
|
|
|
// build mirror map.
|
|
_mirrorMap.reserve(_joints.size());
|
|
for (int i = 0; i < (int)joints.size(); i++) {
|
|
int mirrorJointIndex = -1;
|
|
if (_joints[i].name.startsWith("Left")) {
|
|
QString mirrorJointName = QString(_joints[i].name).replace(0, 4, "Right");
|
|
mirrorJointIndex = nameToJointIndex(mirrorJointName);
|
|
} else if (_joints[i].name.startsWith("Right")) {
|
|
QString mirrorJointName = QString(_joints[i].name).replace(0, 5, "Left");
|
|
mirrorJointIndex = nameToJointIndex(mirrorJointName);
|
|
}
|
|
if (mirrorJointIndex >= 0) {
|
|
_mirrorMap.push_back(mirrorJointIndex);
|
|
} else {
|
|
_mirrorMap.push_back(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
#define DUMP_FBX_JOINTS
|
|
void AnimSkeleton::dump() const {
|
|
qCDebug(animation) << "[";
|
|
for (int i = 0; i < getNumJoints(); i++) {
|
|
qCDebug(animation) << " {";
|
|
qCDebug(animation) << " index =" << i;
|
|
qCDebug(animation) << " name =" << getJointName(i);
|
|
qCDebug(animation) << " absBindPose =" << getAbsoluteBindPose(i);
|
|
qCDebug(animation) << " relBindPose =" << getRelativeBindPose(i);
|
|
qCDebug(animation) << " absDefaultPose =" << getAbsoluteDefaultPose(i);
|
|
qCDebug(animation) << " relDefaultPose =" << getRelativeDefaultPose(i);
|
|
#ifdef DUMP_FBX_JOINTS
|
|
qCDebug(animation) << " fbxJoint =";
|
|
qCDebug(animation) << " isFree =" << _joints[i].isFree;
|
|
qCDebug(animation) << " freeLineage =" << _joints[i].freeLineage;
|
|
qCDebug(animation) << " parentIndex =" << _joints[i].parentIndex;
|
|
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;
|
|
#endif
|
|
if (getParentIndex(i) >= 0) {
|
|
qCDebug(animation) << " parent =" << getJointName(getParentIndex(i));
|
|
}
|
|
qCDebug(animation) << " },";
|
|
}
|
|
qCDebug(animation) << "]";
|
|
}
|
|
|
|
void AnimSkeleton::dump(const AnimPoseVec& poses) const {
|
|
qCDebug(animation) << "[";
|
|
for (int i = 0; i < getNumJoints(); i++) {
|
|
qCDebug(animation) << " {";
|
|
qCDebug(animation) << " index =" << i;
|
|
qCDebug(animation) << " name =" << getJointName(i);
|
|
qCDebug(animation) << " absBindPose =" << getAbsoluteBindPose(i);
|
|
qCDebug(animation) << " relBindPose =" << getRelativeBindPose(i);
|
|
qCDebug(animation) << " absDefaultPose =" << getAbsoluteDefaultPose(i);
|
|
qCDebug(animation) << " relDefaultPose =" << getRelativeDefaultPose(i);
|
|
qCDebug(animation) << " pose =" << poses[i];
|
|
if (getParentIndex(i) >= 0) {
|
|
qCDebug(animation) << " parent =" << getJointName(getParentIndex(i));
|
|
}
|
|
qCDebug(animation) << " },";
|
|
}
|
|
qCDebug(animation) << "]";
|
|
}
|
|
#endif
|