BlueGit

golden-age paperdoll-renderer

design: rest-pose centre pivot supersedes neck pivot; weaker live perspective (Tim t1008u)

timfa Grok Bot · pushed by timfa

Authored 2026-11-07 · 6 days ago

Hash
418294c6f19f83b290faae94c8384c1cce0287d7
Parent
9d6b740e
Pipeline
Passed
1 file changed +9 −0
design.md +9 −0
@@ -520,3 +520,12 @@ Decision (superseded and reverted per Tim t991u, see below): automatic per-body
520 520 ## Decision 2026-11-07 (Tim t1007u): every material per primitive, live preview equals production
521 521
522 522 A glTF body keeps one material per primitive. The live 3D preview draws each primitive range with its own base color factor × base color texture and its own alpha cutoff, exactly like production (which already did); it never merges the materials into one color or drops textures. External image URIs (next to the `.gltf`) are resolved like embedded and `data:` images. Factors are applied as loaded (no correction); production multiplies in linear space and stores sRGB diffuse, the live view stays a simplified lit view. Regression: `tests/fixtures/bodies/multi-material/` (external `.bin`, two external PNGs, three materials: factor only, texture, texture × factor), a unit test on the live GPU frame, a GPU probe case and the `textured_body_fixture` example, which checks all three material colors in the production diffuse.
523
524 ## Decision 2026-11-07 (Tim t1008u): orbit pivot at the rest-pose vertical centre; weaker live perspective
525
526 Supersedes the neck pivot of t952u (the fixed framing itself is unchanged).
527
528 - **Pivot.** `pivot_y_milli = None` now resolves to the vertical centre of the model's rest-pose bounds (`(min Y + max Y) / 2` of all rest-pose vertices), not the neck joint. Reason: around the neck the feet swing far along the view axis at pitch ±60 and leave the 8-bit depth range. An explicit `pivot_y_milli` stays a manual override; a model without finite geometry falls back to `center_y_milli` with a diagnostic. The neck-name detection is removed. `pivot_source.kind` in `render.json`/`.ppda` identity becomes `bounds_center` (with `min_y_milli`/`max_y_milli`); `manual` and `fallback` are unchanged, and the readers still accept the legacy `neck` kind of older exports. The UI button **Auto centre** clears a manual pivot.
529 - **Depth range.** Unchanged rule (T-pose span plus one arm length per side, or a manual total), centred on the orbit pivot at camera distance 10, so it now follows the new pivot depth.
530 - **Perspective.** Production renders and the fixed render frame in the live view are orthographic, i.e. already the limit of "infinitely far and zoomed in": there is no perspective to weaken, the camera distance does not change the image, and no `.ppd` setting is added. Only the free live view (fixed frame unchecked) is perspective; it now sits 2.5× further away with a narrowed field of view (`2·atan(tan(19°)/2.5)` ≈ 15.4° instead of 38°), so the on-screen size stays the same with weaker perspective.
531 - **Check.** A GPU production render of Tim's `maleb.glb`/`femaleb.glb` with his framing must report 0 clamped depth pixels at 8 bit for all pitches including ±60; `depth_clamp_probe` cross-checks per pitch on the CPU.
@@ -520,3 +520,12 @@ Decision (superseded and reverted per Tim t991u, see below): automatic per-body
520## Decision 2026-11-07 (Tim t1007u): every material per primitive, live preview equals production
520## Decision 2026-11-07 (Tim t1007u): every material per primitive, live preview equals production
521
521
522A glTF body keeps one material per primitive. The live 3D preview draws each primitive range with its own base color factor × base color texture and its own alpha cutoff, exactly like production (which already did); it never merges the materials into one color or drops textures. External image URIs (next to the `.gltf`) are resolved like embedded and `data:` images. Factors are applied as loaded (no correction); production multiplies in linear space and stores sRGB diffuse, the live view stays a simplified lit view. Regression: `tests/fixtures/bodies/multi-material/` (external `.bin`, two external PNGs, three materials: factor only, texture, texture × factor), a unit test on the live GPU frame, a GPU probe case and the `textured_body_fixture` example, which checks all three material colors in the production diffuse.
522A glTF body keeps one material per primitive. The live 3D preview draws each primitive range with its own base color factor × base color texture and its own alpha cutoff, exactly like production (which already did); it never merges the materials into one color or drops textures. External image URIs (next to the `.gltf`) are resolved like embedded and `data:` images. Factors are applied as loaded (no correction); production multiplies in linear space and stores sRGB diffuse, the live view stays a simplified lit view. Regression: `tests/fixtures/bodies/multi-material/` (external `.bin`, two external PNGs, three materials: factor only, texture, texture × factor), a unit test on the live GPU frame, a GPU probe case and the `textured_body_fixture` example, which checks all three material colors in the production diffuse.
523
524## Decision 2026-11-07 (Tim t1008u): orbit pivot at the rest-pose vertical centre; weaker live perspective
525
526Supersedes the neck pivot of t952u (the fixed framing itself is unchanged).
527
528- **Pivot.** `pivot_y_milli = None` now resolves to the vertical centre of the model's rest-pose bounds (`(min Y + max Y) / 2` of all rest-pose vertices), not the neck joint. Reason: around the neck the feet swing far along the view axis at pitch ±60 and leave the 8-bit depth range. An explicit `pivot_y_milli` stays a manual override; a model without finite geometry falls back to `center_y_milli` with a diagnostic. The neck-name detection is removed. `pivot_source.kind` in `render.json`/`.ppda` identity becomes `bounds_center` (with `min_y_milli`/`max_y_milli`); `manual` and `fallback` are unchanged, and the readers still accept the legacy `neck` kind of older exports. The UI button **Auto centre** clears a manual pivot.
529- **Depth range.** Unchanged rule (T-pose span plus one arm length per side, or a manual total), centred on the orbit pivot at camera distance 10, so it now follows the new pivot depth.
530- **Perspective.** Production renders and the fixed render frame in the live view are orthographic, i.e. already the limit of "infinitely far and zoomed in": there is no perspective to weaken, the camera distance does not change the image, and no `.ppd` setting is added. Only the free live view (fixed frame unchecked) is perspective; it now sits 2.5× further away with a narrowed field of view (`2·atan(tan(19°)/2.5)` ≈ 15.4° instead of 38°), so the on-screen size stays the same with weaker perspective.
531- **Check.** A GPU production render of Tim's `maleb.glb`/`femaleb.glb` with his framing must report 0 clamped depth pixels at 8 bit for all pitches including ±60; `depth_clamp_probe` cross-checks per pitch on the CPU.