fix #176: light pool tracked the camera via flood scoping - collect residents, anchor at player
The seam-floor purple flicker was NOT a draw z-fight. The in-engine
[seam-*] probe (ACDREAM_PROBE_SEAMDRAW - built because RenderDoc cannot
capture this pipeline: it hides GL_ARB_bindless_texture and the
mandatory-modern startup gate throws; AMD GPU rules out Nsight) killed
every double-draw suspect: ONE shell instance per seam cell at the
lifted z, no floor-coincident entity (portal entities sit at z=-12.05),
zero portal depth fans in the sealed Hub. What it caught instead: the
corridor floor's applied light set flipping wholesale with the flood.
Root cause: c500912b scoped BuildPointLightSnapshot by the per-frame
portal flood, on the research doc's gloss of CEnvCell::visible_cell_table
as "the portal-flood visible set". The named decomp refutes the gloss:
add_visible_cell (0x0052de40) DBObj-LOADS absent cells and inserts them;
a cell activation adds itself + its whole dat visible-cell list
(0x0052e228/0x0052e24a); entries leave only via the flush machinery.
It is the RESIDENT-cell registry - gaze can never remove a cell.
add_dynamic_lights (0x0052d410) walks the WHOLE table per frame
(caller 0x00452d30), and insert_light (0x0054d1b0) caps the pool by
distance to Render::player_pos (0x0054d1dd). Retail's pool is a function
of player position only. Ours followed the camera: turning changed the
flood (probe: 8..41 cells across one turn), the six intensity-100
under-room portal purples entered/left the pool, and the wedge blinked.
Fix: BuildPointLightSnapshot(playerWorldPos) collects ALL registered
(=resident) lit lights; over cap keeps dynamics FIRST (retail's separate
7-slot dynamic pool never competes with statics) then nearest-the-player;
the RebuildScopedLights callback is deleted. Live-verified with the probe:
full-circle turn, flood churning 8..41, the floor set held the same 8
identities on every post-spawn frame. The purple wedge SHAPE stays - it
is cdb-proven retail-faithful.
Residual deviation (AP-85 rewritten): single 128 pool vs retail's
7-dynamic/40-static degrade-scaled dual pools - the Hub now shows
7 purples + viewer where retail's cdb showed 4 + viewer + fixture slots;
if the gate reads the wedge as too purple, the A7 dual-pool cap is the
faithful trim.
Pins: PointSnapshot_HubScaleLightCount_ObjectSelectionIsCameraInvariant
(rewritten to the corrected model),
PointSnapshot_OverCap_DynamicsNeverEvictedByNearerStatics,
PointSnapshot_OverCap_KeepsNearestThePlayer,
PointSnapshot_ResidentCollection_CellTagDoesNotFilter.
Suites: Core 2599+2skip / App 726+2skip / UI 425 / Net 385.
The [seam-*] probes stay until the visual gate passes, then strip.
Correction banner added to 2026-07-06-a7-per-cell-lighting-pseudocode.md;
outcome banner on the z-fight handoff; ISSUES #176 updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8cb3176daa
commit
d8984e877f
12 changed files with 525 additions and 194 deletions
|
|
@ -9103,7 +9103,12 @@ public sealed class GameWindow : IDisposable
|
|||
// camera UBO set for point/spot lights so a wall's torches stay tied to
|
||||
// the wall as the camera moves. The SUN + ambient still flow through the
|
||||
// SceneLighting UBO built below (binding=1) — terrain/sky read those.
|
||||
Lighting.BuildPointLightSnapshot(camPos);
|
||||
// #176 root cause: the pool is anchored at the PLAYER (retail
|
||||
// Render::insert_light sorts by Render::player_pos, 0x0054d1b0) and
|
||||
// collected from ALL registered (=resident-cell) lights — it is a
|
||||
// function of player position only, so camera rotation cannot change
|
||||
// it. playerViewPos carries retail's no-player fallback (camPos).
|
||||
Lighting.BuildPointLightSnapshot(playerViewPos);
|
||||
_wbDrawDispatcher?.SetSceneLights(Lighting.PointSnapshot);
|
||||
_envCellRenderer?.SetPointSnapshot(Lighting.PointSnapshot); // A7 Fix D (D-2)
|
||||
|
||||
|
|
@ -9409,11 +9414,10 @@ public sealed class GameWindow : IDisposable
|
|||
CellLookup = id => _cellVisibility.TryGetCell(id, out var c) ? c : null,
|
||||
Camera = camera,
|
||||
CameraWorldPosition = camPos,
|
||||
// A7 #176/#177: once DrawInside has resolved the visible-cell set,
|
||||
// rebuild the point-light pool from ONLY those cells' lights (retail's
|
||||
// per-frame add_*_lights over visible_cell_table). The renderers hold a
|
||||
// reference to the same PointSnapshot list, rebuilt in place here.
|
||||
RebuildScopedLights = visible => Lighting.BuildPointLightSnapshot(camPos, visible),
|
||||
// (#176 correction: the former RebuildScopedLights callback —
|
||||
// rebuilding the light pool from the frame's FLOOD — was the
|
||||
// flicker mechanism and is deleted. The pool is built once per
|
||||
// frame above, player-anchored, from all resident lights.)
|
||||
Frustum = frustum,
|
||||
PlayerLandblockId = playerLb,
|
||||
AnimatedEntityIds = animatedIds,
|
||||
|
|
@ -11511,6 +11515,22 @@ public sealed class GameWindow : IDisposable
|
|||
world[v].Z += AcDream.App.Rendering.PortalVisibilityBuilder.ShellDrawLiftZ;
|
||||
}
|
||||
|
||||
// #176 seam-draw probe: a sealed dungeon must emit ZERO depth fans
|
||||
// (only OtherCellId==0xFFFF portals reach here) — any line in a
|
||||
// target cell is a finding (a depth stamp fighting the shell floor).
|
||||
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeSeamDrawEnabled
|
||||
&& AcDream.Core.Rendering.RenderingDiagnostics.SeamDrawTargetCells.Contains(sliceCtx.CellId))
|
||||
{
|
||||
float seamZMin = float.MaxValue, seamZMax = float.MinValue;
|
||||
for (int v = 0; v < n; v++)
|
||||
{
|
||||
seamZMin = System.Math.Min(seamZMin, world[v].Z);
|
||||
seamZMax = System.Math.Max(seamZMax, world[v].Z);
|
||||
}
|
||||
Console.WriteLine(System.FormattableString.Invariant(
|
||||
$"[seam-mask] t={System.Environment.TickCount64} cell=0x{sliceCtx.CellId:X8} portal={i} far={forceFarZ} n={n} z=[{seamZMin:F3},{seamZMax:F3}]"));
|
||||
}
|
||||
|
||||
_portalDepthMask.DrawDepthFan(world[..n], viewProjection, sliceCtx.Slice.Planes, forceFarZ);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue