fix(import): skeleton rest fixer animation conversion in headless mode
The %GeneralSkeleton unique node resolution via get_node() fails during headless import (--import flag), causing ALL animation tracks to be silently skipped by ERR_CONTINUE. Rest poses get overwritten but animation keyframe values stay in the old coordinate system, producing incorrect bone orientations (e.g., arms crossed behind back). Fix: fall back to find_child() when unique name resolution fails. Added extensive logging for retarget debugging. Tinqs fork v1.0.1 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -730,13 +730,34 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// [TINQS] Fix: %UniqueNode resolution fails in headless/import context.
|
||||
// Fall back to find_child when get_node fails (e.g., headless --import).
|
||||
Node *node = nullptr;
|
||||
Node *anim_root = ap->get_node_or_null(ap->get_root_node());
|
||||
if (anim_root) {
|
||||
node = anim_root->get_node_or_null(NodePath(track_path));
|
||||
}
|
||||
if (!node && track_path.begins_with(UNIQUE_NODE_PREFIX)) {
|
||||
// Unique name resolution failed — try direct child search.
|
||||
String skel_name = track_path.substr(1); // Strip % prefix.
|
||||
node = p_base_scene->find_child(skel_name, true, false);
|
||||
if (node) {
|
||||
print_verbose(vformat("[RetargetRestFixer] Resolved '%s' via find_child fallback -> '%s'", track_path, node->get_name()));
|
||||
} else {
|
||||
WARN_PRINT(vformat("[RetargetRestFixer] Failed to resolve skeleton node '%s' — animation keyframes will NOT be converted to new rest pose. This may cause incorrect bone orientations.", track_path));
|
||||
}
|
||||
}
|
||||
if (!node) {
|
||||
WARN_PRINT(vformat("[RetargetRestFixer] Skipping track %d: cannot resolve node path '%s' from AnimationPlayer root.", i, track_path));
|
||||
continue;
|
||||
}
|
||||
|
||||
Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
|
||||
if (!track_skeleton ||
|
||||
(is_using_modifier && track_skeleton != profile_skeleton && track_skeleton != orig_skeleton) ||
|
||||
(!is_using_modifier && track_skeleton != src_skeleton)) {
|
||||
print_verbose(vformat("[RetargetRestFixer] Skipping track %d: skeleton mismatch (found '%s', expected src_skeleton).", i, node->get_name()));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -746,6 +767,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
|
||||
}
|
||||
|
||||
int bone_idx = src_skeleton->find_bone(bn);
|
||||
print_verbose(vformat("[RetargetRestFixer] Converting track %d bone '%s' (idx=%d) — %d keys", i, bn, bone_idx, anim->track_get_key_count(i)));
|
||||
|
||||
if (is_using_modifier) {
|
||||
int prof_idx = profile->find_bone(bn);
|
||||
|
||||
Reference in New Issue
Block a user