acdream/tools/cdb/a7-fixd-lights.cdb
Erik c407104ab9 docs(lighting): A7 Fix D investigation RESOLVED + implementation spec (#140)
Resolve the Fix D contradiction with decomp (workflow wf_f660eb88 + adversarial
verify) + 4 live cdb captures. The D3D-FF model was the WRONG oracle: retail has
TWO light systems — STATIC torches BAKE into wall vertices (calc_point_light,
triple-clamped: range gate + per-channel min(scale*color,color) + per-vertex
[0,1] from black), DYNAMIC lights go D3D hardware. The captured intensity=100 is
the purple PORTAL (magenta, dynamic), not a wall torch. Ground truth: 38 static
warm torches (orange (1,0.588,0.314)/cream, intensity=100, falloff 3-5) + 2 dynamic.

acdream over-brightness = two confirmed bugs: D-1 mesh_modern.vert folds
ambient+sun+torches into one UNCLAMPED accumulator (single frag clamp) -> warm
blowout; D-2 EnvCellRenderer never binds SSBO 4/5 so the cell shell reads a leaked
light set. Spec: D-1 in-shader clamp-split (clamp the torch sum on its own before
ambient/sun); D-2 bind the shell's own per-cell light set (mirror WbDrawDispatcher);
LightBake.cs is the C# conformance oracle. Adds the 4 reusable cdb capture scripts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 17:08:27 +02:00

50 lines
3 KiB
Text

$$
$$ A7 Fix D (#140) — wall-torch vs portal light OWNERSHIP + the actual LIGHTINFO
$$ values that feed the EnvCell wall bake. 2026-06-18.
$$
$$ Decomp already settled the render path (workflow wf_f660eb88):
$$ STATIC lights -> CPU per-vertex bake (SetStaticLightingVertexColors ->
$$ calc_point_light), DOUBLE-clamped (per-light min(scale*color,color) +
$$ per-vertex [0,1]) -> walls stay DIM even at intensity=100.
$$ DYNAMIC lights -> D3D hardware FF (minimize_envcell_lighting).
$$ Render::insert_light copies intensity VERBATIM to BOTH paths, so the only
$$ open empirical question is: which light carries intensity=100, and what do
$$ the actual wall-torch LIGHTINFOs look like (intensity/falloff/color)?
$$
$$ CLASSIFICATION via config_hardware_light's d3dLightIndex (arg1 @ [esp+4]):
$$ add_dynamic_light base index = 1 -> dynamic idx in [1..10] (viewer light / teleport PORTAL)
$$ add_static_light base index = 11 -> static idx in [11..70] (WALL TORCHES, baked)
$$
$$ config_hardware_light(d3dIndex, _D3DLIGHT9* out, ulong cellID, LIGHTINFO* info):
$$ d3dIndex = dwo(@esp+4) ; LIGHTINFO* = poi(@esp+0x10) (PROVEN last session)
$$ add_static_light / add_dynamic_light(LIGHTINFO* info, cellID, Frame* offset):
$$ LIGHTINFO* = poi(@esp+4)
$$ `dt acclient!LIGHTINFO <ptr> type intensity falloff color` resolves the
$$ float fields symbolically (PDB types) -> readable values, no hex reinterp.
$$
$$ USAGE: with retail in-world standing in/near the Holtburg meeting hall by a
$$ wall torch, WALK around the hall (and past the teleport portal if present)
$$ for ~15 s so static torch sets re-register. Auto-detaches (qd) after 600
$$ total hits, leaving retail running.
.logopen C:\Users\erikn\source\repos\acdream\.claude\worktrees\thirsty-goldberg-51bb9b\a7-fixd-lights-capture.log
.sympath C:\Users\erikn\source\repos\acdream\refs
.symopt+ 0x40
.reload /f acclient.exe
r $t0 = 0
r $t1 = 0
r $t2 = 0
r $t3 = 0
$$ BP1: config_hardware_light — EVERY light (static+dynamic); d3dIdx classifies.
bp acclient!PrimD3DRender::config_hardware_light "r $t0=@$t0+1; r $t1=@$t1+1; .printf /D \"[CHL] hit#%d d3dIdx=%d (1-10=DYNAMIC portal/viewer, 11+=STATIC torch)\\n\", @$t1, dwo(@esp+4); dt acclient!LIGHTINFO dwo(@esp+0x10) type intensity falloff color; .if (@$t0 >= 600) { qd } .else { gc }"
$$ BP2: add_static_light — every hit is a WALL TORCH (baked path).
bp acclient!Render::add_static_light "r $t0=@$t0+1; r $t2=@$t2+1; .printf /D \"[STATIC torch] hit#%d\\n\", @$t2; dt acclient!LIGHTINFO dwo(@esp+4) type intensity falloff color; .if (@$t0 >= 600) { qd } .else { gc }"
$$ BP3: add_dynamic_light — viewer light + teleport PORTAL (hardware path).
bp acclient!Render::add_dynamic_light "r $t0=@$t0+1; r $t3=@$t3+1; .printf /D \"[DYNAMIC light] hit#%d\\n\", @$t3; dt acclient!LIGHTINFO dwo(@esp+4) type intensity falloff color; .if (@$t0 >= 600) { qd } .else { gc }"
.printf "a7-fixd-lights armed: BP1 CHL (classify via d3dIdx), BP2 STATIC=torch, BP3 DYNAMIC=portal/viewer. qd after 600 total hits.\\n"
g