Fix 2 bugs with scale of position tracks in rest fixer

Both bugs were related to how position animation tracks were adjusted in rest fixer.
First bug: motion scale is applied before subtracting the origin when applying bone roll
Second bug: armature scale was lost when converting basis to quaternion, leading an unscaled position offset to be added to the scaled origin.
This commit is contained in:
Lyuma 2024-03-30 23:54:50 -07:00
parent 29b3d9e9e5
commit 00cf862b54
1 changed files with 46 additions and 41 deletions

View File

@ -436,42 +436,6 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
src_skeleton->set_motion_scale(motion_scale);
}
}
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
while (nodes.size()) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
List<StringName> anims;
ap->get_animation_list(&anims);
for (const StringName &name : anims) {
Ref<Animation> anim = ap->get_animation(name);
int track_len = anim->get_track_count();
for (int i = 0; i < track_len; i++) {
if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) {
continue;
}
if (anim->track_is_compressed(i)) {
continue; // Shouldn't occur in internal_process().
}
String track_path = String(anim->track_get_path(i).get_concatenated_names());
Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path));
ERR_CONTINUE(!node);
Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
if (!track_skeleton || track_skeleton != src_skeleton) {
continue;
}
real_t mlt = 1 / src_skeleton->get_motion_scale();
int key_len = anim->track_get_key_count(i);
for (int j = 0; j < key_len; j++) {
Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
anim->track_set_key_value(i, j, pos * mlt);
}
}
}
}
}
// Overwrite axis.
@ -587,22 +551,24 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
anim->track_set_key_value(i, j, new_pg_q.inverse() * old_pg_q * qt * old_rest_q.inverse() * old_pg_q.inverse() * new_pg_q * new_rest_q);
}
} else if (anim->track_get_type(i) == Animation::TYPE_SCALE_3D) {
Basis old_rest_b = old_rest.basis;
Basis old_rest_b_inv = old_rest.basis.inverse();
Basis new_rest_b = new_rest.basis;
Basis old_pg_b = old_pg.basis;
Basis new_pg_b = new_pg.basis;
Basis old_pg_b_inv = old_pg.basis.inverse();
Basis new_pg_b_inv = new_pg.basis.inverse();
for (int j = 0; j < key_len; j++) {
Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
anim->track_set_key_value(i, j, (new_pg_b.inverse() * old_pg_b * sc * old_rest_b.inverse() * old_pg_b.inverse() * new_pg_b * new_rest_b).get_scale());
anim->track_set_key_value(i, j, (new_pg_b_inv * old_pg_b * sc * old_rest_b_inv * old_pg_b_inv * new_pg_b * new_rest_b).get_scale());
}
} else {
Vector3 old_rest_o = old_rest.origin;
Vector3 new_rest_o = new_rest.origin;
Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
Basis old_pg_b = old_pg.basis;
Basis new_pg_b = new_pg.basis;
for (int j = 0; j < key_len; j++) {
Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
anim->track_set_key_value(i, j, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest_o)) + new_rest_o);
anim->track_set_key_value(i, j, new_pg_b.xform_inv(old_pg_b.xform(ps - old_rest_o)) + new_rest_o);
}
}
}
@ -637,6 +603,45 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
is_rest_changed = true;
}
// Scale position tracks by motion scale if normalize position tracks.
if (bool(p_options["retarget/rest_fixer/normalize_position_tracks"])) {
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
while (nodes.size()) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
List<StringName> anims;
ap->get_animation_list(&anims);
for (const StringName &name : anims) {
Ref<Animation> anim = ap->get_animation(name);
int track_len = anim->get_track_count();
for (int i = 0; i < track_len; i++) {
if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) {
continue;
}
if (anim->track_is_compressed(i)) {
continue; // Shouldn't occur in internal_process().
}
String track_path = String(anim->track_get_path(i).get_concatenated_names());
Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path));
ERR_CONTINUE(!node);
Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
if (!track_skeleton || track_skeleton != src_skeleton) {
continue;
}
real_t mlt = 1 / src_skeleton->get_motion_scale();
int key_len = anim->track_get_key_count(i);
for (int j = 0; j < key_len; j++) {
Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
anim->track_set_key_value(i, j, pos * mlt);
}
}
}
}
}
if (is_rest_changed) {
// Fix skin.
{