Skip to content

Commit ca58715

Browse files
committed
Keep global rest of unmapped bones if no mapped bone descendants
1 parent 259d576 commit ca58715

File tree

1 file changed

+48
-7
lines changed

1 file changed

+48
-7
lines changed

editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ void PostImportPluginSkeletonRestFixer::get_internal_import_options(InternalImpo
4141
if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
4242
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/apply_node_transforms"), true));
4343
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/normalize_position_tracks"), true));
44-
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis"), true));
4544
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/reset_all_bone_poses_after_import"), true));
45+
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
46+
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/keep_global_rest_on_leftovers"), true));
4647
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/fix_silhouette/enable", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
4748
// TODO: PostImportPlugin need to be implemented such as validate_option(PropertyInfo &property, const Dictionary &p_options).
4849
// get_internal_option_visibility() is not sufficient because it can only retrieve options implemented in the core and can only read option values.
@@ -61,6 +62,8 @@ Variant PostImportPluginSkeletonRestFixer::get_internal_option_visibility(Intern
6162
return false;
6263
}
6364
}
65+
} else if (p_option == "retarget/rest_fixer/keep_global_rest_on_leftovers") {
66+
return bool(p_options["retarget/rest_fixer/overwrite_axis"]);
6467
}
6568
}
6669
return true;
@@ -460,6 +463,48 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
460463
old_skeleton_global_rest.push_back(src_skeleton->get_bone_global_rest(i));
461464
}
462465

466+
bool keep_global_rest_leftovers = bool(p_options["retarget/rest_fixer/keep_global_rest_on_leftovers"]);
467+
468+
// Scan hierarchy and populate a whitelist of unmapped bones without mapped descendants.
469+
Vector<int> keep_bone_rest;
470+
if (keep_global_rest_leftovers) {
471+
Vector<int> bones_to_process = src_skeleton->get_parentless_bones();
472+
while (bones_to_process.size() > 0) {
473+
int src_idx = bones_to_process[0];
474+
bones_to_process.erase(src_idx);
475+
Vector<int> src_children = src_skeleton->get_bone_children(src_idx);
476+
for (const int &src_child : src_children) {
477+
bones_to_process.push_back(src_child);
478+
}
479+
480+
StringName src_bone_name = is_renamed ? StringName(src_skeleton->get_bone_name(src_idx)) : bone_map->find_profile_bone_name(src_skeleton->get_bone_name(src_idx));
481+
if (src_bone_name != StringName() && !profile->has_bone(src_bone_name)) {
482+
// Scan descendants for mapped bones.
483+
bool found_mapped = false;
484+
485+
Vector<int> decendants_to_process = src_skeleton->get_bone_children(src_idx);
486+
while (decendants_to_process.size() > 0) {
487+
int desc_idx = decendants_to_process[0];
488+
decendants_to_process.erase(desc_idx);
489+
Vector<int> desc_children = src_skeleton->get_bone_children(desc_idx);
490+
for (const int &desc_child : desc_children) {
491+
decendants_to_process.push_back(desc_child);
492+
}
493+
494+
StringName desc_bone_name = is_renamed ? StringName(src_skeleton->get_bone_name(desc_idx)) : bone_map->find_profile_bone_name(src_skeleton->get_bone_name(desc_idx));
495+
if (desc_bone_name != StringName() && profile->has_bone(desc_bone_name)) {
496+
found_mapped = true;
497+
break;
498+
}
499+
}
500+
501+
if (!found_mapped) {
502+
keep_bone_rest.push_back(src_idx); // No mapped descendants. Add to whitelist.
503+
}
504+
}
505+
}
506+
}
507+
463508
Vector<Basis> diffs;
464509
diffs.resize(src_skeleton->get_bone_count());
465510
Basis *diffs_w = diffs.ptrw();
@@ -485,13 +530,9 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
485530
int prof_idx = profile->find_bone(src_bone_name);
486531
if (prof_idx >= 0) {
487532
tgt_rot = src_pg.inverse() * prof_skeleton->get_bone_global_rest(prof_idx).basis; // Mapped bone uses reference pose.
533+
} else if (keep_global_rest_leftovers && keep_bone_rest.has(src_idx)) {
534+
tgt_rot = src_pg.inverse() * old_skeleton_global_rest[src_idx].basis; // Non-Mapped bone without mapped children keeps global rest.
488535
}
489-
/*
490-
// If there is rest-relative animation, this logic may be work fine, but currently not so...
491-
} else {
492-
// tgt_rot = src_pg.inverse() * old_skeleton_global_rest[src_idx].basis; // Non-Mapped bone keeps global rest.
493-
}
494-
*/
495536
}
496537

497538
if (src_skeleton->get_bone_parent(src_idx) >= 0) {

0 commit comments

Comments
 (0)