diff --git a/docs/research/2026-06-19-lighting-a7-fixD-round2-torch-reach-CHECKPOINT.md b/docs/research/2026-06-19-lighting-a7-fixD-round2-torch-reach-CHECKPOINT.md new file mode 100644 index 00000000..94924439 --- /dev/null +++ b/docs/research/2026-06-19-lighting-a7-fixD-round2-torch-reach-CHECKPOINT.md @@ -0,0 +1,94 @@ +# A7 Fix D round 2 — REAL cause found (object sun+ambient + torch REACH), CHECKPOINT + +**Date:** 2026-06-19 **Branch:** `claude/thirsty-goldberg-51bb9b` (NOT merged — held at the visual gate) +**Predecessor:** `docs/research/2026-06-18-lighting-a7-fixABC-shipped-fixD-handoff.md` +**Status:** checkpointed at user request after pinning the root cause. D-1..D-4 are committed + +correct but **did NOT fix the visible symptom** — they were the wrong subsystem. + +## TL;DR — what the visible bug actually is (and is NOT) + +The user's symptom (Holtburg meeting-hall facade too bright/warm/washed-out + character backs +lit) is **NOT** the EnvCell bake, the per-channel clamp, the half-Lambert wrap, or the SSBO leak. +Those are the D-1..D-4 path. **The visible surfaces are mode-0 OBJECTS**, and the cause is: + +1. **Building facade over-bright** = the **torch REACH is too long** (acdream ~7.8 m vs retail + ~5.2 m), so each entrance torch floods the whole small facade instead of a tight pool. + **CONFIRMED by isolation**: gating object (mode-0) point lights OFF made the building match + retail ("looks much better", user 2026-06-19). +2. **Character backs / slight object over-bright** = the **sun + ambient on objects** (mode 0 + runs both). Ambient is NOT the culprit (it MATCHES retail exactly — see values). The residual + is small for the character (it ~matches retail), so the dominant visible bug is #1 (torches). + +## Render-path facts (source-verified, workflow `wf_c4ad8cf8`) + +- **Building EXTERIOR** = a flat-mesh `WorldEntity` with `IsBuildingShell=true`, `ParentCellId=null`, + built from `BuildingInfo.ModelId` (`LandblockLoader.cs:79-90`), drawn by **WbDrawDispatcher** + which hard-sets `uLightingMode=0` (`WbDrawDispatcher.cs:898`). It is **NOT an EnvCell** — so + **D-4 (EnvCell walls get no sun) never touched it**. +- **Characters/creatures/players** = ordinary `WorldEntity` dynamics, also drawn by + WbDrawDispatcher at `uLightingMode=0` (plain Lambert + sun). The mode plumbing is CORRECT + (mode-0 plain Lambert already zeroes a torch behind a back-face — that part of D-3 works). +- **EnvCellRenderer** (`uLightingMode=1`, no-sun, wrap) only ever draws **interior** cell shells + from the dat EnvCell list — never `info.Buildings`, never characters. +- Render loop: in-world frames go through `RetailPViewRenderer.DrawInside`; the bare + `WbDrawDispatcher.Draw` (GameWindow.cs:8230) is the no-viewer-cell fallback. Both share the + ONE `_meshShader` (mesh_modern) program (GameWindow.cs:1845-1857), so `uLightingMode` is one + shared uniform; each renderer re-sets it before its draws. + +## Ground truth (live cdb retail + acdream probe, SAME-INSTANT) + +- **Ambient MATCHES exactly**: acdream `(0.447,0.447,0.495)` == retail `(0.4465,0.4465,0.4951)`. + → same sky keyframe → **same time of day; NO time desync** (the earlier "retail 0.3 / acdream + purple" was sequential-capture drift + acdream's un-synced spawn frame; ignore it). +- **retail sun** (`world_lights.sunlight` @ 0x008672a0+0x18) = `(0.573, ~0, 0.445)`, magnitude + **0.725**, colour `(0.98,0.84,0.59)` warm. acdream `sun=1` (active, derived from the same sky + state via Fix C `|sunVec|=DirBright`). Sun is NOT zero — retail DOES sun-light objects. +- **retail torches** (golden, a7-fixd-golden2): static, `intensity=100`, `falloff 3/4/5`, warm + `(1,0.588,0.314)` orange + `(0.98,0.843,0.612)` cream. `calc_point_light` makes a BRIGHT TIGHT + pool (saturates to full warm to ~4 m, gone by ~5.2 m). Faithful in acdream (LightBake.cs). +- **acdream torches** ([light-detail]): `range=7.8` (Falloff 6×1.3) and `range=6.5` (Falloff 5). + acdream `Range = info.Falloff * 1.3f` (`LightInfoLoader.cs:90`) — the 1.3 is correct, NO stray 1.5. + +## The OPEN question to resolve FIRST on resume (don't guess) + +acdream's orange torch reads **Falloff 6** (range 7.8); retail's orange torch was captured at +**Falloff 4** (range 5.2). `6 = 4 × 1.5` (smells like rangeAdjust) BUT they **might be different +torches** (38 static torches, several orange). **Resolve by comparing the SAME torch's Falloff in +acdream vs retail, matched by world position** (one focused capture): break/dump acdream's torch +Falloff for a specific Holtburg torch and the retail `world_lights.static_lights[i].info.falloff` +for the same one. Then: +- If acdream reads a **too-large Falloff** for the same torch → fix the dat read / conversion + (the DatReaderWriter `LightInfo.Falloff` path) so acdream's reach == retail's. +- If the Falloff matches and reach is genuinely ~7.8 → the building-shell-as-one-object spill is + the issue; tighten how building shells receive torches (the per-vertex range gate already + localises, so this is unlikely — favour the Falloff hypothesis). + +## Proposed fix (after the falloff is confirmed) + +Tighten acdream's torch reach to match retail (≈5 m), keep torches ON. Building facade then shows +a tight warm pool by each flame + dark stone elsewhere (retail-faithful). Files: `LightInfoLoader.cs` +(the Falloff→Range conversion), possibly the DatReaderWriter light read. Add a divergence-register +row if any conversion deviates. Re-verify visually (the diagnostic that confirmed the cause: +object point lights OFF == retail-match). + +## State of the committed work (KEEP — all correct, just off-target for the visible bug) + +| Commit | What | Verdict | +|---|---|---| +| `180b4af` | D-1 clamp point sum on its own | faithful; keep | +| `39c70f0` | D-2 prep — LightBake conformance test | keep | +| `cf62793` | D-1 shader clamp | keep | +| `c62da82` | D-2 EnvCell shell binds own light set (real leak fix) | keep | +| `b57a53e`/`156dc45` | register AP-35/AP-16 corrections | keep | +| `0980bea` | D-3 objects plain-Lambert / D-4 EnvCell no-sun | keep; correct but doesn't touch the building (it's an object) | + +`tools/cdb/a7-fixd-*.cdb` capture scripts are committed. **Diagnostic shader hack reverted** +(working tree clean). Branch NOT merged — finish the torch-reach fix, visual-verify, then merge. + +## DO-NOT-RETRY (cost a lot this session) + +- Don't re-tune the EnvCell bake / per-channel clamp / wrap / SSBO binding for the building — the + building is a mode-0 OBJECT, none of that path lights it. +- Don't chase a time-of-day / ambient desync — ambient + time MATCH retail exactly (0.446). +- Don't "remove the sun" globally — retail DOES sun-light objects (sun 0.725). +- The visible building bug is the **torch REACH** (confirmed by isolation); start there.