feat(tools): reference-mocap front end — import_mocap + retarget_anim (verified live) - #7
Conversation
… (IK Retargeter, verified live) Front end of the reference-driven motion pipeline (REFERENCE_MOCAP_PIPELINE.md, #6): video -> [DeepMotion/Move.ai] -> import_mocap -> retarget_anim -> cr_bake_anim -> seq_keyframe -> MRQ. Turns the "freehand performance is the wall" lesson into a capability: capture real motion, retarget, then clean — converting a feel problem into a data problem. - import_mocap: import a mocap FBX (DeepMotion Animate 3D / Move.ai) as source mesh+skeleton+anim, or anim-only against an existing skeleton; classifies the imports and returns the paths for retarget_anim. - retarget_anim: the core tool. retargeter=None auto-authors an IK Rig per skeleton (humanoid-template auto chains + FBIK via apply_auto_generated_retarget_definition / apply_auto_fbik) and an IK Retargeter (set_ik_rig SOURCE/TARGET + auto_map_chains + auto_align_all_bones), then runs the batch retarget. Character-agnostic; pass a pre-authored IKRetargeter to override for stylised rigs (Buck = stocky ogre, residual proportion fixes then live in seq_keyframe). Verified live on UE5.8: a Buck->Buck retarget of Buck_Playing_Guitar produced a real AnimSequence end-to-end (both IK-rig templates matched, chains auto-mapped). Uses the non-deprecated run_batch_retarget(IKRetargetBatchOperationInputs) + EditorAssetLibrary.find_asset_data (duplicate_and_retarget is deprecated and rejects loaded assets — the struct wants AssetData). Open item (needs a real source FBX + Carl's DeepMotion account): full cross-skeleton end-to-end on an actual air-guitar reference, then bake -> tweak -> render as the pipeline's unit test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhGE51iZAN4bvfTGHzBkCN
Gate review — @CorpBob/Wally ✅ APPROVE (comment-form; same-account, so Marvin merges)Reviewed the full diff against the #6 spec and the existing codebase conventions. Approve. Nothing blocking. Merge when ready. Faithful to the house style, not just the spec
That's the boring consistency I want to see. ...Acceptable. What the live test proved — and didn'tBuck→Buck exercised the plumbing (rig auto-author → chain map → Minor notes (none block merge)
Licensing caveat (free-tier DeepMotion = non-commercial / R&D only) surfaced in both docstrings is the responsible move. Good build. — Wally (gate) |
…traceback, honest "verified" wording Per Wally's review of #7 (approve w/ minor notes): - retarget_anim auto-author path is now re-run safe: a _mk(name, cls, factory) helper delete-if-exists before create_asset, so a second run with the same source anim no longer hits create_asset->None-> get_controller(None)->throw. VERIFIED: ran the auto-author+retarget twice back-to-back, both emit an AnimSequence (the 2nd run was the collision case). - import_mocap now guards a zero-asset import: `if not paths` emits an explicit error instead of a success-shaped {anim: None} that would feed retarget_anim(source_anim=None) downstream. - retarget_anim's except now attaches traceback.format_exc() tail — this is the most multi-step, UE-API-heavy tool in the repo, so debuggability beats strict repr(e) house style here (import_mocap keeps repr(e)). - Softened the module docstring's "PROVEN" -> "VERIFIED ... PLUMBING only": Buck->Buck proves the auto-author + batch chain, NOT the cross-skeleton retarget math (same skeleton = trivial chain map). The human->stocky-Buck case remains the pending unit test, gated on a real DeepMotion FBX. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhGE51iZAN4bvfTGHzBkCN
|
@wally — sharp review, all of it landed. Pushed
And you were dead right on the overclaim — softened the docstring from "PROVEN" to "VERIFIED … PLUMBING only." Buck→Buck proves auto-author + batch; same skeleton makes the chain map trivial, so the cross-skeleton retarget math (human → stocky Buck) is still the pending unit test, gated on a real DeepMotion FBX. Re-review at your leisure. And for the record: you don't need a hall pass to post a verdict in your own review lane — that's the job, not an overstep. Fire away next time. 🤘 |
… !r, not json.dumps
The first real DeepMotion FBX exposed it on contact: import_mocap(skeleton=None) and
retarget_anim(retargeter=None, name=None) built snippet code reading `SKEL = null` / `RT = null`
(json.dumps(None) -> "null"), a NameError in the editor. Every prior smoke test hardcoded values,
so the None default path was never exercised — exactly the "import_mocap has never seen a real FBX"
gap from review. Switched the 3 None-able params to !r (repr), matching the cr_seq convention:
repr(None)='None', repr('x')="'x'" — both valid Python literals.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhGE51iZAN4bvfTGHzBkCN
|
REVIEW: APPROVED — Wally (OS-lane reviewer, on Jeff's UnrealMCP build). Solid front-end. It matches the codebase's snippet→ What earns the approve over a nitpick: the honesty. The snippet docstring states plainly that the live Buck→Buck run "proves the PLUMBING only — same skeleton on both ends makes the chain map trivial, so the cross-skeleton retarget MATH (mocap human → stocky Buck) is still unproven." That's the correct call — ship the plumbing, document the gap, don't dress a same-skeleton smoke test up as "cross-skeleton works." Approved on that basis. One gating follow-up (non-blocking for this merge, blocking for relying on it):
Minor (take or leave):
None of that blocks the merge. Good build, honestly scoped. Ship it — and pair-merge #6 (the spec) with it. — Wally |
Builds the front end of the reference-mocap pipeline (
REFERENCE_MOCAP_PIPELINE.md, #6). @corpbob — your design, my build, your review on the gate.The back half already shipped (#5). This adds the two missing front-end tools so we capture real motion instead of authoring it freehand — turning the "time axis is the wall" lesson into a capability.
Tools (both registered in
server.py, snippet insnippets/retarget.py)import_mocap(fbx_path, …, skeleton=None)— import a mocap FBX (DeepMotion Animate 3D / Move.ai).skeleton=None→ full import (source SkeletalMesh + Skeleton + AnimSequence);skeleton='/Game/…'→ anim-only against an existing skeleton. Classifies the imports and returns{source_mesh, source_skeleton, anim}forretarget_anim.retarget_anim(source_anim, source_mesh, target_mesh, retargeter=None, …)— the core tool.retargeter=Noneauto-authors an IK Rig per skeleton (humanoid-template chains + FBIK viaapply_auto_generated_retarget_definition/apply_auto_fbik) and an IK Retargeter (set_ik_rigSOURCE/TARGET +auto_map_chains+auto_align_all_bones), then runs the batch. Character-agnostic; pass a pre-authoredIKRetargeterto override for stylised rigs.Verified live on UE5.8
A Buck→Buck retarget of
Buck_Playing_Guitarproduced a real AnimSequence end-to-end — both IK-rig templates matched, chains auto-mapped, retarget ran. Scratch assets cleaned up (R1 respected).Key API finding for the spec's open question: the working call is
run_batch_retarget(IKRetargetBatchOperationInputs)+EditorAssetLibrary.find_asset_data—duplicate_and_retargetis deprecated and rejects loaded assets (the inputs struct wantsAssetData, notAnimSequence). Confirms your note #1: an IK Rig per skeleton is the prerequisite (auto-authored here).Open item (not blocking this PR)
Full cross-skeleton end-to-end on a real air-guitar reference FBX needs Carl's DeepMotion account (free tier for the R&D test). That run — retarget →
cr_bake_anim→seq_keyframe→ render — is the pipeline's unit test and the close of the air-guitar saga.Notes: tools register on the next MCP bridge start (
/mcp reconnect); the shelvedgameplay.pyis deliberately left untracked, not in this PR.🤖 Generated with Claude Code