acdream/docs/research/2026-08-21-terrain-fidelity-track-a-report.md
Erik 6e76314b08 docs(vm4): every Campaign AR document says what its evidence shows
Dated 'VM4 correction' notes, not silent rewrites:
- AR plan: NoOpRenderPackProductionIntegrationTests is a 2x2 recording-
  device fixture, not a production pin; the real invariance is VM0's.
  Both '14,928/14,928 zero skips' totals qualified: hermetic lane filter.
- Stage-2 connected report: the dense-town CPU figures ran under the
  automation observer (9.8 MB/frame alloc) and say nothing about the
  owner's hitch on the product; clean numbers are VM0's.
- Track A report + findings doc: TerrainUtils.GetNormal only orients
  scenery; the render normals were already smooth; A2 replaced central
  differences with retail's incident-face average (the reviewer's own
  premise error).
- Findings doc: 'retail brightens' is the fallback path only; real
  hardware runs the single-pass lerp (VM2). LandscapeDetailTextures = 0
  answers the landscape open question. VM0 production table added as the
  baseline.
- Completion audit retail-path row and the review's F1/F2/F3/F5 headers
  annotated with their closures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 22:51:59 +02:00

81 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Terrain fidelity Track A report
**Date:** 2026-08-21
**Status:** REPORT ACCEPTED BY OWNER DIRECTION; A1/A2 IMPLEMENTED; A3 REJECTED
This report answers Track A from the measured
[`terrain and atmospheric rendering findings`](2026-08-21-terrain-and-atmospheric-rendering-findings.md).
It cites that evidence rather than repeating its measurements, and it does not
reopen the findings' three refuted claims. The project owner subsequently
authorized implementation. No physics or collision behavior changed.
## A1 — #226 detail-texture overlay
The complete source/size/tiling, blend, neutral point, distance units, setting
gate, material-ordering contract, reverted-experiment analysis, and connected
A/B/A evidence are in the
[`#226 retail building/EnvCell detail-texturing port note`](2026-08-21-retail-building-detail-texturing-pseudocode.md).
The report conclusions are:
- The reachable user-visible target is **building shells and interior EnvCell
geometry**, not outdoor terrain. The Options preference caller and
`LScape::ChangeRegion` both install category state `(landscape=0,
building=enabled, environment=enabled, ordinary=0)` through
`SmartBox::SetDetailTexturing`.
- The existing **Building Detail Textures** checkbox is the sole setting gate.
No second option was added. Toggling it now visibly changes the connected
Facility Hub scene without a restart.
- The port keeps retail's `DEST_COLOR + ONE_MINUS_SRC_ALPHA` blend verbatim,
including the measured slight brightening. `dst=ZERO` would be an opt-in
visual correction, not parity; exposing both meanings behind the one retail
checkbox would make that preference ambiguous.
- The reverted experiment targeted landscape, built the wrong texture-array
shape, used `base * detail * 2`, assumed 128 gray was neutral, and rejected
the brightness change that the measured retail blend actually produces.
## A2 — terrain vertex normals
**Verdict: parity gap. Retail smooths shared terrain vertices.**
The decisive named-retail function is
`CLandBlockStruct::calc_lighting` at `0x00531700` in
[`acclient_2013_pseudo_c.txt`](named-retail/acclient_2013_pseudo_c.txt):
1. It zeroes one three-float accumulator for every shared landblock vertex.
2. From `0x00531774` through `0x005317F6`, it walks every terrain polygon and
adds that polygon's plane normal (`CPolygon + 0x20..0x28`) to the
accumulator of each of its three vertex IDs.
3. From `0x00531817` through `0x00531886`, it normalizes every accumulated
vector, falling back to `(0, 0, 1)` only for a degenerate sum.
4. The following sunlight/ambient loop dots those normalized shared-vertex
normals with `LScape::sunlight` and writes per-vertex lighting.
That is incident-face normal averaging. **VM4 correction (2026-08-22):** the
findings doc's premise that `TerrainUtils.GetNormal` produced a faceted render
was wrong — that function only orients procedural scenery
(`SceneryGenerator.cs:166`) and never fed the render normal. The rendered
terrain mesh already had smooth central-difference normals (Phase 3b,
`LandblockMesh`). The real change A2 made is central-difference smoothing →
retail's split-aware incident-face average: a genuine, decomp-verified parity
port, but a subtler visual change than either document implied (VM0 measured
1114 % of pixels at mean |Δ| ≈ 11.5 on the same view).
The approved port is in `LandblockMesh.BuildRetailVertexNormals`. It uses the
same split hash and exact emitted triangle topology, accumulates each
normalized incident face normal at the shared 9 x 9 height-sample vertex, and
normalizes the sum. Tests independently reconstruct the average from emitted
positions/indices and prove every position and index is unchanged.
This is lighting-only parity: the 81 height samples, 128 triangles, split
directions, terrain surface, collision triangles, walkability, and physics
owners are byte-for-byte/topology-equivalent to the prior path.
## A3 — subdivision
**Agree: the standing “not worth doing” recommendation survives.** The
findings §4 already establishes that the 9 x 9 samples are height-table
quantized, so subdivision cannot recover missing terrain detail; changing the
surface would create physics divergence, while coplanar subdivision would only
interpolate a surface whose retail-correct shared-vertex smoothing is now
already present. No subdivision work is scheduled.