mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 19:21:16 +02:00
Merge pull request #10045 from hyperlogic/feature/ac-avatar-translation
Added translation support to AC avatar animations.
This commit is contained in:
commit
aea5cf0ac0
1 changed files with 31 additions and 9 deletions
|
@ -9,11 +9,15 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <glm/gtx/transform.hpp>
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
|
#include <AnimUtil.h>
|
||||||
#include "ScriptableAvatar.h"
|
#include "ScriptableAvatar.h"
|
||||||
|
|
||||||
|
|
||||||
QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail) {
|
QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail) {
|
||||||
_globalPosition = getPosition();
|
_globalPosition = getPosition();
|
||||||
return AvatarData::toByteArrayStateful(dataDetail);
|
return AvatarData::toByteArrayStateful(dataDetail);
|
||||||
|
@ -57,6 +61,14 @@ void ScriptableAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
_animSkeleton.reset();
|
_animSkeleton.reset();
|
||||||
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
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) {
|
void ScriptableAvatar::update(float deltatime) {
|
||||||
if (_bind.isNull() && !_skeletonFBXURL.isEmpty()) { // AvatarData will parse the .fst, but not get the .fbx skeleton.
|
if (_bind.isNull() && !_skeletonFBXURL.isEmpty()) { // AvatarData will parse the .fst, but not get the .fbx skeleton.
|
||||||
_bind = DependencyManager::get<AnimationCache>()->getAnimation(_skeletonFBXURL);
|
_bind = DependencyManager::get<AnimationCache>()->getAnimation(_skeletonFBXURL);
|
||||||
|
@ -81,32 +93,42 @@ void ScriptableAvatar::update(float deltatime) {
|
||||||
if (_jointData.size() != nJoints) {
|
if (_jointData.size() != nJoints) {
|
||||||
_jointData.resize(nJoints);
|
_jointData.resize(nJoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int frameCount = _animation->getFrames().size();
|
const int frameCount = _animation->getFrames().size();
|
||||||
const FBXAnimationFrame& floorFrame = _animation->getFrames().at((int)glm::floor(currentFrame) % frameCount);
|
const FBXAnimationFrame& floorFrame = _animation->getFrames().at((int)glm::floor(currentFrame) % frameCount);
|
||||||
const FBXAnimationFrame& ceilFrame = _animation->getFrames().at((int)glm::ceil(currentFrame) % frameCount);
|
const FBXAnimationFrame& ceilFrame = _animation->getFrames().at((int)glm::ceil(currentFrame) % frameCount);
|
||||||
const float frameFraction = glm::fract(currentFrame);
|
const float frameFraction = glm::fract(currentFrame);
|
||||||
std::vector<AnimPose> poses = _animSkeleton->getRelativeDefaultPoses();
|
std::vector<AnimPose> poses = _animSkeleton->getRelativeDefaultPoses();
|
||||||
|
|
||||||
|
const float UNIT_SCALE = 0.01f;
|
||||||
|
|
||||||
for (int i = 0; i < animationJointNames.size(); i++) {
|
for (int i = 0; i < animationJointNames.size(); i++) {
|
||||||
const QString& name = animationJointNames[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
|
// 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).
|
// trusting the .fst (which is sometimes not updated to match changes to .fbx).
|
||||||
int mapping = _bind->getGeometry().getJointIndex(name);
|
int mapping = _bind->getGeometry().getJointIndex(name);
|
||||||
if (mapping != -1 && !_maskedJoints.contains(name)) {
|
if (mapping != -1 && !_maskedJoints.contains(name)) {
|
||||||
// Eventually, this should probably deal with post rotations and translations, too.
|
|
||||||
poses[mapping].rot() = modelJoints[mapping].preRotation *
|
AnimPose floorPose = composeAnimPose(modelJoints[mapping], floorFrame.rotations[i], floorFrame.translations[i] * UNIT_SCALE);
|
||||||
safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);;
|
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++) {
|
for (int i = 0; i < nJoints; i++) {
|
||||||
JointData& data = _jointData[i];
|
JointData& data = _jointData[i];
|
||||||
AnimPose& pose = poses[i];
|
AnimPose& absPose = absPoses[i];
|
||||||
if (data.rotation != pose.rot()) {
|
if (data.rotation != absPose.rot()) {
|
||||||
data.rotation = pose.rot();
|
data.rotation = absPose.rot();
|
||||||
data.rotationSet = true;
|
data.rotationSet = true;
|
||||||
}
|
}
|
||||||
|
AnimPose& relPose = poses[i];
|
||||||
|
if (data.translation != relPose.trans()) {
|
||||||
|
data.translation = relPose.trans();
|
||||||
|
data.translationSet = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue