Add rest fixer toggle to disable bone pose reset

Adds a "Reset All Bone Poses After Import" option to the Skeleton3D Rest Fixer settings.
Default value of true resets the bone poses to rest (usually a t-pose), matching previous behavior.
If disabled, keeps the bones posed as they would have been before silhouette adjustment.
This commit is contained in:
Lyuma 2024-02-25 02:26:54 -08:00
parent 2e7fc81315
commit 6a6bd2307c

View file

@ -42,6 +42,7 @@ void PostImportPluginSkeletonRestFixer::get_internal_import_options(InternalImpo
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/apply_node_transforms"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/normalize_position_tracks"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/reset_all_bone_poses_after_import"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/fix_silhouette/enable"), false));
// TODO: PostImportPlugin need to be implemented such as validate_option(PropertyInfo &property, const Dictionary &p_options).
// get_internal_option_visibility() is not sufficient because it can only retrieve options implemented in the core and can only read option values.
@ -113,6 +114,10 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
Vector<int> bones_to_process = src_skeleton->get_parentless_bones();
for (int i = 0; i < bones_to_process.size(); i++) {
src_skeleton->set_bone_rest(bones_to_process[i], global_transform.orthonormalized() * src_skeleton->get_bone_rest(bones_to_process[i]));
src_skeleton->set_bone_pose_position(bones_to_process[i], global_transform.orthonormalized().xform(src_skeleton->get_bone_pose_position(bones_to_process[i])));
src_skeleton->set_bone_pose_rotation(bones_to_process[i], global_transform.basis.get_rotation_quaternion() * src_skeleton->get_bone_pose_rotation(bones_to_process[i]));
src_skeleton->set_bone_pose_scale(bones_to_process[i], (global_transform.orthonormalized().basis * Basis().scaled(src_skeleton->get_bone_pose_scale((bones_to_process[i])))).get_scale());
}
while (bones_to_process.size() > 0) {
@ -123,6 +128,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
bones_to_process.push_back(src_children[i]);
}
src_skeleton->set_bone_rest(src_idx, Transform3D(src_skeleton->get_bone_rest(src_idx).basis, src_skeleton->get_bone_rest(src_idx).origin * scl));
src_skeleton->set_bone_pose_position(src_idx, src_skeleton->get_bone_pose_position(src_idx) * scl);
}
// Fix animation.
@ -603,6 +609,30 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
}
if (p_options.has("retarget/rest_fixer/reset_all_bone_poses_after_import") && !bool(p_options["retarget/rest_fixer/reset_all_bone_poses_after_import"])) {
// If Reset All Bone Poses After Import is disabled, preserve the original bone pose, adjusted for the new bone rolls.
for (int bone_idx = 0; bone_idx < src_skeleton->get_bone_count(); bone_idx++) {
Transform3D old_rest = old_skeleton_rest[bone_idx];
Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx);
Transform3D old_pg;
Transform3D new_pg;
int parent_idx = src_skeleton->get_bone_parent(bone_idx);
if (parent_idx >= 0) {
old_pg = old_skeleton_global_rest[parent_idx];
new_pg = src_skeleton->get_bone_global_rest(parent_idx);
}
Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
Quaternion qt = src_skeleton->get_bone_pose_rotation(bone_idx);
src_skeleton->set_bone_pose_rotation(bone_idx, new_pg_q.inverse() * old_pg_q * qt * old_rest.basis.get_rotation_quaternion().inverse() * old_pg_q.inverse() * new_pg_q * new_rest.basis.get_rotation_quaternion());
Basis sc = Basis().scaled(src_skeleton->get_bone_pose_scale(bone_idx));
src_skeleton->set_bone_pose_scale(bone_idx, (new_pg.basis.inverse() * old_pg.basis * sc * old_rest.basis.inverse() * old_pg.basis.inverse() * new_pg.basis * new_rest.basis).get_scale());
Vector3 ps = src_skeleton->get_bone_pose_position(bone_idx);
src_skeleton->set_bone_pose_position(bone_idx, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest.origin)) + new_rest.origin);
}
}
is_rest_changed = true;
}
@ -669,12 +699,14 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
// Init skeleton pose to new rest.
for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
Transform3D fixed_rest = src_skeleton->get_bone_rest(i);
src_skeleton->set_bone_pose_position(i, fixed_rest.origin);
src_skeleton->set_bone_pose_rotation(i, fixed_rest.basis.get_rotation_quaternion());
src_skeleton->set_bone_pose_scale(i, fixed_rest.basis.get_scale());
if (!p_options.has("retarget/rest_fixer/reset_all_bone_poses_after_import") || bool(p_options["retarget/rest_fixer/reset_all_bone_poses_after_import"])) {
// Init skeleton pose to new rest.
for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
Transform3D fixed_rest = src_skeleton->get_bone_rest(i);
src_skeleton->set_bone_pose_position(i, fixed_rest.origin);
src_skeleton->set_bone_pose_rotation(i, fixed_rest.basis.get_rotation_quaternion());
src_skeleton->set_bone_pose_scale(i, fixed_rest.basis.get_scale());
}
}
}