docs(render): §10.6 — post-hoc lens verdicts (three PASS) and the landing-hygiene chunk; AD-17 particle clause corrected
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
6435655d73
commit
6989868c37
2 changed files with 90 additions and 1 deletions
|
|
@ -144,7 +144,7 @@ readiness/requeue adaptation. See
|
|||
| AD-13 | 1-second dedup window for identical system chat messages (retail has none) | `src/AcDream.Core/Chat/ChatLog.cs:29` | ACE dual-sends the same system text (0xF7E0 + 0x02EB) for back-compat; without dedup every line doubled (Phase J compromise) | Two genuinely distinct but textually identical system messages within 1 s collapse to one line where retail shows both | ACE dual-send 0xF7E0 + 0x02EB |
|
||||
| AD-15 | `IsEnv` masks low-16 of the cell id (`(Id & 0xFFFF) >= 0x100`) where retail tests the full id | `src/AcDream.Core/World/Cells/ObjCell.cs:25` | Every real prefixed EnvCell id has low-16 ≥ 0x100 and every outdoor cell ≤ 0x40 — identical answers for all real dat ids, works for both bare and prefixed forms | None for real dat data; a hypothetical convention-violating id would route to the wrong (BSP vs terrain) point-in-cell logic | `CObjCell::GetVisible` pc:308215 |
|
||||
| AD-16 | Building-flood gate is a CPU frustum test on each building's `PortalBounds` AABB; retail floods exactly when the shell draws and an aperture survives (no bounds constant anywhere) | `src/AcDream.App/Rendering/WorldRenderFrameBuilder.cs` (`RuntimeWorldFrameBuildingSource.Gather`) | Documented as the tight equivalent of the shell viewconeCheck for flood purposes (the FPS fix the Chebyshev≤1 hack approximated); per-portal admission still goes through BuildFromExterior's screen clip; missing-bounds buildings always flood (safe over-include) | A too-small/stale PortalBounds AABB means the interior never floods — doorway shows a hole/black aperture from outside (inverse of the vanishing-staircase class) | `DrawBuilding` 0x0059f2a0; `BSPPORTAL::portal_draw_portals_only` 0x53d870 |
|
||||
| AD-17 | **REWRITTEN 2026-09-03 at Campaign OVERHAUL v2 S3 chunk 4 (rounds `ff607a1e0` + `7df0b94c9`).** Only two GPU clips remain, both retail `PView::DrawCells` portal-polygon draws: the exit seals and the punch fans. Each carries ≤8 `gl_ClipDistance` half-planes per view region (`ClipPlaneSet.MaxPlanes`; `Render::copy_view` caps a view at 31 vertices). Overflow handling differs by consumer: a >8-edge exit-seal view uses its convex NDC AABB as a conservative four-plane gate (`WalkFrameDriver.AppendClipSlot`); a >8-edge or multi-polygon OUTSIDE view yields a zero-plane slice (`ClipFrameAssembler.AppendOutsideSlice`'s fallback: slot 0, empty `Planes`, `ScissorFallbacks` counted) and that view's punch fan draws UNCLIPPED. Retail CPU-clips its portal polygons exactly. The former union-AABB scissor fallback, the sky's doorway scissor bracket, the per-slice terrain/sky/weather clips, the TerrainClip UBO and `NdcScissorRect` are DELETED: sky, terrain, weather and particles are never GPU-clipped, matching retail (`LScape::draw` installs no view before any of them). | `src/AcDream.App/Rendering/ClipPlaneSet.cs:23`; `src/AcDream.App/Rendering/ClipFrameAssembler.cs` (`AppendOutsideSlice`); `src/AcDream.App/Rendering/Walk/WalkFrameDriver.cs` (`AppendClipSlot`); `src/AcDream.App/Rendering/RetailPViewPassExecutor.WalkLeaf.cs` (`DrawWalkPunchFan` reads `OutsideViewSlices[i].Planes`) | Vulkan's `VkPhysicalDeviceLimits::maxClipDistances` floor is 8; over-inclusion is the safe direction for a depth-only seal/punch (it can cover at most the whole aperture fan), under-inclusion is the bug class | A >8-edge exit-seal view seals its AABB instead of the exact polygon and a >8-edge outside view punches its whole fan — depth-only over-include with no color bleed (the former **#130** strip family died with the scissor); an interior root's aperture exactness now rests on the depth clear + exit seals + interior repaint, never on a GPU clip of the landscape | `ACRender::polyClipFinish` decomp:702749; `PView::DrawCells` 0x005a4840 portal_view slices; `Render::copy_view` 0x0054dfc0; `LScape::draw` 0x00506330 |
|
||||
| AD-17 | **REWRITTEN 2026-09-03 at Campaign OVERHAUL v2 S3 chunk 4 (rounds `ff607a1e0` + `7df0b94c9`).** Only two GPU clips remain, both retail `PView::DrawCells` portal-polygon draws: the exit seals and the punch fans. Each carries ≤8 `gl_ClipDistance` half-planes per view region (`ClipPlaneSet.MaxPlanes`; `Render::copy_view` caps a view at 31 vertices). Overflow handling differs by consumer: a >8-edge exit-seal view uses its convex NDC AABB as a conservative four-plane gate (`WalkFrameDriver.AppendClipSlot`); a >8-edge or multi-polygon OUTSIDE view yields a zero-plane slice (`ClipFrameAssembler.AppendOutsideSlice`'s fallback: slot 0, empty `Planes`, `ScissorFallbacks` counted) and that view's punch fan draws UNCLIPPED. Retail CPU-clips its portal polygons exactly. The former union-AABB scissor fallback, the sky's doorway scissor bracket, the per-slice terrain/sky/weather clips, the TerrainClip UBO and `NdcScissorRect` are DELETED: sky, terrain and weather are never GPU-clipped, matching retail (`LScape::draw` installs no view before any of them). The mesh and particle shaders KEEP a per-cell `clipRegions[aClipSlot]` input, but the walk feeds every ordinary part (`WbDrawDispatcher.WalkClassify.ResolvePartVisible` — a Boolean sphere test, whole-mesh slot 0) and every particle (`ParticleRenderer`'s `clipSlot` default 0) the no-clip slot, matching retail's `DrawMeshInternal` sphere test; that machinery is dormant in the walk path and live only for the non-walk flat path. | `src/AcDream.App/Rendering/ClipPlaneSet.cs:23`; `src/AcDream.App/Rendering/ClipFrameAssembler.cs` (`AppendOutsideSlice`); `src/AcDream.App/Rendering/Walk/WalkFrameDriver.cs` (`AppendClipSlot`); `src/AcDream.App/Rendering/RetailPViewPassExecutor.WalkLeaf.cs` (`DrawWalkPunchFan` reads `OutsideViewSlices[i].Planes`) | Vulkan's `VkPhysicalDeviceLimits::maxClipDistances` floor is 8; over-inclusion is the safe direction for a depth-only seal/punch (it can cover at most the whole aperture fan), under-inclusion is the bug class | A >8-edge exit-seal view seals its AABB instead of the exact polygon and a >8-edge outside view punches its whole fan — depth-only over-include with no color bleed (the former **#130** strip family died with the scissor); an interior root's aperture exactness now rests on the depth clear + exit seals + interior repaint, never on a GPU clip of the landscape | `ACRender::polyClipFinish` decomp:702749; `PView::DrawCells` 0x005a4840 portal_view slices; `Render::copy_view` 0x0054dfc0; `LScape::draw` 0x00506330 |
|
||||
| AD-18 | Aperture far-Z punch is two-pass stencil-gated with an invented mark bias: 0.0005 NDC capped to a 0.5 m EYE-SPACE span (`MarkBiasNdc`); retail's single DEPTHTEST_ALWAYS punch is safe only under painter's far→near order we don't have | `src/AcDream.App/Rendering/PortalDepthMaskRenderer.cs:149` | **#117** (2026-06-11): the unconditional punch erased nearer occluders, painting interiors through them; the two-pass form is the z-buffered equivalent of retail's ordering safety. **#129** (2026-06-12): the constant-NDC bias spanned ~190 m of eye depth at a landblock (non-linear depth) → distant occluders punched; the eye-space cap bounds the reach (`Issue129PunchBiasTests`). DO-NOT-RETRY: punch must stay depth-gated (ISSUES #108) | Door-plane-hugging geometry beyond the 0.5 m cap re-occludes the aperture (a **#108**-class regression at >10 m viewing range); an occluder within the cap in front of a distant aperture still punches through | `D3DPolyRender::DrawPortalPolyInternal` 0x0059bc90 (maxZ1=7 / maxZ2=6) |
|
||||
| AD-19 | Under outdoor roots, ALL dynamics draw in one z-buffered final pass; retail draws objects painter-ordered per landcell inside the landscape pass (interior roots route per **#118**) | `src/AcDream.App/Rendering/RetailPViewRenderer.cs:126` | The dynamics-drawn-LAST invariant is what makes the aperture depth punch safe (first BR-2 attempt punched after dynamics and erased the player, reverted `88be519`); z-buffer substitutes for painter's order on opaque geometry | Punch/seal correctness hinges on an ordering invariant — any pass added after DrawDynamicsLast, or alpha content needing painter order, gets erased inside apertures or composites wrong | `LScape::draw` → `DrawBlock` 0x005a17c0 → DrawSortCell pc:430124; `PView::DrawCells` 0x005a4840 |
|
||||
| AD-20 | Camera sweep fallback seeds the eye's `AdjustPosition` from the PLAYER's cell; retail re-seats at the sought eye's own tracked cell (rest of function is a verbatim `update_viewer` port) | `src/AcDream.App/Rendering/PhysicsCameraCollisionProbe.cs:97` | acdream's camera doesn't track the sought-eye's cell separately; the eye is near the player so the player-cell stab list is assumed to cover it | An eye outside the player cell's stab-list coverage (boundary corners, cross-landblock pull-back) seats in the wrong cell — and the viewer cell roots the whole render: one-frame wrong root (flap-class flash) | `SmartBox::update_viewer` 0x00453ce0, pc:92878-92883 |
|
||||
|
|
|
|||
|
|
@ -967,6 +967,95 @@ lead's `ACDREAM_DEVTOOLS=1` four-pose self-gate shows no validation error and
|
|||
no visual delta against `logs/selfgate-20260903-104516-s3-chunk3-r2` beyond
|
||||
actors/daylight.
|
||||
|
||||
### 10.6 Post-hoc three-lens verdict on round 2 and the landing-hygiene chunk (lead, 2026-09-03 evening)
|
||||
|
||||
**Verdicts (all three PASS, `s3-chunk4-impl` @ `2e3ae95ff`, run after the API
|
||||
overload lifted; the lead had already landed the round on its own
|
||||
verification — §13 S3 row).** The findings are documentation and dead-state
|
||||
hygiene, none touches admission, order or a pin's discriminating power:
|
||||
|
||||
- (major, two lenses) AD-17 still described the deleted scissor fallback in
|
||||
the chunk's own worktree — already rewritten on the campaign branch at
|
||||
`5b43d8d55`; the rewrite's "particles never GPU-clipped" clause is
|
||||
corrected in this hygiene commit (the mesh/particle shaders KEEP the
|
||||
per-cell `clipRegions[aClipSlot]` input; the walk feeds every ordinary
|
||||
part and every particle the whole-mesh slot 0 = no clip, so the machinery
|
||||
is dormant in the walk path, live only for the non-walk flat path).
|
||||
- (major) `Issue130DoorwayStripTests`' rewritten header claims the surviving
|
||||
plane-gap half pins "ProjectToClip → ClipToRegion → ClipPlaneSet.From
|
||||
that the punch fans consume"; only `ClipPlaneSet.From` has a production
|
||||
caller — the test drives `PortalVisibilityBuilder` + `Assemble`, both
|
||||
zero-caller legacy paths.
|
||||
- (major) `ClipPlaneSet.cs` header (`:23-39`) and member docs (`:80-92`)
|
||||
still promise a consumer that "draws the ScissorNdcAabb box";
|
||||
`UseScissorFallback`/`ScissorNdcAabb` have no production reader
|
||||
(`AppendOutsideSlice` reads only `IsNothingVisible`/`Count`/`PlaneArray`).
|
||||
- (minor) stale sentences: `ClipFrameAssembler.cs:14-15`, `:37-38`
|
||||
(`TerrainClipMode.Scissor`, a value nothing produces), `:45-46`;
|
||||
`WorldPassSurface.cs:22-26` ("Four concerns" incl. "the doorway
|
||||
scissor"), `:54-58` (shaders "write 1.0 into every slot" — they no longer
|
||||
write `gl_ClipDistance`), `:76-77`; `TerrainModernRenderer.cs:244-245`
|
||||
dead `clipPlanes`/`ndcClipAabb` parameters of `Draw` and the
|
||||
`IsAabbVisibleThroughClipRegion` scissor branch + comment `:521-524`
|
||||
(no producer left); `RetailPViewRenderer.cs:418-419` computes a
|
||||
`terrainUploadCount` the only `PrepareClipFrame` discards, with a GL-era
|
||||
doc at `WorldPassSurface.cs:34-41`; `RetailPViewPassExecutorTests.cs:159-161`
|
||||
says "unconditionally" (false since K2); the K1 pin's doc lacks the
|
||||
switch-table scope note L8 put on its own; `RetailPViewRenderer.cs:647`
|
||||
cites the callee address `@0x00506ff0` where §10.1 cites the call site
|
||||
`@0x00506396`.
|
||||
- (minor, pin limit) the L1 condition pin accepts a CONJOINED gate
|
||||
`if (clipAssembly.OutsideViewSlices.Length != 0 && walkDriver.WeatherTurnFired)`
|
||||
(the extra `brfalse` lands before the getter's offset); the print/draw
|
||||
divergence it would reintroduce is exactly K2's.
|
||||
|
||||
**Hygiene chunk H (one Sonnet agent in `s3-hygiene` at the campaign tip; one
|
||||
lens; no third round — a FAIL here is written up, not fixed again):**
|
||||
|
||||
- **H1** `ClipPlaneSet`: delete `ScissorNdcAabb`; rename `UseScissorFallback`
|
||||
→ `IsPlaneOverflow` with the doc "Count == 0 because the region needs more
|
||||
than `MaxPlanes` half-planes (or is multi-polygon); the consumer draws
|
||||
UNCLIPPED (`AppendOutsideSlice` emits an empty plane array; the punch fan
|
||||
covers the whole fan) — over-include, never a scissor"; rewrite the file
|
||||
header (`:23-39`) to the three states that exist (Empty / overflow /
|
||||
planes); update `ClipPlaneSetTests` to the new name and delete its AABB
|
||||
assertions (they pinned the deleted consumer contract).
|
||||
- **H2** `TerrainModernRenderer`: delete `Draw`'s `clipPlanes`/`ndcClipAabb`
|
||||
parameters, the scissor branch of `IsAabbVisibleThroughClipRegion` (keep
|
||||
the clip-plane test only if a caller still passes planes — grep; if none,
|
||||
delete the whole helper and its comment `:521-524` so `CollectVisibleCells`
|
||||
is frustum-only), and the `terrainUploadCount` computation at
|
||||
`RetailPViewRenderer.cs:418-419` + `PrepareClipFrame`'s parameter and its
|
||||
GL-era doc (`IWorldPassSurface.PrepareClipFrame()` takes nothing).
|
||||
- **H3** `Issue130DoorwayStripTests`: DELETE the test (its remaining half
|
||||
drives two zero-caller legacy paths; the one production stage it touches,
|
||||
`ClipPlaneSet.From`, is pinned by the K6 punch-fan pin through the real
|
||||
producers) and say so in the commit body with #130's history in one
|
||||
sentence.
|
||||
- **H4** comments: `ClipFrameAssembler.cs:14-15/:45-46` (no scissor
|
||||
consumer), delete `TerrainClipMode.Scissor` (nothing produces it; keep
|
||||
`Planes`/`Skip` for the flat path — grep the enum's readers first);
|
||||
`WorldPassSurface.cs:22-26` → three concerns, `:54-58` → only
|
||||
`portal_depth.vert` writes `gl_ClipDistance` in the world pass now,
|
||||
`:76-77` drop the scissor sentence; `RetailPViewPassExecutorTests.cs:159-161`
|
||||
→ "conditional on `WalkFrameDriver.WeatherTurnFired`, see the L1 pin";
|
||||
add the switch-table note to the K1 pin's doc; `RetailPViewRenderer.cs:647`
|
||||
→ the call-site address `@0x00506396` (callee `@0x00506ff0`).
|
||||
- **H5** strengthen the L1 pin against the conjoined gate: between the
|
||||
`DrawUnattachedSceneParticles` call (the last call before the gate) and
|
||||
the `DrawWeatherOnce` call there is exactly ONE conditional branch in
|
||||
total, and it is the forward `brfalse` after `get_WeatherTurnFired` —
|
||||
MUTATION: the conjoined gate adds a second `brfalse` → fails; record the
|
||||
text.
|
||||
- **H6** commit body: every mutation text (H5), the H2 grep results, the
|
||||
H3 sentence; `Co-Authored-By` last.
|
||||
|
||||
Gates: build 0 warnings; hermetic lane fully green; InstalledDat exactly the
|
||||
four known (2× #383, TowerAscent, #458); the L6 grep from §10.5 extended
|
||||
with `ScissorNdcAabb|UseScissorFallback|TerrainClipMode.Scissor|
|
||||
ndcClipAabb|terrainUploadCount` returns nothing under `src`/`tests`; no
|
||||
register row (AD-17's correction is the lead's, in the same landing).
|
||||
|
||||
## 11. Chunk 1 contract — transcript kinds, fixtures, and the print-only emitter (lead, 2026-09-03; runs AFTER chunk 3, because `LC`/`SC` only exist once terrain is per cell)
|
||||
|
||||
### 11.1 What exists (verified in the tree at `542b049b`)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue