fix(lighting): A7 Fix D round 2 — outdoor objects get NO torches (retail useSunlight gate) (#140)
The Holtburg meeting-hall facade washed out warm/bright vs retail. The round-1 checkpoint blamed torch REACH (acdream Falloff 6×1.3=7.8m vs a supposed retail Falloff 4). That theory is WRONG, and this commit fixes the real cause. Empirical (HoltburgTorchFalloffProbeTests, headless dat dump via the production LightInfoLoader): the orange entrance torch (setup 0x020005D8) is raw dat Falloff 6 and acdream reads it FAITHFULLY — there is no Falloff-4 torch anywhere in Holtburg. Both clients read the same dat float, so reach was never inflated. Decomp (read verbatim + corroborated by an independent adversarial workflow): retail's per-object torch binder minimize_object_lighting (0x0054d480) is gated in RenderDeviceD3D::DrawMeshInternal (0x0059f398) by `if (Render::useSunlight == 0)`. The outdoor landscape stage runs useSunlightSet(1) (PView::DrawCells 0x005a485a, before LScape::draw), so the building EXTERIOR shell — drawn via DrawBlock→DrawSortCell→DrawBuilding→CPhysicsPart::Draw→DrawMeshInternal — is lit by SUN + ambient ONLY; torches are SKIPPED. The static bake (SetStaticLightingVertexColors 0x0059cfe0) is EnvCell-only. So retail NEVER torch-lights outdoor objects. This exactly explains the isolation test (object point lights OFF → building matches retail). Fix: WbDrawDispatcher.ComputeEntityLightSet gates per-object torch selection on the object being INDOOR (ParentCellId is an EnvCell, (id&0xFFFF)>=0x0100) via the pure predicate IndoorObjectReceivesTorches. Outdoor objects (building shells with null ParentCellId, outdoor scenery, outdoor creatures) keep the all-(-1) light set ⇒ sun + ambient only = retail. The indoor "no sun" half is already handled by the global sun-kill when the player is inside a cell (UpdateSunFromSky). No dungeon regression: EnvCell statics get ParentCellId set (keep torches). Divergence register: AP-37 (residual: acdream keys sun/torch on the object's own cell + a per-frame player-inside sun-kill, vs retail's per-draw-stage useSunlight; only matters for through-doorway look-ins). The round-1 CHECKPOINT got a RESOLVED banner correcting the reach theory. Tests: WbDrawDispatcherTorchGateTests (7), HoltburgTorchFalloffProbeTests (dat dump). App 280/1skip, Core 1486/2skip green. Held at the visual gate — not merged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1e6fbff9bc
commit
b7d655bce7
5 changed files with 254 additions and 0 deletions
|
|
@ -5,6 +5,64 @@
|
|||
**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.
|
||||
|
||||
---
|
||||
|
||||
## ✅ RESOLVED 2026-06-19 (second session) — the "torch REACH" theory was WRONG; real cause = retail does NOT torch-light OUTDOOR objects at all
|
||||
|
||||
**The open question is settled, and it overturns this checkpoint's own hypothesis. The fix is NOT
|
||||
"shorten torch reach" — it is "outdoor objects receive NO torches."**
|
||||
|
||||
**Empirical (acdream side, headless dat dump `HoltburgTorchFalloffProbeTests`):** the Holtburg
|
||||
neighbourhood has **27 static lights, raw dat Falloff ∈ {3,5,6}** — the dominant orange entrance
|
||||
torch (setup `0x020005D8`, colour `(1,0.588,0.314)`) is **Falloff 6** (17 of 27). acdream reads
|
||||
this **faithfully** — `LightInfoLoader` just copies `info.Falloff`, no stray ×1.5. There is **NO
|
||||
Falloff-4 torch anywhere in Holtburg**, so the predecessor's "retail orange = falloff 4" could not
|
||||
be a *different* falloff-4 torch. Both clients read the same dat float → acdream's reach is NOT
|
||||
inflated. So "acdream 6 vs retail 4" was a red herring.
|
||||
|
||||
**Decomp (retail side, read verbatim + corroborated by an independent adversarial workflow
|
||||
`wf_07289ba4`):** retail's per-object torch binder `minimize_object_lighting` (0x0054d480) is
|
||||
**gated** in `RenderDeviceD3D::DrawMeshInternal` (0x0059f398) by `if (Render::useSunlight == 0)`.
|
||||
The OUTDOOR landscape stage runs `Render::useSunlightSet(1)` (`PView::DrawCells` 0x005a485a, right
|
||||
before `LScape::draw`), so when the building EXTERIOR shell is drawn
|
||||
(`LScape::draw → DrawBlock 0x005a17c0 → DrawSortCell 0x0059f140 → DrawBuilding 0x0059f2a0 →
|
||||
CPhysicsPart::Draw → DrawMeshInternal`), torches are **SKIPPED** — the only active light is the
|
||||
**sun** (`useSunlightSet(1)` enables `add_active_light(0xffffffff, 0)` = sun + ambient only). The
|
||||
static vertex bake (`SetStaticLightingVertexColors` 0x0059cfe0) is **EnvCell-only** (sole caller
|
||||
`DrawEnvCell` 0x0059f1f6). **So retail lights outdoor objects with SUN + ambient ONLY — never the
|
||||
wall torches.** This exactly explains the checkpoint's own isolation result ("object point lights
|
||||
OFF → building matches retail"): retail's outdoor facade gets ZERO torch energy. (Confirming the
|
||||
non-bug nature of reach: retail's free-object *hardware* path `config_hardware_light` 0x0059ad30
|
||||
uses `Range = falloff × rangeAdjust(1.5)` = LONGER than acdream's ×1.3, with `Diffuse = color×100`
|
||||
and att `1/d` — that would blow the facade WHITE if enabled, which is further proof retail never
|
||||
enables it outdoors.)
|
||||
|
||||
**The three retail lighting regimes (now all mapped):**
|
||||
1. **EnvCell walls** → static bake (`calc_point_light`, range `falloff×1.3`, wrap, capped), no sun.
|
||||
→ acdream mode 1 (EnvCell). ✓ already correct.
|
||||
2. **Indoor objects** (`useSunlight==0`) → torches (hardware, no sun). → acdream mode 0 **indoor**.
|
||||
3. **Outdoor objects** (`useSunlight==1`) → sun + ambient, **NO torches**. → acdream mode 0 **outdoor**.
|
||||
acdream's mode-0 path applied sun **AND** torches to ALL objects — wrong for both 2 and 3.
|
||||
|
||||
**THE FIX (shipped this session):** in `WbDrawDispatcher.ComputeEntityLightSet`, gate per-object
|
||||
torch selection on the object being INDOOR (`ParentCellId` is an EnvCell, `(id&0xFFFF)>=0x0100`)
|
||||
via the pure predicate `IndoorObjectReceivesTorches`. Outdoor objects (building shells — ParentCellId
|
||||
null; outdoor scenery; outdoor creatures) keep the all-(-1) light set ⇒ sun + ambient only = retail.
|
||||
The indoor "no sun" half is already handled by the global sun-kill when the player is inside a cell
|
||||
(`UpdateSunFromSky`, intensity 0). Divergence-register row **AP-37** added (documents the residual:
|
||||
acdream keys sun/torch on the object's own cell + a per-frame player-inside sun-kill, vs retail's
|
||||
per-draw-STAGE `useSunlight` — only matters for through-doorway look-ins). Tests:
|
||||
`WbDrawDispatcherTorchGateTests` (7✓), `HoltburgTorchFalloffProbeTests` (dat dump). Build green;
|
||||
App 280✓/1skip, Core 1486✓/2skip. **Awaiting the user visual side-by-side at Holtburg before merge.**
|
||||
|
||||
**DO-NOT-RETRY (this session's corrections to the checkpoint below):** do NOT shorten torch reach /
|
||||
change `Falloff×1.3` — acdream reads the dat faithfully and the bake reach is correct for EnvCells.
|
||||
The building is an OUTDOOR object; retail gives it no torches. The original checkpoint's "tighten reach
|
||||
to ~5m, keep torches ON" plan (below) is SUPERSEDED — keeping torches ON for the outdoor shell at any
|
||||
reach is the bug.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue