Narrow the pose-harness root cause: skinned mesh ignores its Rig parent
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped

This commit is contained in:
zwitschi committed 2026-11-03 19:26:07 +01:00
1 parent 1afd97c72d
commit a677a95d13
3 files changed
+23 -11

No files matched your search

+8
View File
@@ -705,6 +705,14 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
(`smoke_props.gd`); the NPC FSM re-writes `rotation.y` every physics tick, so pose/portrait (`smoke_props.gd`); the NPC FSM re-writes `rotation.y` every physics tick, so pose/portrait
captures set the yaw after `set_physics_process(false)`; and `visible = false` does not keep the captures set the yaw after `set_physics_process(false)`; and `visible = false` does not keep the
crowd out of a portrait frame (park the rest of the crowd away instead). crowd out of a portrait frame (park the rest of the crowd away instead).
- Pose capture blocked — root cause narrowed (2026-11-03 re-attempt): rebuilding the harness with
the recipe (SubViewport + `RenderingServer.force_draw()` + `force_update_all_bone_transforms()`
+ disabled avatar process/physics) still produced byte-identical rest frames. Decisive probe:
teleporting the **avatar** (CharacterBody3D) changes the render (diff 10), but moving the
**`Rig` child** (the GLB model's parent) does not (diff 0) — the skinned mesh does not follow the
`Rig` Node3D transform, so the rig lowering (`rig_y=-0.339`) never reaches the rendered model.
The failure is upstream of capture ordering. Do not re-attempt the recipe; next attempt must
answer why the skinned model ignores its `Rig` parent, or stage poses via `capture_npc_review.gd`.
- Blender tooling: `bisect_plane` and thin bevels leave zero-area triangles (Godot warns - Blender tooling: `bisect_plane` and thin bevels leave zero-area triangles (Godot warns
"non-finite normal in LOD generation"); `_clean()` + a weld after bisect fix them and the audit "non-finite normal in LOD generation"); `_clean()` + a weld after bisect fix them and the audit
rejects them. rejects them.
+7 -7
View File
@@ -110,13 +110,13 @@ licence-free zone only.
frames still show the rest pose; direct bone writes deform the mesh, so this is a staging/ 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 capture discrepancy that may also affect live venue frames. See
`docs/3d-model-review.md` §"Pose evidence is blocked". `docs/3d-model-review.md` §"Pose evidence is blocked".
- [ ] Rebuild the pose harness from the verified recipe. Established: the pose reaches proxies - [ ] Rebuild the pose harness. **Re-attempt 2026-11-03 narrowed the root cause:** the recipe
and bones (headless test, 273/273), direct bone rotations deform the mesh, and both window (SubViewport + `force_draw()` + `force_update_all_bone_transforms()` + disabled process/physics)
probes and a `SubViewport` + `RenderingServer.force_draw()` probe render the crouch (offscreen still produced byte-identical rest frames. Decisive probe: teleporting the avatar renders
diff 602 at +2/+6/+12 frames, including a re-created avatar). The current harness still (diff 10) but moving the `Rig` child does not (diff 0) — the skinned mesh ignores its `Rig`
saves rest frames, so its phase/camera/force-draw ordering is the remaining defect. Rebuild parent transform, so `rig_y=-0.339` never reaches the render. Next attempt must answer why
one pose at a time using the recipe in `docs/3d-model-review.md`, verify each pose visually, the skinned model ignores the `Rig` node, or stage poses via the known-good
then wire the sheets and fill the weights/pose column. `capture_npc_review.gd` fallback.
- [ ] UV/texel density: measure the 256² slot maps; decide whether atlas, UDIM or a resolution - [ ] 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 change is justified. Do not change `CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` without re-running the
budget smoke and the Web/Compatibility path. budget smoke and the Web/Compatibility path.
+8 -4
View File
@@ -181,10 +181,14 @@ variants (full-body + shoulder views) and its output does not match the state it
| 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 | | 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 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 rig, the animation math and the offscreen render path are all sound. The remaining failure is The rig, the animation math and the offscreen render path are all sound. A 2026-11-03 re-attempt
specific to the harness's frame/phase ordering around staging, camera framing and `force_draw()`. with the recipe (SubViewport + `force_draw()` + `force_update_all_bone_transforms()` + disabled
Do not keep guessing: rebuild the harness from the working recipe below, one pose at a time, and process/physics) still produced byte-identical rest frames, and a decisive probe narrowed the
verify each pose before wiring up the sheets. failure further: teleporting the **avatar** changes the render (diff 10), but moving the **`Rig`
child** (the GLB model's parent) does not (diff 0). The skinned mesh therefore does not follow its
`Rig` Node3D transform, so the rig lowering never reaches the rendered model — the defect is
upstream of camera/`force_draw()` ordering. Next attempt must answer why the skinned model ignores
the `Rig` node, or stage poses via the known-good `capture_npc_review.gd` fallback.
Working recipe (verified by the probes; keep it when rebuilding): Working recipe (verified by the probes; keep it when rebuilding):