mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 02:24:51 +02:00
Merge pull request #14904 from hyperlogic/feature/preserve-default-scale
Case 20943: Animations should preserve avatar joint scale
This commit is contained in:
commit
72f198fe00
2 changed files with 51 additions and 50 deletions
|
@ -99,65 +99,64 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
assert(_networkAnim && _networkAnim->isLoaded() && _skeleton);
|
assert(_networkAnim && _networkAnim->isLoaded() && _skeleton);
|
||||||
_anim.clear();
|
_anim.clear();
|
||||||
|
|
||||||
// build a mapping from animation joint indices to skeleton joint indices.
|
auto avatarSkeleton = getSkeleton();
|
||||||
|
|
||||||
|
// build a mapping from animation joint indices to avatar joint indices.
|
||||||
// by matching joints with the same name.
|
// by matching joints with the same name.
|
||||||
const HFMModel& hfmModel = _networkAnim->getHFMModel();
|
const HFMModel& animModel = _networkAnim->getHFMModel();
|
||||||
AnimSkeleton animSkeleton(hfmModel);
|
AnimSkeleton animSkeleton(animModel);
|
||||||
const auto animJointCount = animSkeleton.getNumJoints();
|
const int animJointCount = animSkeleton.getNumJoints();
|
||||||
const auto skeletonJointCount = _skeleton->getNumJoints();
|
const int avatarJointCount = avatarSkeleton->getNumJoints();
|
||||||
std::vector<int> jointMap;
|
std::vector<int> animToAvatarJointIndexMap;
|
||||||
jointMap.reserve(animJointCount);
|
animToAvatarJointIndexMap.reserve(animJointCount);
|
||||||
for (int i = 0; i < animJointCount; i++) {
|
for (int animJointIndex = 0; animJointIndex < animJointCount; animJointIndex++) {
|
||||||
int skeletonJoint = _skeleton->nameToJointIndex(animSkeleton.getJointName(i));
|
QString animJointName = animSkeleton.getJointName(animJointIndex);
|
||||||
jointMap.push_back(skeletonJoint);
|
int avatarJointIndex = avatarSkeleton->nameToJointIndex(animJointName);
|
||||||
|
animToAvatarJointIndexMap.push_back(avatarJointIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int frameCount = hfmModel.animationFrames.size();
|
const int animFrameCount = animModel.animationFrames.size();
|
||||||
_anim.resize(frameCount);
|
_anim.resize(animFrameCount);
|
||||||
|
|
||||||
for (int frame = 0; frame < frameCount; frame++) {
|
for (int frame = 0; frame < animFrameCount; frame++) {
|
||||||
|
|
||||||
const HFMAnimationFrame& hfmAnimFrame = hfmModel.animationFrames[frame];
|
const HFMAnimationFrame& animFrame = animModel.animationFrames[frame];
|
||||||
|
|
||||||
// init all joints in animation to default pose
|
// init all joints in animation to default pose
|
||||||
// this will give us a resonable result for bones in the model skeleton but not in the animation.
|
// this will give us a resonable result for bones in the avatar skeleton but not in the animation.
|
||||||
_anim[frame].reserve(skeletonJointCount);
|
_anim[frame].reserve(avatarJointCount);
|
||||||
for (int skeletonJoint = 0; skeletonJoint < skeletonJointCount; skeletonJoint++) {
|
for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
|
||||||
_anim[frame].push_back(_skeleton->getRelativeDefaultPose(skeletonJoint));
|
_anim[frame].push_back(avatarSkeleton->getRelativeDefaultPose(avatarJointIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int animJoint = 0; animJoint < animJointCount; animJoint++) {
|
for (int animJointIndex = 0; animJointIndex < animJointCount; animJointIndex++) {
|
||||||
int skeletonJoint = jointMap[animJoint];
|
int avatarJointIndex = animToAvatarJointIndexMap[animJointIndex];
|
||||||
|
|
||||||
const glm::vec3& hfmAnimTrans = hfmAnimFrame.translations[animJoint];
|
// skip joints that are in the animation but not in the avatar.
|
||||||
const glm::quat& hfmAnimRot = hfmAnimFrame.rotations[animJoint];
|
if (avatarJointIndex >= 0 && avatarJointIndex < avatarJointCount) {
|
||||||
|
|
||||||
// skip joints that are in the animation but not in the skeleton.
|
const glm::vec3& animTrans = animFrame.translations[animJointIndex];
|
||||||
if (skeletonJoint >= 0 && skeletonJoint < skeletonJointCount) {
|
const glm::quat& animRot = animFrame.rotations[animJointIndex];
|
||||||
|
|
||||||
AnimPose preRot, postRot;
|
const AnimPose& animPreRotPose = animSkeleton.getPreRotationPose(animJointIndex);
|
||||||
preRot = animSkeleton.getPreRotationPose(animJoint);
|
AnimPose animPostRotPose = animSkeleton.getPostRotationPose(animJointIndex);
|
||||||
postRot = animSkeleton.getPostRotationPose(animJoint);
|
AnimPose animRotPose(glm::vec3(1.0f), animRot, glm::vec3());
|
||||||
|
|
||||||
// cancel out scale
|
// adjust anim scale to equal the scale from the avatar joint.
|
||||||
preRot.scale() = glm::vec3(1.0f);
|
// we do not support animated scale.
|
||||||
postRot.scale() = glm::vec3(1.0f);
|
const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex);
|
||||||
|
animPostRotPose.scale() = avatarDefaultPose.scale();
|
||||||
|
|
||||||
AnimPose rot(glm::vec3(1.0f), hfmAnimRot, glm::vec3());
|
// retarget translation from animation to avatar
|
||||||
|
const glm::vec3& animZeroTrans = animModel.animationFrames[0].translations[animJointIndex];
|
||||||
// adjust translation offsets, so large translation animatons on the reference skeleton
|
|
||||||
// will be adjusted when played on a skeleton with short limbs.
|
|
||||||
const glm::vec3& hfmZeroTrans = hfmModel.animationFrames[0].translations[animJoint];
|
|
||||||
const AnimPose& relDefaultPose = _skeleton->getRelativeDefaultPose(skeletonJoint);
|
|
||||||
float boneLengthScale = 1.0f;
|
float boneLengthScale = 1.0f;
|
||||||
const float EPSILON = 0.0001f;
|
const float EPSILON = 0.0001f;
|
||||||
if (fabsf(glm::length(hfmZeroTrans)) > EPSILON) {
|
if (fabsf(glm::length(animZeroTrans)) > EPSILON) {
|
||||||
boneLengthScale = glm::length(relDefaultPose.trans()) / glm::length(hfmZeroTrans);
|
boneLengthScale = glm::length(avatarDefaultPose.trans()) / glm::length(animZeroTrans);
|
||||||
}
|
}
|
||||||
|
AnimPose animTransPose = AnimPose(glm::vec3(1.0f), glm::quat(), avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans));
|
||||||
|
|
||||||
AnimPose trans = AnimPose(glm::vec3(1.0f), glm::quat(), relDefaultPose.trans() + boneLengthScale * (hfmAnimTrans - hfmZeroTrans));
|
_anim[frame][avatarJointIndex] = animTransPose * animPreRotPose * animRotPose * animPostRotPose;
|
||||||
|
|
||||||
_anim[frame][skeletonJoint] = trans * preRot * rot * postRot;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +164,7 @@ void AnimClip::copyFromNetworkAnim() {
|
||||||
// mirrorAnim will be re-built on demand, if needed.
|
// mirrorAnim will be re-built on demand, if needed.
|
||||||
_mirrorAnim.clear();
|
_mirrorAnim.clear();
|
||||||
|
|
||||||
_poses.resize(skeletonJointCount);
|
_poses.resize(avatarJointCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimClip::buildMirrorAnim() {
|
void AnimClip::buildMirrorAnim() {
|
||||||
|
|
|
@ -1878,13 +1878,15 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<AnimInverseKinematics> ikNode = getAnimInverseKinematicsNode();
|
std::shared_ptr<AnimInverseKinematics> ikNode = getAnimInverseKinematicsNode();
|
||||||
for (int i = 0; i < (int)NumSecondaryControllerTypes; i++) {
|
if (ikNode) {
|
||||||
int index = indexOfJoint(secondaryControllerJointNames[i]);
|
for (int i = 0; i < (int)NumSecondaryControllerTypes; i++) {
|
||||||
if ((index >= 0) && (ikNode)) {
|
int index = indexOfJoint(secondaryControllerJointNames[i]);
|
||||||
if (params.secondaryControllerFlags[i] & (uint8_t)ControllerFlags::Enabled) {
|
if (index >= 0) {
|
||||||
ikNode->setSecondaryTargetInRigFrame(index, params.secondaryControllerPoses[i]);
|
if (params.secondaryControllerFlags[i] & (uint8_t)ControllerFlags::Enabled) {
|
||||||
} else {
|
ikNode->setSecondaryTargetInRigFrame(index, params.secondaryControllerPoses[i]);
|
||||||
ikNode->clearSecondaryTarget(index);
|
} else {
|
||||||
|
ikNode->clearSecondaryTarget(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2177,4 +2179,4 @@ void Rig::initFlow(bool isActive) {
|
||||||
_internalFlow.cleanUp();
|
_internalFlow.cleanUp();
|
||||||
_networkFlow.cleanUp();
|
_networkFlow.cleanUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue