Added translation support to AC avatar animations.

This commit is contained in:
Anthony J. Thibault 2017-03-28 17:23:36 -07:00
parent 82114ae6ab
commit ecc31802b8

View file

@ -9,11 +9,15 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QDebug>
#include <QThread>
#include <glm/gtx/transform.hpp>
#include <GLMHelpers.h>
#include <AnimUtil.h>
#include "ScriptableAvatar.h"
QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail) {
_globalPosition = getPosition();
return AvatarData::toByteArrayStateful(dataDetail);
@ -57,6 +61,14 @@ void ScriptableAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
_animSkeleton.reset();
AvatarData::setSkeletonModelURL(skeletonModelURL);
}
static AnimPose composeAnimPose(const FBXJoint& fbxJoint, const glm::quat rotation, const glm::vec3 translation) {
glm::mat4 translationMat = glm::translate(translation);
glm::mat4 rotationMat = glm::mat4_cast(fbxJoint.preRotation * rotation * fbxJoint.postRotation);
glm::mat4 finalMat = translationMat * fbxJoint.preTransform * rotationMat * fbxJoint.postTransform;
return AnimPose(finalMat);
}
void ScriptableAvatar::update(float deltatime) {
if (_bind.isNull() && !_skeletonFBXURL.isEmpty()) { // AvatarData will parse the .fst, but not get the .fbx skeleton.
_bind = DependencyManager::get<AnimationCache>()->getAnimation(_skeletonFBXURL);
@ -81,32 +93,42 @@ void ScriptableAvatar::update(float deltatime) {
if (_jointData.size() != nJoints) {
_jointData.resize(nJoints);
}
const int frameCount = _animation->getFrames().size();
const FBXAnimationFrame& floorFrame = _animation->getFrames().at((int)glm::floor(currentFrame) % frameCount);
const FBXAnimationFrame& ceilFrame = _animation->getFrames().at((int)glm::ceil(currentFrame) % frameCount);
const float frameFraction = glm::fract(currentFrame);
std::vector<AnimPose> poses = _animSkeleton->getRelativeDefaultPoses();
float UNIT_SCALE = 0.01f;
for (int i = 0; i < animationJointNames.size(); i++) {
const QString& name = animationJointNames[i];
// As long as we need the model preRotations anyway, let's get the jointIndex from the bind skeleton rather than
// trusting the .fst (which is sometimes not updated to match changes to .fbx).
int mapping = _bind->getGeometry().getJointIndex(name);
if (mapping != -1 && !_maskedJoints.contains(name)) {
// Eventually, this should probably deal with post rotations and translations, too.
poses[mapping].rot() = modelJoints[mapping].preRotation *
safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);;
AnimPose floorPose = composeAnimPose(modelJoints[mapping], floorFrame.rotations[i], floorFrame.translations[i] * UNIT_SCALE);
AnimPose ceilPose = composeAnimPose(modelJoints[mapping], ceilFrame.rotations[i], floorFrame.translations[i] * UNIT_SCALE);
blend(1, &floorPose, &ceilPose, frameFraction, &poses[mapping]);
}
}
_animSkeleton->convertRelativePosesToAbsolute(poses);
std::vector<AnimPose> absPoses = poses;
_animSkeleton->convertRelativePosesToAbsolute(absPoses);
for (int i = 0; i < nJoints; i++) {
JointData& data = _jointData[i];
AnimPose& pose = poses[i];
if (data.rotation != pose.rot()) {
data.rotation = pose.rot();
AnimPose& absPose = absPoses[i];
if (data.rotation != absPose.rot()) {
data.rotation = absPose.rot();
data.rotationSet = true;
}
AnimPose& relPose = poses[i];
if (data.translation != relPose.trans()) {
data.translation = relPose.trans();
data.translationSet = true;
}
}
} else {