# Skill: Animation Retargeting (Kevin → BoZo) — DEPRECATED **DEPRECATED May 19, 2026.** BoZo and Kevin characters retired. Quaternius character system replaces them — no retargeting needed. This skill is kept for engine reference (Godot fork rest fixer fix). ```bash # 1. Clean import (creates default .import files) rm -f assets/animations/kevin/*.import assets/models/characters/Body/Body_BasicBody.fbx.import rm -f .godot/imported/Archer*.scn .godot/imported/Body_BasicBody*.scn .godot/imported/Villager*.scn .godot/imported/Throwing*.scn godot --headless --path . --import # 2. Patch .import files with BoneMap + retarget config godot --headless --path . -s setup_retarget.gd # 3. Delete cache + reimport with retarget config rm -f .godot/imported/Archer*.scn .godot/imported/Body_BasicBody*.scn .godot/imported/Villager*.scn .godot/imported/Throwing*.scn godot --headless --path . --import ``` IMPORTANT: Must delete `.godot/imported/*.scn` cache between steps 2→3, otherwise Godot skips reimport. ## What the pipeline does 1. **Bone renamer:** Renames Kevin bones (`B-hips` → `Hips`) and BoZo bones (`pelvis` → `Hips`) to Humanoid standard 2. **Overwrite Axis (method 1):** Changes skeleton rest poses to match SkeletonProfileHumanoid reference 3. **Animation conversion:** Transforms keyframe values from old rest coordinate system to new rest coordinate system using formula from `post_import_plugin_skeleton_rest_fixer.cpp:777`: ``` new_q = new_pg_q.inv * old_pg_q * qt * old_rest_q.inv * old_pg_q.inv * new_pg_q * new_rest_q ``` ## Known Bug (patched in tinqs/godot fork) **Commit:** `4e16c3f5bd` on `main` The `%GeneralSkeleton` unique node resolution via `get_node()` fails in headless import mode. Original code at line 733: ```cpp Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path)); ERR_CONTINUE(!node); // Silently skips ALL animation tracks! ``` **Fix:** Falls back to `find_child()` when unique name resolution fails. Without this fix, rest poses change but animation keyframe values stay in the old coordinate system. ## Current Status (2026-05-18) **Working:** - Bone renaming (Kevin → Humanoid, BoZo → Humanoid) ✓ - Rest pose overwrite to Humanoid reference ✓ - Skeleton node resolution fix (find_child fallback) ✓ - Animation conversion runs for spine/chest bones ✓ **NOT working:** - Animation conversion appears to be a NO-OP for limb bones (arms, legs) - Spine keys → near identity (correct). Arm/leg keys → near rest (unconverted) - Root cause: unknown. Possibly old_rest captured AFTER partial overwrite, or formula output matches input for bones with specific rest orientations **Visual symptoms:** - Arms cross behind back during animation - Legs may be double-rotated (rest * rest) - Spine animates correctly ## Bone Mapping ### Kevin → Humanoid | Humanoid | Kevin | |----------|-------| | Hips | B-hips | | Spine | B-spine | | Chest | B-chest | | UpperChest | B-upperChest | | Neck | B-neck | | Head | B-head | | LeftShoulder | B-shoulder.L | | LeftUpperArm | B-upper_arm.L | | LeftLowerArm | B-forearm.L | | LeftHand | B-hand.L | | Right* | B-*.R (mirror) | | LeftUpperLeg | B-thigh.L | | LeftLowerLeg | B-shin.L | | LeftFoot | B-foot.L | | LeftToes | B-toe.L | | Right* | B-*.R (mirror) | ### BoZo → Humanoid | Humanoid | BoZo | |----------|------| | Hips | pelvis | | Spine | spine_01 | | Chest | spine_03 | | UpperChest | spine_05 | | Neck | neck_01 | | Head | head | | LeftShoulder | clavicle_l | | LeftUpperArm | upperarm_l | | LeftLowerArm | lowerarm_l | | LeftHand | hand_l | | Right* | *_r (mirror) | | LeftUpperLeg | thigh_l | | LeftLowerLeg | calf_l | | LeftFoot | foot_l | | LeftToes | ball_l | | Right* | *_r (mirror) | BoZo intermediate bones (spine_02, spine_04, neck_02) have no Kevin equivalent and keep global rest. ## Key Files | File | Purpose | |------|---------| | `setup_retarget.gd` | Headless script: patches .import files with BoneMap + retarget config | | `run_retarget.gd` | EditorScript: same but runs inside Godot editor GUI | | `addons/retarget_setup/plugin.gd` | EditorPlugin: auto-runs on editor start | | `assets/retarget/kevin_bonemap.tres` | Kevin → Humanoid BoneMap resource | | `assets/retarget/bozo_bonemap.tres` | BoZo → Humanoid BoneMap resource | | `inspect_fbx.gd` | Debug: prints bone names, rest poses, animation values | | `src/Viewer/PlayerController.cs` | Character: loads animation, remaps %GeneralSkeleton paths | ## Godot Engine Source (for debugging) | File | What | |------|------| | `editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp` | Overwrite Axis + animation conversion | | `editor/import/3d/post_import_plugin_skeleton_renamer.cpp` | Bone renaming | | `scene/3d/retarget_modifier_3d.cpp` | Runtime retargeting (RetargetModifier3D) | | `scene/resources/bone_map.cpp` | BoneMap resource | | `scene/resources/skeleton_profile.cpp` | SkeletonProfile + Humanoid preset | ## What NOT to do 1. **Manual quaternion retargeting in C#** — tried 5 different formulas, all failed. The formula requires parent GLOBAL rest transforms for the entire bone chain. Only Godot's engine code handles this correctly. 2. **Rename BoZo bones at runtime** — breaks outfit/clothing FBX loading (bone name mismatch). 3. **BoneAttachment3D for head without inverse rest compensation** — double-transforms the head. 4. **Headless import without deleting .scn cache** — Godot skips reimport if source FBX unchanged.