From 88a0793bba5401985da23eea1e4815f3c8652e2f Mon Sep 17 00:00:00 2001 From: Zwitschi Date: Tue, 3 Nov 2026 11:44:55 +0100 Subject: [PATCH] Record the verified pose-capture recipe and the harness defect --- MEMORY.md | 14 ++++++++------ TODO.md | 13 +++++++------ docs/3d-model-review.md | 26 +++++++++++++++++--------- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/MEMORY.md b/MEMORY.md index 028ae68..aa00345 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -11,12 +11,14 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o direct `set_bone_pose_rotation` on HipL/KneeL/Spine/ShoulderL/ElbowL/Head changes rendered pixels; a bone *position* offset moves the head; a standalone probe running the same `_animate()` sequence renders the crouch. A staged in-game `film` frame also showed the arms - Standalone SceneTree probes (avatar under `root`, under a `Node3D` stage, and created - mid-`_process`) all render the seated crouch, so the rig and animation math are fine and the - harness capture path is the outlier. A headless test now locks the proxy→bone contract - (`test_pose_reaches_the_skeleton_bones`, suite 273). Next leads: reproduce the stage inside - `capture_npc_review.gd` (known-good captures) or capture via `SubViewport` + - `RenderingServer.force_draw()`. + Standalone SceneTree probes (avatar under `root`, under a `Node3D` stage, created + mid-`_process`) all render the seated crouch, and a `SubViewport` + `RenderingServer.force_draw()` + probe does too (window probes diff ~2,200-2,360; offscreen 602 at +2/+6/+12 frames, including a + re-created avatar). So the rig, the animation math and the offscreen path are sound; only + `capture_npc_pose.gd` still saves rest frames, which makes its phase/camera/force-draw ordering + the defect. A headless test locks the proxy→bone contract + (`test_pose_reaches_the_skeleton_bones`, suite 273). Rebuild the harness from the verified + recipe in `docs/3d-model-review.md` instead of iterating on the current phase machine. - **3D review baseline (2026-11-03):** `docs/3d-model-review.md` records the first skill-guided measurements: 46/46 assets clean, library 59,012 tris, characters 4,482–5,474 tris (68–69% of the 8,000 caps), `npc_base` only 1,204/2,488, 24-NPC 6.94 ms, and authored texel density diff --git a/TODO.md b/TODO.md index f3d81e8..35f9a4b 100644 --- a/TODO.md +++ b/TODO.md @@ -64,12 +64,13 @@ except the rebuilt assets themselves. frames still show the rest pose; direct bone writes deform the mesh, so this is a staging/ capture discrepancy that may also affect live venue frames. See `docs/3d-model-review.md` §"Pose evidence is blocked". -- [ ] Finish the pose-capture diagnosis. Done so far: the pose reaches proxies and skeleton - bones (new headless test, 273/273), direct bone rotations deform the rendered mesh, and - three standalone probes render the seated crouch — only `capture_npc_pose.gd` saves the - rest pose. Remaining leads: reproduce the stage inside `capture_npc_review.gd` (known to - render) or capture via `SubViewport` + `RenderingServer.force_draw()`, then add a scene - test that a posed avatar renders differently from its rest frame. +- [ ] Rebuild the pose harness from the verified recipe. Established: the pose reaches proxies + and bones (headless test, 273/273), direct bone rotations deform the mesh, and both window + probes and a `SubViewport` + `RenderingServer.force_draw()` probe render the crouch (offscreen + diff 602 at +2/+6/+12 frames, including a re-created avatar). The current harness still + saves rest frames, so its phase/camera/force-draw ordering is the remaining defect. Rebuild + one pose at a time using the recipe in `docs/3d-model-review.md`, verify each pose visually, + then wire the sheets and fill the weights/pose column. - [ ] UV/texel density: measure the 256² slot maps; decide whether atlas, UDIM or a resolution change is justified. Do not change `CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` without re-running the budget smoke and the Web/Compatibility path. diff --git a/docs/3d-model-review.md b/docs/3d-model-review.md index c23aeea..26adb2a 100644 --- a/docs/3d-model-review.md +++ b/docs/3d-model-review.md @@ -172,20 +172,28 @@ variants (full-body + shoulder views) and its output does not match the state it | Check | Result | | --- | --- | | Pose reaches proxies | Seated pose logs `rig_y=-0.339`, `leg0=-1.357` | -| Pose reaches skeleton bones | `Skeleton3D.get_bone_pose_rotation(HipL/KneeL)` differs from rest; new headless test `test_pose_reaches_the_skeleton_bones` locks it (suite 273/273) | +| Pose reaches skeleton bones | `HipL`/`KneeL` bone rotations differ from rest; headless test `test_pose_reaches_the_skeleton_bones` locks it (suite 273/273) | | Idle restores rest | Same test asserts the hip returns to its rest orientation | | Skinning bound | One `Skeleton3D`, mesh bound to it (`same=true`); hiding `npc_base` removes the body | | Bone rotations deform the mesh | Direct writes change rendered pixels: Spine 1,719 / HipL 1,052 / KneeL 810 / ElbowL 745 / Head 671 / ShoulderL 640 sampled pixels | | Bone translation deforms the mesh | A +0.5 m Head offset moves the head in frame | -| Standalone probes render the pose | Three variants (avatar under `root`, under a `Node3D` stage, created mid-`_process`) all render the seated crouch (`posed` vs rest diff ≈ 2,200–2,360 samples) | -| The harness renders the pose | **No.** All 8 variants × 4 poses save the rest pose while the logged state and bone poses are posed | +| Standalone window probes render the pose | Three variants (avatar under `root`, under a `Node3D` stage, created mid-`_process`) render the seated crouch (diff ~2,200-2,360 samples) | +| Offscreen capture renders the pose | A `SubViewport` + `RenderingServer.force_draw()` probe renders the crouch reliably (diff 602 at +2/+6/+12 frames), including a re-created second avatar | +| The harness renders the pose | **No** in its current form: same stage, same pose, rest frames. One ordering (`_frame_view()` immediately before `force_draw()`) produced posed walk frames once, then regressed to rest/garbage on the next run | -The cause is therefore in the harness's capture path, not in the rig or the animation math. Two -leads are left and both are cheap: reproduce the stage inside a harness that is known to render -correctly (`capture_npc_review.gd` already produces 96 valid frames), or capture through a -`SubViewport` with `RenderingServer.force_draw()` so the frame cannot lag the state. Until a -scene test asserts that a posed avatar renders differently from its rest frame, do not treat pose -sheets as evidence and do not claim rig deformation in the review. +The rig, the animation math and the offscreen render path are all sound. The remaining failure is +specific to the harness's frame/phase ordering around staging, camera framing and `force_draw()`. +Do not keep guessing: rebuild the harness from the working recipe below, one pose at a time, and +verify each pose before wiring up the sheets. + +Working recipe (verified by the probes; keep it when rebuilding): + +1. Create a `SubViewport` (1280x720, `own_world_3d = true`, `UPDATE_ALWAYS`) in `_initialize`. +2. Build the studio (environment, key/fill light, ground, camera) and one avatar inside it. +3. Wait 2-3 frames so the skinned mesh binds. +4. Apply the pose with `_animate()` ticks, with the avatar's process/physics disabled. +5. Call `RenderingServer.force_draw()`, then `viewport.get_texture().get_image()`. +6. Free the avatar and repeat for the next pose; a re-created avatar also rendered correctly in a probe. ## Ranked candidate gaps