revert #176/#177 cap raise: the uncapped light pool exposes unported per-cell reach semantics — defer to A7
The MaxGlobalLights 128->1024 fix (4d25e04d) was live-tested and made
the eviction pops stop — but with the full 366-fixture pool active,
three unported retail lighting semantics dominate the Facility Hub:
(a) lights reach THROUGH solid floors/walls: retail registers lights
per-CELL (insert_light 0x0054d1b0) so the under-room portals'
purple light never touches the corridor above; our flat
sphere-overlap selection has no reach/occlusion notion — rooms
washed magenta (user screenshot).
(b) stationary weenie fixtures ride the DYNAMIC 1/d falloff (~9x
retail's static 1/d3 bake curve at 3m) — the #143 isDynamic
assignment is wrong for ACE-served world fixtures.
(c) an unexplained striped z-fight-like artifact on lit floor regions
(user screenshot; no coincident dat geometry — the coplanar-pair
sweep came back empty; not a striped texture — all corridor
surfaces are plain Base1Image stone).
Reverted to 128. The cap is now documented as a LOAD-BEARING STOPGAP:
it accidentally approximates per-cell reach by keeping the pool local
to the camera. The #176/#177 root cause (cap eviction popping per-cell
light sets) stays CONFIRMED and fully documented; the real fix is the
A7 dungeon-lighting arc: per-cell light registration + the static
fixture curve + the stripe hunt, THEN uncap. The desired-end-state pin
is kept as Skip with the full pointer. Register row AP-85 rewritten to
match reality; ISSUES #176/#177 back to OPEN with the complete
mechanism story.
Suites: Core 2591+3skip / App 719 green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
4d25e04d83
commit
d591e3bbe5
5 changed files with 169 additions and 48 deletions
|
|
@ -233,6 +233,94 @@ public class Issue176177DungeonSeamInspectionTests
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #176 THE STRIPES (user screenshot, 2026-07-06 evening): a floor region
|
||||
/// z-fights in regular bands between a purple-lit copy and an unlit copy —
|
||||
/// two COINCIDENT DRAWN surfaces with different per-cell light sets. This
|
||||
/// sweep hunts the pair in the dat: every pair of DRAWN polys across the
|
||||
/// corridor neighborhood that is coplanar AND overlapping in area. Before
|
||||
/// the light-cap fix both copies were usually equally unlit (the purple
|
||||
/// portal light was cap-evicted) so the fight was invisible; the stable
|
||||
/// light exposed it.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void CorridorNeighborhood_CoplanarOverlappingDrawnPolyPairs()
|
||||
{
|
||||
var datDir = ResolveDatDir();
|
||||
if (datDir is null) { _out.WriteLine("SKIP: no dat dir"); return; }
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
|
||||
// Seed cells around the screenshot location (the 016E/017A seam) +
|
||||
// one portal ring.
|
||||
var cellIds = new HashSet<uint> { 0x8A020165u, 0x8A02016Eu, 0x8A02017Au };
|
||||
foreach (var seed in new List<uint>(cellIds))
|
||||
{
|
||||
var seedCell = dats.Get<EnvCell>(seed);
|
||||
if (seedCell is null) continue;
|
||||
foreach (var p in seedCell.CellPortals)
|
||||
cellIds.Add(0x8A020000u | p.OtherCellId);
|
||||
}
|
||||
|
||||
// Collect all DRAWN polys world-space per cell.
|
||||
var drawn = new List<(uint CellId, ushort PolyId, Vector3 N, float D,
|
||||
Vector3 Min, Vector3 Max, uint SurfaceId)>();
|
||||
foreach (var cellId in cellIds)
|
||||
{
|
||||
var loaded = LoadCell(dats, cellId);
|
||||
if (loaded is null) continue;
|
||||
var (cell, cs) = loaded.Value;
|
||||
var world = WorldTransform(cell);
|
||||
|
||||
foreach (var (id, poly) in cs.Polygons)
|
||||
{
|
||||
if (!WouldDraw(poly, cell)) continue;
|
||||
var w = WorldVerts(cs, poly, world);
|
||||
if (w.Count < 3) continue;
|
||||
var n = Vector3.Normalize(Vector3.Cross(w[1] - w[0], w[2] - w[0]));
|
||||
float d = Vector3.Dot(n, w[0]);
|
||||
var min = new Vector3(float.MaxValue); var max = new Vector3(float.MinValue);
|
||||
foreach (var v in w) { min = Vector3.Min(min, v); max = Vector3.Max(max, v); }
|
||||
uint surfaceId = 0x08000000u | (uint)cell.Surfaces[poly.PosSurface];
|
||||
drawn.Add((cellId, id, n, d, min, max, surfaceId));
|
||||
}
|
||||
}
|
||||
_out.WriteLine($"cells={cellIds.Count} drawnPolys={drawn.Count}");
|
||||
|
||||
int pairs = 0;
|
||||
for (int i = 0; i < drawn.Count; i++)
|
||||
{
|
||||
for (int j = i + 1; j < drawn.Count; j++)
|
||||
{
|
||||
var a = drawn[i]; var b = drawn[j];
|
||||
if (a.CellId == b.CellId && a.PolyId == b.PolyId) continue;
|
||||
|
||||
float align = Vector3.Dot(a.N, b.N);
|
||||
if (MathF.Abs(align) < 0.999f) continue;
|
||||
float dB = align > 0 ? b.D : -b.D;
|
||||
if (MathF.Abs(a.D - dB) > 0.02f) continue; // same plane within 2 cm
|
||||
|
||||
// Overlap in world AABB, with meaningful area in the plane.
|
||||
float ox = MathF.Min(a.Max.X, b.Max.X) - MathF.Max(a.Min.X, b.Min.X);
|
||||
float oy = MathF.Min(a.Max.Y, b.Max.Y) - MathF.Max(a.Min.Y, b.Min.Y);
|
||||
float oz = MathF.Min(a.Max.Z, b.Max.Z) - MathF.Max(a.Min.Z, b.Min.Z);
|
||||
if (ox < 0.05f || oy < 0.05f) continue;
|
||||
// For horizontal planes require XY overlap area; for walls allow thin Z.
|
||||
bool horizontal = MathF.Abs(a.N.Z) > 0.85f;
|
||||
if (horizontal && ox * oy < 0.05f) continue;
|
||||
if (!horizontal && oz < 0.05f) continue;
|
||||
|
||||
pairs++;
|
||||
_out.WriteLine(
|
||||
$">>> COPLANAR-OVERLAP {(a.CellId == b.CellId ? "SAME-CELL" : "CROSS-CELL")}: " +
|
||||
$"0x{a.CellId:X8} poly {a.PolyId} (surf 0x{a.SurfaceId:X8}) <-> " +
|
||||
$"0x{b.CellId:X8} poly {b.PolyId} (surf 0x{b.SurfaceId:X8}) " +
|
||||
$"n=({a.N.X:F2},{a.N.Y:F2},{a.N.Z:F2}) align={align:F3} " +
|
||||
$"overlap x={ox:F2} y={oy:F2} z=[{MathF.Max(a.Min.Z, b.Min.Z):F2}..{MathF.Min(a.Max.Z, b.Max.Z):F2}]");
|
||||
}
|
||||
}
|
||||
_out.WriteLine($"coplanar overlapping drawn pairs: {pairs}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #176 candidate (A2C): the opaque pass derives GL_SAMPLE_ALPHA_TO_COVERAGE
|
||||
/// from the sampled texture alpha (mesh_modern.frag uRenderPass==0 keeps
|
||||
|
|
@ -379,6 +467,9 @@ public class Issue176177DungeonSeamInspectionTests
|
|||
[InlineData(0x8A02011Du)]
|
||||
[InlineData(0x8A020122u)]
|
||||
[InlineData(0x8A02011Fu)]
|
||||
[InlineData(0x8A02016Eu)] // corridor cells — the striped-floor screenshot area
|
||||
[InlineData(0x8A02017Au)]
|
||||
[InlineData(0x8A020165u)]
|
||||
public void UnderHall_DrawnPolys_SurfaceColors(uint cellId)
|
||||
{
|
||||
var datDir = ResolveDatDir();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue