mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 04:57:58 +02:00
Merge pull request #15068 from hyperlogic/bug-fix/avatar-missing-animated-joints-bug
Fix for case when animated joints are missing from the target avatar
This commit is contained in:
commit
369c718ba8
3 changed files with 79 additions and 34 deletions
|
@ -95,57 +95,85 @@ void AnimClip::setCurrentFrameInternal(float frame) {
|
||||||
_frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame + _startFrame, dt, _loopFlag, _id, triggers);
|
_frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame + _startFrame, dt, _loopFlag, _id, triggers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<int> buildJointIndexMap(const AnimSkeleton& dstSkeleton, const AnimSkeleton& srcSkeleton) {
|
||||||
|
std::vector<int> jointIndexMap;
|
||||||
|
int srcJointCount = srcSkeleton.getNumJoints();
|
||||||
|
jointIndexMap.reserve(srcJointCount);
|
||||||
|
for (int srcJointIndex = 0; srcJointIndex < srcJointCount; srcJointIndex++) {
|
||||||
|
QString srcJointName = srcSkeleton.getJointName(srcJointIndex);
|
||||||
|
int dstJointIndex = dstSkeleton.nameToJointIndex(srcJointName);
|
||||||
|
jointIndexMap.push_back(dstJointIndex);
|
||||||
|
}
|
||||||
|
return jointIndexMap;
|
||||||
|
}
|
||||||
|
|
||||||
void AnimClip::copyFromNetworkAnim() {
|
void AnimClip::copyFromNetworkAnim() {
|
||||||
assert(_networkAnim && _networkAnim->isLoaded() && _skeleton);
|
assert(_networkAnim && _networkAnim->isLoaded() && _skeleton);
|
||||||
_anim.clear();
|
_anim.clear();
|
||||||
|
|
||||||
auto avatarSkeleton = getSkeleton();
|
auto avatarSkeleton = getSkeleton();
|
||||||
|
|
||||||
// build a mapping from animation joint indices to avatar joint indices.
|
|
||||||
// by matching joints with the same name.
|
|
||||||
const HFMModel& animModel = _networkAnim->getHFMModel();
|
const HFMModel& animModel = _networkAnim->getHFMModel();
|
||||||
AnimSkeleton animSkeleton(animModel);
|
AnimSkeleton animSkeleton(animModel);
|
||||||
const int animJointCount = animSkeleton.getNumJoints();
|
const int animJointCount = animSkeleton.getNumJoints();
|
||||||
const int avatarJointCount = avatarSkeleton->getNumJoints();
|
const int avatarJointCount = avatarSkeleton->getNumJoints();
|
||||||
std::vector<int> animToAvatarJointIndexMap;
|
|
||||||
animToAvatarJointIndexMap.reserve(animJointCount);
|
// build a mapping from animation joint indices to avatar joint indices by matching joints with the same name.
|
||||||
for (int animJointIndex = 0; animJointIndex < animJointCount; animJointIndex++) {
|
std::vector<int> avatarToAnimJointIndexMap = buildJointIndexMap(animSkeleton, *avatarSkeleton);
|
||||||
QString animJointName = animSkeleton.getJointName(animJointIndex);
|
|
||||||
int avatarJointIndex = avatarSkeleton->nameToJointIndex(animJointName);
|
|
||||||
animToAvatarJointIndexMap.push_back(avatarJointIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int animFrameCount = animModel.animationFrames.size();
|
const int animFrameCount = animModel.animationFrames.size();
|
||||||
_anim.resize(animFrameCount);
|
_anim.resize(animFrameCount);
|
||||||
|
|
||||||
for (int frame = 0; frame < animFrameCount; frame++) {
|
for (int frame = 0; frame < animFrameCount; frame++) {
|
||||||
|
|
||||||
const HFMAnimationFrame& animFrame = animModel.animationFrames[frame];
|
const HFMAnimationFrame& animFrame = animModel.animationFrames[frame];
|
||||||
|
|
||||||
// init all joints in animation to default pose
|
// extract the full rotations from the animFrame (including pre and post rotations from the animModel).
|
||||||
// this will give us a resonable result for bones in the avatar skeleton but not in the animation.
|
std::vector<glm::quat> animRotations;
|
||||||
_anim[frame].reserve(avatarJointCount);
|
animRotations.reserve(animJointCount);
|
||||||
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
for (int i = 0; i < animJointCount; i++) {
|
||||||
_anim[frame].push_back(avatarSkeleton->getRelativeDefaultPose(avatarJointIndex));
|
animRotations.push_back(animModel.joints[i].preRotation * animFrame.rotations[i] * animModel.joints[i].postRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int animJointIndex = 0; animJointIndex < animJointCount; animJointIndex++) {
|
// convert rotations into absolute frame
|
||||||
int avatarJointIndex = animToAvatarJointIndexMap[animJointIndex];
|
animSkeleton.convertRelativeRotationsToAbsolute(animRotations);
|
||||||
|
|
||||||
// skip joints that are in the animation but not in the avatar.
|
// build absolute rotations for the avatar
|
||||||
if (avatarJointIndex >= 0 && avatarJointIndex < avatarJointCount) {
|
std::vector<glm::quat> avatarRotations;
|
||||||
|
avatarRotations.reserve(avatarJointCount);
|
||||||
|
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
||||||
|
int animJointIndex = avatarToAnimJointIndexMap[avatarJointIndex];
|
||||||
|
if (animJointIndex >= 0) {
|
||||||
|
// This joint is in both animation and avatar.
|
||||||
|
// Set the absolute rotation directly
|
||||||
|
avatarRotations.push_back(animRotations[animJointIndex]);
|
||||||
|
} else {
|
||||||
|
// This joint is NOT in the animation at all.
|
||||||
|
// Set it so that the default relative rotation remains unchanged.
|
||||||
|
glm::quat avatarRelativeDefaultRot = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex).rot();
|
||||||
|
glm::quat avatarParentAbsoluteRot;
|
||||||
|
int avatarParentJointIndex = avatarSkeleton->getParentIndex(avatarJointIndex);
|
||||||
|
if (avatarParentJointIndex >= 0) {
|
||||||
|
avatarParentAbsoluteRot = avatarRotations[avatarParentJointIndex];
|
||||||
|
}
|
||||||
|
avatarRotations.push_back(avatarParentAbsoluteRot * avatarRelativeDefaultRot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert avatar rotations into relative frame
|
||||||
|
avatarSkeleton->convertAbsoluteRotationsToRelative(avatarRotations);
|
||||||
|
|
||||||
|
_anim[frame].reserve(avatarJointCount);
|
||||||
|
|
||||||
|
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
||||||
|
const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex);
|
||||||
|
|
||||||
|
// copy scale over from avatar default pose
|
||||||
|
glm::vec3 relativeScale = avatarDefaultPose.scale();
|
||||||
|
|
||||||
|
glm::vec3 relativeTranslation;
|
||||||
|
int animJointIndex = avatarToAnimJointIndexMap[avatarJointIndex];
|
||||||
|
if (animJointIndex >= 0) {
|
||||||
|
// This joint is in both animation and avatar.
|
||||||
const glm::vec3& animTrans = animFrame.translations[animJointIndex];
|
const glm::vec3& animTrans = animFrame.translations[animJointIndex];
|
||||||
const glm::quat& animRot = animFrame.rotations[animJointIndex];
|
|
||||||
|
|
||||||
const AnimPose& animPreRotPose = animSkeleton.getPreRotationPose(animJointIndex);
|
|
||||||
AnimPose animPostRotPose = animSkeleton.getPostRotationPose(animJointIndex);
|
|
||||||
AnimPose animRotPose(glm::vec3(1.0f), animRot, glm::vec3());
|
|
||||||
|
|
||||||
// adjust anim scale to equal the scale from the avatar joint.
|
|
||||||
// we do not support animated scale.
|
|
||||||
const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex);
|
|
||||||
animPostRotPose.scale() = avatarDefaultPose.scale();
|
|
||||||
|
|
||||||
// retarget translation from animation to avatar
|
// retarget translation from animation to avatar
|
||||||
const glm::vec3& animZeroTrans = animModel.animationFrames[0].translations[animJointIndex];
|
const glm::vec3& animZeroTrans = animModel.animationFrames[0].translations[animJointIndex];
|
||||||
|
@ -154,10 +182,15 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
if (fabsf(glm::length(animZeroTrans)) > EPSILON) {
|
if (fabsf(glm::length(animZeroTrans)) > EPSILON) {
|
||||||
boneLengthScale = glm::length(avatarDefaultPose.trans()) / glm::length(animZeroTrans);
|
boneLengthScale = glm::length(avatarDefaultPose.trans()) / glm::length(animZeroTrans);
|
||||||
}
|
}
|
||||||
AnimPose animTransPose = AnimPose(glm::vec3(1.0f), glm::quat(), avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans));
|
relativeTranslation = avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans);
|
||||||
|
} else {
|
||||||
_anim[frame][avatarJointIndex] = animTransPose * animPreRotPose * animRotPose * animPostRotPose;
|
// This joint is NOT in the animation at all.
|
||||||
|
// preserve the default translation.
|
||||||
|
relativeTranslation = avatarDefaultPose.trans();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// build the final pose
|
||||||
|
_anim[frame].push_back(AnimPose(relativeScale, avatarRotations[avatarJointIndex], relativeTranslation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,8 +149,19 @@ void AnimSkeleton::convertAbsolutePosesToRelative(AnimPoseVec& poses) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimSkeleton::convertRelativeRotationsToAbsolute(std::vector<glm::quat>& rotations) const {
|
||||||
|
// rotations start off relative and leave in absolute frame
|
||||||
|
int lastIndex = std::min((int)rotations.size(), _jointsSize);
|
||||||
|
for (int i = 0; i < lastIndex; ++i) {
|
||||||
|
int parentIndex = _parentIndices[i];
|
||||||
|
if (parentIndex != -1) {
|
||||||
|
rotations[i] = rotations[parentIndex] * rotations[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AnimSkeleton::convertAbsoluteRotationsToRelative(std::vector<glm::quat>& rotations) const {
|
void AnimSkeleton::convertAbsoluteRotationsToRelative(std::vector<glm::quat>& rotations) const {
|
||||||
// poses start off absolute and leave in relative frame
|
// rotations start off absolute and leave in relative frame
|
||||||
int lastIndex = std::min((int)rotations.size(), _jointsSize);
|
int lastIndex = std::min((int)rotations.size(), _jointsSize);
|
||||||
for (int i = lastIndex - 1; i >= 0; --i) {
|
for (int i = lastIndex - 1; i >= 0; --i) {
|
||||||
int parentIndex = _parentIndices[i];
|
int parentIndex = _parentIndices[i];
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
void convertRelativePosesToAbsolute(AnimPoseVec& poses) const;
|
void convertRelativePosesToAbsolute(AnimPoseVec& poses) const;
|
||||||
void convertAbsolutePosesToRelative(AnimPoseVec& poses) const;
|
void convertAbsolutePosesToRelative(AnimPoseVec& poses) const;
|
||||||
|
|
||||||
|
void convertRelativeRotationsToAbsolute(std::vector<glm::quat>& rotations) const;
|
||||||
void convertAbsoluteRotationsToRelative(std::vector<glm::quat>& rotations) const;
|
void convertAbsoluteRotationsToRelative(std::vector<glm::quat>& rotations) const;
|
||||||
|
|
||||||
void saveNonMirroredPoses(const AnimPoseVec& poses) const;
|
void saveNonMirroredPoses(const AnimPoseVec& poses) const;
|
||||||
|
|
Loading…
Reference in a new issue