docs(vm1): closeout - AP-232 for the translucent detail blend weight; sampler test pins the production constant
Opus narrow re-review ofae651312: APPROVE. Closes its three residuals: - AP-232 filed: retail's single-pass stage-1 OUTPUT alpha (MODULATE(TEXTURE, CURRENT) @0x0059c549) is the blend weight for a translucent subset; acdream's two-draw model is exact for opaque subsets (fog identity pinned) and a bounded weight difference on translucent ones. Distinct from AP-34 (queue order). Owed since05970306. - TerrainAtlas.DetailSamplerDescription names the production sampler (WRAP/LINEAR x3 per ACRender::SetDetailSurfaceInternal @0x006b6280); the test now asserts that constant's properties instead of a test-local copy. - Plan VM1 section: fragment now described as fogged; VM1 marked CLOSED with the Holtburg measurement (+2.17/+0.57/+0.16 vs predicted +2.2/+0.66/+0.16) and the detail-on cost (+0.3-0.5 ms CPU at Arwic). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
ae6513126e
commit
dcdd102824
5 changed files with 24 additions and 8 deletions
File diff suppressed because one or more lines are too long
|
|
@ -77,7 +77,7 @@ single-pass path darkens by ~10 %. Neither explains a scene-wide level.
|
|||
| Slice | Closes | Gate |
|
||||
|---|---|---|
|
||||
| VM0 | F1 — default-path invariance | **CLOSED 2026-08-22 — PASS**; [report](../research/2026-08-22-vm0-default-path-invariance.md) |
|
||||
| VM1 | F2 — invented detail fade | automated |
|
||||
| VM1 | F2/F3 — #226 single-pass re-port + fade removal | **CLOSED 2026-08-22** — `05970306`, `388457a7`, `ae651312`, closeout; Opus APPROVE |
|
||||
| VM2 | F3 — which retail detail path ran | **CLOSED 2026-08-22** — single-pass; see [cdb note](../research/2026-08-22-vm2-retail-detail-path-cdb.md) |
|
||||
| VM3 | F4 — linear-light post stack | automated + **owner visual** |
|
||||
| VM4 | F5 — overclaiming docs, incl. the reviewer's own | docs |
|
||||
|
|
@ -85,7 +85,7 @@ single-pass path darkens by ~10 %. Neither explains a scene-wide level.
|
|||
| VM6 | Foliage wind | automated + **owner visual** |
|
||||
| VM7 | Closeout: full gates, register, roadmap, merge | **owner** |
|
||||
|
||||
Order is VM2 (done) → VM0 (done) → VM1 → VM4 → VM5 → VM3 → VM6 → VM7. VM0 goes first because everything after it is measured
|
||||
Order is VM2 (done) → VM0 (done) → VM1 (done) → VM4 → VM5 → VM3 → VM6 → VM7. VM0 goes first because everything after it is measured
|
||||
against the baseline it establishes.
|
||||
|
||||
---
|
||||
|
|
@ -147,7 +147,7 @@ already converges the live category texture to its 1.033 mean factor.
|
|||
**Implementation**
|
||||
|
||||
- Delete the two constants and `vDetailFade` from `mesh_detail.vert/.frag`
|
||||
(`mesh_detail.vert:83`); the fragment outputs `detail.rgba` unscaled.
|
||||
(`mesh_detail.vert:83`); the fragment outputs `applyFog(detail.rgb)` with alpha `detail.a * instanceOpacity` — fogged so the two-draw result collapses to retail's fog-after-combine pixel (VM1 review fix).
|
||||
- Confirm the detail texture is uploaded with a full mip chain and sampled
|
||||
LINEAR/LINEAR/LINEAR, WRAP — that *is* retail's attenuation; test it.
|
||||
- Rename `RetailDetailTextureContract` members so nothing un-anchored is
|
||||
|
|
@ -157,6 +157,8 @@ already converges the live category texture to its 1.033 mean factor.
|
|||
- If the owner later wants a ramp back, it returns as a **pack setting**
|
||||
(enhancement), never on the default path.
|
||||
|
||||
**OUTCOME (2026-08-22): CLOSED.** Four commits: the single-pass re-port + fade removal (`05970306`); the interior shell/detail passes binding their own instance opacity — a pre-campaign stale-slot read (`388457a7`); the Opus fix round — the detail contribution is fogged so the two-draw result collapses to retail's fog-after-combine pixel, mip/sampler test, doc caveats (`ae651312`); and the closeout (AP-232 for the translucent-subset blend weight, the sampler test pinned to the production constant). Measured on Holtburg buildings: predicted +2.2/+0.66/+0.16 levels vs measured +2.17/+0.57/+0.16 (`artifacts/vm1`, grass/sky controls 0.00). Detail-on costs +0.3-0.5 ms CPU / +0.1 ms GPU at dense Arwic, still under the pre-campaign baseline. Opus dual-lens review: APPROVE WITH FIXES -> fix round -> narrow re-review APPROVE.
|
||||
|
||||
**Acceptance:** no reference to a distance fade remains in src or the note;
|
||||
VM0's masked comparison re-run shows the only change is on detail surfaces;
|
||||
at >50 m a building reads the same as at 60 m (mips), not a hard step.
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ draw weighted by `detail.a * diffuseAlpha` (the pipeline in
|
|||
opaque subsets this is identical (both reduce to the base's own alpha
|
||||
gating nothing else downstream); on translucent building/EnvCell subsets it
|
||||
is a bounded difference in how much the SUBSEQUENT alpha-queue compositing
|
||||
sees, already covered by the existing AP-34 shared-alpha-queue divergence
|
||||
sees, registered as its own row AP-232 (blend WEIGHT on translucent subsets), distinct from AP-34 (queue ORDER)
|
||||
row rather than a new one.
|
||||
|
||||
## Darkening, not brightening
|
||||
|
|
|
|||
|
|
@ -34,6 +34,16 @@ public sealed class TerrainAtlas : IDisposable
|
|||
/// one-layer 2-D array so it uses the same backend-neutral table contract
|
||||
/// as every other world texture.
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// Retail's detail-stage sampler: <c>ACRender::SetDetailSurfaceInternal</c>
|
||||
/// (0x006b6280) sets WRAP/WRAP addressing and LINEAR/LINEAR/LINEAR filtering
|
||||
/// on the detail stage. The LINEAR mip chain is retail's only distance
|
||||
/// attenuation for built meshes (VM1), so this constant is load-bearing and
|
||||
/// pinned by <c>TerrainAtlasDetailTextureTests</c>.
|
||||
/// </summary>
|
||||
internal static readonly GpuSamplerDescription DetailSamplerDescription =
|
||||
GpuSamplerDescription.WorldRepeat;
|
||||
|
||||
internal readonly record struct RetailDetailTextureBinding(
|
||||
GpuTextureSlot TextureSlot,
|
||||
float Tiling,
|
||||
|
|
@ -430,7 +440,7 @@ public sealed class TerrainAtlas : IDisposable
|
|||
// ChangeRegion and the only reachable SmartBox caller keep
|
||||
// landscape (0) and object (3) disabled, so do not create or expose
|
||||
// those categories here.
|
||||
detailSampler = device.CreateSampler(GpuSamplerDescription.WorldRepeat);
|
||||
detailSampler = device.CreateSampler(DetailSamplerDescription);
|
||||
if (terrainDesc is { Count: > 1 })
|
||||
{
|
||||
buildingDetail = TryCreateDetailTexture(
|
||||
|
|
|
|||
|
|
@ -65,7 +65,10 @@ public sealed class TerrainAtlasDetailTextureTests
|
|||
},
|
||||
};
|
||||
|
||||
IGpuSampler sampler = device.CreateSampler(GpuSamplerDescription.WorldRepeat);
|
||||
// The sampler is created from the PRODUCTION constant so that changing
|
||||
// TerrainAtlas's choice (e.g. to a clamp sampler) fails the property
|
||||
// assertions below rather than being forwarded unnoticed.
|
||||
IGpuSampler sampler = device.CreateSampler(TerrainAtlas.DetailSamplerDescription);
|
||||
|
||||
MethodInfo method = typeof(TerrainAtlas).GetMethod(
|
||||
"TryCreateDetailTexture",
|
||||
|
|
@ -92,7 +95,7 @@ public sealed class TerrainAtlasDetailTextureTests
|
|||
// point-filtered UI sampler.
|
||||
GpuRecordedTextureRegistration registration = Assert.Single(
|
||||
device.Calls.OfType<GpuRecordedTextureRegistration>());
|
||||
Assert.Equal(GpuSamplerDescription.WorldRepeat, registration.Sampler);
|
||||
Assert.Equal(TerrainAtlas.DetailSamplerDescription, registration.Sampler);
|
||||
Assert.Equal(GpuFilter.Linear, registration.Sampler.MinFilter);
|
||||
Assert.Equal(GpuFilter.Linear, registration.Sampler.MagFilter);
|
||||
Assert.Equal(GpuMipFilter.Linear, registration.Sampler.MipFilter);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue