BlueGit

golden-age paperdoll-renderer

design: depth_encoding enum gray/rgb_bands/rgb_packed x depth_bits 8/16 (t987u)

timfa Grok Bot · pushed by timfa

Authored 2026-11-07 · 7 days ago

Hash
49baef40e50124dcae3a73c57f349fa62869a1df
Parent
5f4672e7
Pipeline
Passed
1 file changed +6 −5
design.md +6 −5
@@ -409,9 +409,10 @@ Implementation (2026-11-07): the build folder is `renders/inprogress-<stamp>-<pi
409 409
410 410 Supersedes the `R = half render height + |pivot − centre|` rule. (1) The default per-sex depth range is the **T-pose arm span** (fingertip to fingertip, measured in the bind pose) **plus one arm length of margin on each side**, centred on the pivot depth: `total = span + 2·arm`, `near = D − total/2`, `far = D + total/2` (camera distance D = 10 m). This covers the model in any rotation plus long weapons. Span = horizontal extent of the bind-pose body vertices; arm = (span − shoulder width)/2 with the shoulder width taken from the left/right upper-arm/shoulder joints when they can be identified by name, otherwise arm = 0.4·span (documented fallback, also for static bodies). Geometry still outside the range is clamped and reported (progress + `complete.json` `depth_clamped`). (2) The range is configurable per sex in the `.ppd` (`depth_range_milli`: optional total range in millimetres, centred on the pivot) and editable in the GUI next to framing ("Dieptebereik", with an "automatisch" choice). It stays fixed for all frames, views and equipment of that sex and is stored in `render.json` and `.ppda` `depth_near`/`depth_far`; readers use the recorded values (validated: finite, 0 < near < far, equal to identity near/far) instead of recomputing them.
411 411
412 ## Decision 2026-11-07 (Tim t980u, amended t981u/t983u): depth bit depth + optional RGB band encoding
412 ## Decision 2026-11-07 (Tim t980u, amended t981u/t983u/t987u): depth bit depth + depth encoding
413 413
414 Two project settings in `.ppd`: `depth_bits` = **8 (default)** or 16, and the boolean `depth_rgb_bands`, default **off**. This changes the default export: depth becomes 8-bit unless 16 is chosen. Four combinations, with M = 2^bits − 1 (255 or 65535) and `t = (d − near)/(far − near)` clamped to 0..1:
415 - `gray8` (default) / `gray16`: gray+alpha PNG at that bit depth, `gray = round(t·M)`, decode `d = near + (gray/M)·(far − near)`.
416 - `rgb-bands8` / `rgb-bands16`: RGBA PNG at that bit depth, `v = round(t·3M)`, `R = min(v, M)`, `G = clamp(v − M, 0, M)`, `B = clamp(v − 2M, 0, M)`, alpha kept; decode `v = R + G + B`, `d = near + (v/3M)·(far − near)` (3M+1 levels; 766 at 8-bit).
417 `render.json` and the `.ppda` record `depth_bits` and `depth_encoding` (`gray` or `rgb-bands`), so the game renderer and the 2D previewer decode all four; the previewer/compositor support all four. Older `.ppda` files without `depth_bits` are read as gray16 (their actual format). Both settings are part of the render contract (changing them is a contract difference for resume).
414 Two project settings in `.ppd` (`render`): `depth_bits` = **8 (default)** or 16, and `depth_encoding` = **`gray` (default)**, `rgb_bands` or `rgb_packed`. The default export is therefore 8-bit gray. With M = 2^bits − 1 (255 or 65535), B = 2^bits and `t = (d − near)/(far − near)` clamped to 0..1:
415 - `gray`: gray+alpha PNG at that bit depth, `gray = round(t·M)`; decode `t = gray/M`.
416 - `rgb_bands`: RGBA PNG at that bit depth, `v = round(t·3M)`, `R = min(v, M)`, `G = clamp(v − M, 0, M)`, `B = clamp(v − 2M, 0, M)`; decode `t = (R+G+B)/(3M)` (3M+1 levels; 766 at 8-bit).
417 - `rgb_packed`: RGBA PNG at that bit depth, positional base B over three channels: `v = round(t·(B³ − 1))`, `R = v / B²`, `G = (v / B) mod B`, `B = v mod B` (8-bit: 24-bit value, `R = v>>16`, `G = (v>>8)&255`, `B = v&255`; 16-bit: 48-bit value); decode `t = (R·B² + G·B + Bc)/(B³ − 1)`. **rgb_packed requires nearest sampling, no mipmaps/filtering and lossless storage** (no texture compression); any interpolation between texels or lossy compression corrupts the value.
418 Alpha is always kept (scaled to the bit depth). Distance = near + t·(far − near). `render.json` and the `.ppda` record `depth_bits` and `depth_encoding`, so the game renderer and the 2D previewer decode all six combinations; the previewer/compositor support all of them. Older `.ppda`/`render.json` without `depth_bits` are read as 16-bit gray (their actual format). Both settings are part of the render contract (changing them is a contract difference for resume).
@@ -409,9 +409,10 @@ Implementation (2026-11-07): the build folder is `renders/inprogress-<stamp>-<pi
409
409
410Supersedes the `R = half render height + |pivot − centre|` rule. (1) The default per-sex depth range is the **T-pose arm span** (fingertip to fingertip, measured in the bind pose) **plus one arm length of margin on each side**, centred on the pivot depth: `total = span + 2·arm`, `near = D − total/2`, `far = D + total/2` (camera distance D = 10 m). This covers the model in any rotation plus long weapons. Span = horizontal extent of the bind-pose body vertices; arm = (span − shoulder width)/2 with the shoulder width taken from the left/right upper-arm/shoulder joints when they can be identified by name, otherwise arm = 0.4·span (documented fallback, also for static bodies). Geometry still outside the range is clamped and reported (progress + `complete.json` `depth_clamped`). (2) The range is configurable per sex in the `.ppd` (`depth_range_milli`: optional total range in millimetres, centred on the pivot) and editable in the GUI next to framing ("Dieptebereik", with an "automatisch" choice). It stays fixed for all frames, views and equipment of that sex and is stored in `render.json` and `.ppda` `depth_near`/`depth_far`; readers use the recorded values (validated: finite, 0 < near < far, equal to identity near/far) instead of recomputing them.
410Supersedes the `R = half render height + |pivot − centre|` rule. (1) The default per-sex depth range is the **T-pose arm span** (fingertip to fingertip, measured in the bind pose) **plus one arm length of margin on each side**, centred on the pivot depth: `total = span + 2·arm`, `near = D − total/2`, `far = D + total/2` (camera distance D = 10 m). This covers the model in any rotation plus long weapons. Span = horizontal extent of the bind-pose body vertices; arm = (span − shoulder width)/2 with the shoulder width taken from the left/right upper-arm/shoulder joints when they can be identified by name, otherwise arm = 0.4·span (documented fallback, also for static bodies). Geometry still outside the range is clamped and reported (progress + `complete.json` `depth_clamped`). (2) The range is configurable per sex in the `.ppd` (`depth_range_milli`: optional total range in millimetres, centred on the pivot) and editable in the GUI next to framing ("Dieptebereik", with an "automatisch" choice). It stays fixed for all frames, views and equipment of that sex and is stored in `render.json` and `.ppda` `depth_near`/`depth_far`; readers use the recorded values (validated: finite, 0 < near < far, equal to identity near/far) instead of recomputing them.
411
411
412## Decision 2026-11-07 (Tim t980u, amended t981u/t983u): depth bit depth + optional RGB band encoding
412## Decision 2026-11-07 (Tim t980u, amended t981u/t983u/t987u): depth bit depth + depth encoding
413
413
414Two project settings in `.ppd`: `depth_bits` = **8 (default)** or 16, and the boolean `depth_rgb_bands`, default **off**. This changes the default export: depth becomes 8-bit unless 16 is chosen. Four combinations, with M = 2^bits − 1 (255 or 65535) and `t = (d − near)/(far − near)` clamped to 0..1:
414Two project settings in `.ppd` (`render`): `depth_bits` = **8 (default)** or 16, and `depth_encoding` = **`gray` (default)**, `rgb_bands` or `rgb_packed`. The default export is therefore 8-bit gray. With M = 2^bits − 1 (255 or 65535), B = 2^bits and `t = (d − near)/(far − near)` clamped to 0..1:
415- `gray8` (default) / `gray16`: gray+alpha PNG at that bit depth, `gray = round(t·M)`, decode `d = near + (gray/M)·(far − near)`.
415- `gray`: gray+alpha PNG at that bit depth, `gray = round(t·M)`; decode `t = gray/M`.
416- `rgb-bands8` / `rgb-bands16`: RGBA PNG at that bit depth, `v = round(t·3M)`, `R = min(v, M)`, `G = clamp(v − M, 0, M)`, `B = clamp(v − 2M, 0, M)`, alpha kept; decode `v = R + G + B`, `d = near + (v/3M)·(far − near)` (3M+1 levels; 766 at 8-bit).
416- `rgb_bands`: RGBA PNG at that bit depth, `v = round(t·3M)`, `R = min(v, M)`, `G = clamp(v − M, 0, M)`, `B = clamp(v − 2M, 0, M)`; decode `t = (R+G+B)/(3M)` (3M+1 levels; 766 at 8-bit).
417`render.json` and the `.ppda` record `depth_bits` and `depth_encoding` (`gray` or `rgb-bands`), so the game renderer and the 2D previewer decode all four; the previewer/compositor support all four. Older `.ppda` files without `depth_bits` are read as gray16 (their actual format). Both settings are part of the render contract (changing them is a contract difference for resume).
417- `rgb_packed`: RGBA PNG at that bit depth, positional base B over three channels: `v = round(t·(B³ − 1))`, `R = v / B²`, `G = (v / B) mod B`, `B = v mod B` (8-bit: 24-bit value, `R = v>>16`, `G = (v>>8)&255`, `B = v&255`; 16-bit: 48-bit value); decode `t = (R·B² + G·B + Bc)/(B³ − 1)`. **rgb_packed requires nearest sampling, no mipmaps/filtering and lossless storage** (no texture compression); any interpolation between texels or lossy compression corrupts the value.
418Alpha is always kept (scaled to the bit depth). Distance = near + t·(far − near). `render.json` and the `.ppda` record `depth_bits` and `depth_encoding`, so the game renderer and the 2D previewer decode all six combinations; the previewer/compositor support all of them. Older `.ppda`/`render.json` without `depth_bits` are read as 16-bit gray (their actual format). Both settings are part of the render contract (changing them is a contract difference for resume).