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

4.3 KiB
Raw Blame History

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. 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.

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:

  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.