Procedural-scenery foliage (trees/bushes — entity ids in the ProceduralSceneryIdAllocator's 0x8XXYYIII namespace) sways with weather in mesh_atmospheric.vert and all four directional_shadow_world_* caster vertex shaders, both calling the identical new foliage_wind.glsl include so the shadow moves with the leaf by construction. Classification (FoliageWindClassification, AcDream.App.Rendering.Wb): two new BatchData.flags bits, computed once per (entity, subset) from four inputs — entity id (bit 31 for procedural scenery), the pack's declared FoliageExclusions membership, the subset's TranslucencyKind, and ObjectRenderData.HasCutoutSubset (computed once per mesh at build time, not per frame). Bit 1 marks an alpha-cutout leaf subset; bit 2 marks an opaque trunk subset (only when its own mesh also owns a cutout subset, so rocks stay still). WbDrawDispatcher.ClassifyBatches (world receiver) and AddDirectionalShadowBatches (caster) call this with the same four inputs, so casters and receivers classify identically without needing to share state. Retail's mesh_modern/terrain_modern/mesh_detail pipelines never read these bits, so pack-off output is unaffected. Motion model (foliage_wind.glsl, mirrored bit-for-bit in the new FoliageWindModel for hermetic CPU tests): height-squared-scaled slow lean for every foliage subset, plus branch swing and per-vertex-hash-decorrelated flutter for cutout subsets only. AtmosphericPostProcessGraph.ResolveFoliageWind resolves the wind block once per frame.Serial — advanced by whichever of RenderDirectionalShadows (which runs first) or RenderPostProcess is called first that frame, with the second reading the already-advanced state, which is what keeps the caster and receiver reading byte-identical clock/strength values. The per-day-group mean/gust target (AtmospherePolicyDeclaration. FoliageWindByDayGroup, keyed by the same day-group index convention ActiveDayGroupMultipliers already established: Clear/Cloudy/Overcast/Rainy) eases toward its target over WeatherSystem.TransitionSeconds (10s) so a weather change never snaps; wind-enabled off or indoor instead gates the OUTPUT to an exact zero (not an asymptotic approach) so a settings toggle or cell transition is immediate. The wind clock is a Stopwatch started at graph construction (monotonic, session-relative magnitude for GPU sin() accuracy), overridable by the same ACDREAM_SKY_PHASE_SECONDS pin SkyRenderer already uses, for deterministic offline gates. New settings: wind-enabled, wind-strength, wind-direction-degrees (225° default — no authored retail wind direction exists to read), wind-lean-metres, wind-branch-metres, wind-flutter-metres (0 on Low), wind-canopy-height-metres. Register row IA-25 files this as an intentional, strictly opt-in divergence: retail applies no per-vertex wind displacement to any geometry. Known, accepted limitation: classification is per mesh-subset (one BatchData.flags word per indirect-draw batch), not per entity instance, so the rare case of one mesh subset being reachable from both a procedural-scenery and a non-scenery placement would classify all of that subset's instances alike. Tests: FoliageWindClassificationTests (the full classification matrix), FoliageWindModelTests (identity on non-foliage/calm-wind/base-vertex, canopy-top displacement bound, z-never-increases, trunk has no flutter term), RenderPackAtmospherePolicyEvaluationTests (exact day-group lookup, no interpolation across day-group ids, easing convergence without overshoot or discontinuity), AtmosphericShaderAbiTests (each of the five shaders calls acdreamFoliageDisplace exactly once; mesh_modern/terrain/mesh_detail call it never), and four AtmosphericPostProcessGraphTests additions (indoor/disabled exact-zero gating, settings-to-UBO wiring, same-frame-Serial idempotency — the last proxies the caster/receiver agreement invariant without needing this hermetic harness's WbDrawDispatcher/TerrainModernRenderer dependency chain to exercise RenderDirectionalShadows directly). App hermetic filter: 6015/6017 (the same 2 pre-existing failures as VM6a, confirmed unrelated). Core.Tests hermetic: 4697/4697. RenderPackValidator.Tests: 30/30. Full solution Debug and Release builds green. Shader recompile touched exactly the 5 edited files' .spv (plus manifest); the retail oracle set and every other pack shader are byte-identical. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
977 lines
58 KiB
Markdown
977 lines
58 KiB
Markdown
# Campaign AR — Atmospheric Rendering / Shader Packs
|
||
|
||
**Date:** 2026-08-21
|
||
**Status:** MACHINE-LOCAL STAGE 2 COMPLETE — the authored sun-and-moon
|
||
shadow-source extension, Stage 1 owner gate, connected ACE matrix, dense A/B,
|
||
long lifetime, graphical package lifecycle, shader, locked-restore, Release,
|
||
and complete-test gates pass. A distinct-account second-client remote-player
|
||
row, unavailable physical GPU classes, and final project-owner pack-off/pack-on
|
||
acceptance remain external closeout gates; the campaign is not yet declared
|
||
shipped.
|
||
**Phase id:** **Campaign AR** — assigned by the project owner on 2026-08-22
|
||
**Scheduling:** originally held for the post-M7 rendering-polish pass; the
|
||
project owner explicitly authorized implementation on 2026-08-21. This
|
||
owner-directed campaign is now Campaign AR and does not displace the active M4
|
||
gameplay work. The previously referenced #268 + TS-8 stat-chain package is
|
||
already complete and retired, so it is no longer a scheduling dependency.
|
||
|
||
## Goal
|
||
|
||
Add an opt-in enhanced-graphics system whose headline feature is **real-time
|
||
directional shadows cast by trees, monsters, players, and buildings as
|
||
Dereth's authored sun and moons move across the sky**. The same system can add
|
||
bloom, filmic tonemapping, colour grading, vignette, sun rays, and later
|
||
volumetric shafts, with useful quality levels on weak through high-end
|
||
hardware. Sun rays and volumetric shafts remain sun-only effects; the approved
|
||
moon scope applies to Tier 2 directional shadows.
|
||
|
||
Campaign AR executes in two stages. Stage 1 fixed the dense-scene transform
|
||
ceiling and shadow quality, completed authored sun/dominant-moon/secondary-moon
|
||
source selection, and finished every automated gate that did not require the
|
||
project owner's physical-display judgment. The owner accepted the subsequent
|
||
live visual/performance round on 2026-08-22 after the default Atmospheric
|
||
exposure was corrected from 1.0 to 0.80. The machine-local Stage 2 rows are now
|
||
complete. Remaining closeout is limited to a second connected remote player on
|
||
a distinct ACE account, unavailable physical-hardware rows, and final owner
|
||
acceptance; it does not add another renderer feature tier.
|
||
|
||
Stage 1's dense-scene regression is pinned by the connected failures already
|
||
captured on 2026-08-22: Atmospheric fell back at 68,395, 67,581, and even
|
||
65,538 combined world matrices against the old 65,536-matrix binding ceiling.
|
||
The corrected connected launch must exceed that historical workload without
|
||
persisting acdream-default fallback or splitting the authoritative pose data.
|
||
|
||
The enhancement is a shader pack, not a rewrite of acdream's renderer or AC's
|
||
art. **acdream's current retail-faithful renderer** remains the default,
|
||
authoritative path. References below to the “default” or “retail-faithful” path
|
||
always mean acdream—not the original retail executable.
|
||
|
||
The evidence and constraints for this design are recorded in the
|
||
[terrain and atmospheric rendering findings](../research/2026-08-21-terrain-and-atmospheric-rendering-findings.md),
|
||
especially [the measured renderer baseline](../research/2026-08-21-terrain-and-atmospheric-rendering-findings.md#5-renderer-state-relevant-to-atmospheric-work)
|
||
and [the requested tier model](../research/2026-08-21-terrain-and-atmospheric-rendering-findings.md#6-wanted-work--atmospheric-rendering-user-stated).
|
||
The approved celestial identity, priority, transform, and direction-versus-
|
||
energy contract are pinned by the
|
||
[Dereth celestial shadow-source research](../research/2026-08-22-dereth-celestial-shadow-sources.md).
|
||
|
||
## Opt-in contract
|
||
|
||
1. **acdream's current renderer is the default.** With no pack selected, the current render graph,
|
||
shaders, render targets, submissions, lighting, colours, and screenshots
|
||
remain authoritative. No enhancement resource or pass is created.
|
||
2. **Selection is explicit.** Installing a pack does not enable it. The user
|
||
selects one pack and one quality preset in Display settings. `acdream
|
||
default (retail-faithful)` is always present and cannot be removed.
|
||
3. **One pack owns the enhancement graph.** Packs do not stack. This prevents
|
||
ambiguous pass ordering, incompatible HDR conventions, and unbounded GPU
|
||
cost.
|
||
4. **The renderer owns the RHI.** A pack declares assets, semantic pass hooks,
|
||
capabilities, resources, and quality variants. It never receives Vulkan
|
||
handles or mutates the authoritative scene, streaming, gameplay, or
|
||
physics owners.
|
||
5. **Failure returns to acdream's default renderer.** Unsupported capabilities,
|
||
malformed assets, shader/pipeline candidate-creation failure, or an invalid
|
||
pass graph disables the complete pack and restores acdream's default path
|
||
with a visible reason. A half-enabled pack is never rendered. A terminal
|
||
`VK_ERROR_DEVICE_LOST` cannot render either path on the lost device; it tears
|
||
down that renderer/device lifetime, and retail remains authoritative while a
|
||
fresh renderer/device is constructed and the pack is validated again.
|
||
6. **Divergence is honest.** Enhanced screenshots are intentionally not retail
|
||
parity evidence. The default path remains the comparison oracle and the
|
||
enhancement choice is recorded in diagnostics and screenshot metadata.
|
||
7. **No scheduling claim.** Rendering phases stay frozen until the M7 polish
|
||
pass unless the project owner explicitly reprioritizes this work.
|
||
|
||
## Capability tiers
|
||
|
||
The costs below are **planning estimates**, not measurements. They are
|
||
incremental GPU p50 targets for a representative discrete GPU at 1920x1080;
|
||
every slice must replace them with physical-hardware measurements. Tier-1
|
||
pixel effects scale with output resolution, so 4K has roughly four times the
|
||
1080p fragment workload. Shadow-map cost depends more on caster count, map
|
||
resolution, and cascade count than on output resolution.
|
||
|
||
| Tier | Contents | Prerequisite | Rough incremental GPU cost at 1080p |
|
||
|---|---|---|---:|
|
||
| acdream default | Current authoritative retail-faithful rendering | Current mandatory Vulkan/RHI capabilities | 0 ms |
|
||
| 0 | **Weather-driven foliage wind** (Campaign VM VM6): procedural-scenery trees/bushes lean, branch-swing, and flutter; their directional-shadow casters apply the identical displacement so the shadow moves with the leaf | Shader ABI v2 (`AtmosphericFrame` gains `uAtmosphereClockWind`/`uAtmosphereWindAmplitude`); the existing `ProceduralSceneryIdAllocator` entity-id namespace for classification | ~0.05 ms (near-zero; ~25 ALU per displaced vertex, zero CPU cost, zero extra draw submissions — an early-out `uint` AND gates every non-foliage vertex) |
|
||
| 1 | Bloom, ACES filmic tonemap, colour grade, vignette | Main-world colour intermediate and fullscreen passes | 0.35–0.80 ms |
|
||
| 1 | Screen-space sun rays (crepuscular) | Authored sun screen position plus an occlusion mask; **no shadow maps** | 0.20–0.50 ms |
|
||
| 2 | **Moving authored sun-and-moon cascaded directional shadows from trees, monsters, players, and houses/buildings** | A second scene pass, selected-celestial view/projection matrices, sampled depth maps, caster pipeline variants | 1.50–3.00 ms |
|
||
| 2+ | Sun-only volumetric light shafts | Reuse Tier-2 shadow infrastructure only while the selected source is the authored sun, plus authored weather | 0.15–0.40 ms |
|
||
| Later | SSAO and water reflections | Scene depth plus normal inputs and separate designs | Not budgeted here |
|
||
| Out | True PBR | AC lacks authored per-texture normal/roughness/metalness maps | Not planned |
|
||
|
||
Tier numbers express prerequisites, not a forced bundle. A pack may offer
|
||
Tier 1 without shadows. Tier 2 always includes the complete shadow-caster
|
||
classes; weak-hardware presets reduce range, cascade count, and resolution
|
||
rather than silently dropping monsters, trees, or buildings.
|
||
|
||
**Foliage wind (Tier 0, Campaign VM VM6).** Deliberately numbered below Tier
|
||
1: it needs no fullscreen pass, no colour intermediate, and no shadow
|
||
infrastructure of its own — only the shader ABI v2 clock/wind block and the
|
||
per-batch classification bits `BatchData.flags` already carries. It composes
|
||
with every other tier (Tier 2's shadow casters read the same displacement so
|
||
a swaying tree's shadow tracks it) and, uniquely among these tiers, is cheap
|
||
enough that a future default-on consideration is plausible; today it ships
|
||
opt-in with the rest of the atmospheric pack, gated by `wind-enabled`.
|
||
|
||
## Tier 2 headline: Dereth's moving authored sun-and-moon shadows
|
||
|
||
The [measured renderer state](../research/2026-08-21-terrain-and-atmospheric-rendering-findings.md#5-renderer-state-relevant-to-atmospheric-work)
|
||
already supplies retail's single directional colour/energy channel from
|
||
`SkyStateProvider`. Tier 2 augments it with the visible authored celestial
|
||
positions documented in the
|
||
[Dereth celestial shadow-source research](../research/2026-08-22-dereth-celestial-shadow-sources.md).
|
||
The camera-relative cascaded map selects, in order, the visible above-horizon
|
||
sun (`0x01001348`), dominant haloed moon (`0x01001F6A`), or secondary moon
|
||
(`0x01001F67`). The selected mesh's exact rendered transform supplies shadow
|
||
direction; retail's one interpolated `DirColor * DirBright` channel supplies
|
||
colour/energy. Moon texture brightness and mesh luminosity never manufacture a
|
||
second world light. As those authored bodies move, tree branches, monsters,
|
||
players, houses, and other eligible world geometry cast correspondingly moving
|
||
shadows.
|
||
|
||
This source selection is an explicit opt-in pack enhancement. It is not a
|
||
claim that the retail executable rendered real-time moon shadows, and it does
|
||
not alter acdream's default retail-faithful scene lighting. Screen-space sun
|
||
rays and volumetric shafts continue to use only the authored sun; they do not
|
||
switch to either moon.
|
||
|
||
The required behavior is:
|
||
|
||
- Terrain and opaque world geometry receive shadows. Terrain, buildings,
|
||
statics, procedural scenery, the local player, remote players, and creatures
|
||
cast them when resident and visible to the main outdoor world.
|
||
- Foliage and other cutout materials use an alpha-sampling shadow fragment
|
||
shader. An empty depth fragment shader would turn each tree plane into a
|
||
solid rectangular shadow.
|
||
- Animated casters reuse the exact per-part transforms already published in
|
||
the N.5 SSBO. The shadow pass must not create a second animation pose or
|
||
gameplay entity projection.
|
||
- Cascades follow the camera and are texel-stabilized. Their reach is clamped
|
||
to the resident two-tier streaming window; the pack does not extend world
|
||
streaming or issue speculative loads.
|
||
- The celestial directional-shadow pass is outdoor-only. Dungeon and EnvCell lighting remains
|
||
authored per-cell lighting. Entering an interior retires or idles outdoor
|
||
shadow work without leaving stale maps on screen.
|
||
- Shadow direction follows the selected visible above-horizon sun, dominant
|
||
moon, or secondary moon. The authored directional colour/energy remains
|
||
`DirColor * DirBright`; active day/weather pack policy may soften or reduce
|
||
it without inventing a second celestial clock, light-energy channel, or
|
||
weather system. A time with no eligible above-horizon body has no
|
||
directional shadow; night is not itself a disable condition.
|
||
- Transparent blend materials do not cast an opaque silhouette by default.
|
||
Only existing opaque and cutout classifications participate until a
|
||
material-specific transparent-shadow contract is designed.
|
||
|
||
The pass reuses the retained resident scene. It must not run PView, portal
|
||
traversal, or per-object CPU visibility classification once per cascade.
|
||
Initially, each cascade draws the bounded resident caster set through the
|
||
existing batched/MDI ownership. If that is too expensive, the next permitted
|
||
step is GPU culling—not repeated CPU culling or per-object submissions.
|
||
|
||
## Pack API surface sketch
|
||
|
||
The public declarations belong in the BCL-only
|
||
`AcDream.Plugin.Abstractions` assembly. The graphical App supplies the
|
||
implementation and translates the declarations to the Vulkan RHI. Headless
|
||
hosts expose no render-pack registry and never load pack assets.
|
||
|
||
This is an API shape, not code committed by this design:
|
||
|
||
```csharp
|
||
public interface IRenderPackPlugin
|
||
{
|
||
void Register(IRenderPackRegistry registry);
|
||
}
|
||
|
||
public interface IRenderPackRegistry
|
||
{
|
||
IDisposable Register(RenderPackDescriptor descriptor, IRenderPackAssets assets);
|
||
}
|
||
|
||
public interface IRenderPackAssets
|
||
{
|
||
Stream OpenRead(string assetKey);
|
||
}
|
||
|
||
public sealed record RenderPackDescriptor(
|
||
string Id,
|
||
string DisplayName,
|
||
Version PackVersion,
|
||
int PackApiVersion,
|
||
RenderPackTier HighestTier,
|
||
IReadOnlyList<RenderCapability> RequiredCapabilities,
|
||
IReadOnlyList<RenderCapability> OptionalCapabilities,
|
||
IReadOnlyList<RenderResourceDeclaration> Resources,
|
||
IReadOnlyList<RenderPassDeclaration> Passes,
|
||
IReadOnlyList<SceneReplayDeclaration> SceneReplays,
|
||
IReadOnlyList<PipelineVariantDeclaration> PipelineVariants,
|
||
IReadOnlyList<RenderQualityPreset> QualityPresets,
|
||
IReadOnlyList<RenderSettingDeclaration> Settings,
|
||
AtmospherePolicyDeclaration? AtmospherePolicy);
|
||
```
|
||
|
||
A pack declares:
|
||
|
||
- a stable ID, display name, pack version, and pack-API version;
|
||
- its highest tier and a human-readable feature summary;
|
||
- mandatory and optional GPU capabilities and per-preset limits;
|
||
- shader assets and fixed renderer semantic inputs, including world colour,
|
||
scene depth, optional normals, selected celestial shadow direction/energy,
|
||
sun direction/screen position for sun-only effects, active weather, camera
|
||
matrices, shadow-caster transforms, and frame time;
|
||
- intermediate images/buffers by relative or absolute extent, format class,
|
||
usage, lifetime, and estimated bytes;
|
||
- passes at renderer-owned hooks such as `ShadowDepthBeforeWorld`,
|
||
`AtmosphereBeforeToneMap`, `ToneMap`, and
|
||
`AfterToneMapBeforePrivateViewports`;
|
||
- renderer-owned scene replays such as `OutdoorDirectionalShadowCasters`, with
|
||
requested cascade views and existing caster/material classes
|
||
(`Terrain`, `OpaqueWorld`, `AlphaCutoutWorld`, `AnimatedOpaque`, and
|
||
`AnimatedAlphaCutout`); the renderer resolves those classes from its
|
||
retained scene and records their existing batched draws;
|
||
- fixed pipeline variants for shadow-caster depth and main-world shadow
|
||
receivers. A variant names its base semantic (`Terrain`, `WorldMesh`, or
|
||
`EnvCell`), shader asset, compatible material classes, and declared inputs
|
||
such as cascade matrices, directional depth maps, and sampler state; it does
|
||
not replace visibility, batching, mesh ownership, or draw submission code;
|
||
- quality presets, user-visible settings with bounded ranges, and declared
|
||
incremental GPU/VRAM budgets; and
|
||
- an atmosphere policy: explicit directional-source/sun-elevation response
|
||
curves and a mapping from AC's categorical `activeDayGroup` values to effect
|
||
multipliers. These values live in the visible pack declaration, not as hidden
|
||
renderer constants; AC remains the owner of celestial position, directional
|
||
energy, and weather state.
|
||
|
||
The renderer—not the pack—defines descriptor layouts, validates SPIR-V and
|
||
resource declarations, resolves semantic scene-replay and pipeline-variant
|
||
requests, builds pipelines, schedules barriers, owns frame-flight and teardown,
|
||
and supplies immutable frame inputs. Packs cannot add arbitrary draw callbacks,
|
||
read gameplay owners, submit command buffers, retain borrowed frame views, or
|
||
address resources outside their registration. The built-in pack's Tier-2
|
||
caster pass and receiver shaders must be expressible entirely through these
|
||
same public declarations.
|
||
|
||
### Selection and fail-safe lifecycle
|
||
|
||
1. Discover manifests and descriptors without creating GPU objects.
|
||
2. Show compatibility and estimated cost in Display settings. Unsupported
|
||
packs remain visible with the exact missing capability; they cannot be
|
||
selected.
|
||
3. On explicit selection, validate the whole descriptor, all assets, resource
|
||
ceilings, hooks, and shader interfaces; then build a complete candidate
|
||
pipeline set off to the side.
|
||
4. Atomically activate the candidate only after every required object exists.
|
||
Until then acdream's default path continues rendering.
|
||
5. Persist `pack id + pack version + preset`, never a positional index. If the
|
||
pack disappears or becomes incompatible, select `acdream default` and
|
||
retain the failure notice.
|
||
6. On runtime validation or post-recreation candidate failure, withdraw all
|
||
pack passes/resources at a frame boundary and resume acdream's default
|
||
renderer. Do not repeatedly retry a failing pack during the session.
|
||
7. Unload and reconnect use the normal render-generation and GPU-flight
|
||
retirement rules. No pack object may retain a world generation, scene
|
||
entity, or collectible plugin load context.
|
||
|
||
In this campaign, **device recreation** means disposing the complete old
|
||
renderer, Vulkan context, and device, then constructing a fresh context/device,
|
||
re-probing capabilities, and validating selection again with retail active
|
||
until the candidate is complete. It does **not** mean live, in-process recovery
|
||
from `VK_ERROR_DEVICE_LOST`; device loss remains terminal to that renderer and
|
||
device lifetime.
|
||
|
||
The built-in Atmospheric Rendering pack should be the first consumer of this
|
||
same API. It must not receive private renderer shortcuts that third-party packs
|
||
cannot express.
|
||
|
||
The public v1 authoring surface, manifest schema, shader semantic bindings,
|
||
failure guidance, validator command, and external no-op sample are indexed by
|
||
the [render-pack SDK](../render-packs/README.md).
|
||
|
||
## Frame-graph placement
|
||
|
||
With the pack off, the frozen retail graph is unchanged. With a pack selected,
|
||
the renderer builds a separate enhancement graph:
|
||
|
||
1. Update the existing immutable world frame, including authored sky objects,
|
||
the retail directional colour/energy channel, and weather.
|
||
2. Outdoors, select the visible above-horizon sun/dominant moon/secondary moon
|
||
direction and render Tier-2 cascaded shadow depth from the resident caster
|
||
set.
|
||
3. Render the main world to the pack's world-colour intermediate, using
|
||
pack-selected pipeline variants to sample the shadow map where requested.
|
||
4. Preserve the established PView, punch/seal depth discipline, shared-alpha
|
||
ordering, particle ordering, and world transparency boundaries.
|
||
5. Generate screen-space sun occlusion/rays or, only while the shadow source is
|
||
the sun, shadow-map volumetrics.
|
||
6. Composite rays/shafts **before tonemapping**, so bloom sees them and the
|
||
filmic curve rolls them off instead of clipping them.
|
||
7. Apply tonemap, colour grade, and vignette to the main world image.
|
||
8. Continue with private portal/paperdoll/appraisal viewports and retained UI
|
||
on their existing path. They are not accidentally post-processed with the
|
||
main world.
|
||
|
||
## Delivery slices and acceptance
|
||
|
||
The slice labels below are local to this document. They are not phase IDs.
|
||
|
||
### Pre-moon checkpoint, Stage 1 acceptance, and Stage 2 start — 2026-08-22
|
||
|
||
Before the approved moon extension, all seven local slices (0–6) had production
|
||
implementations in the current worktree. A source-identical isolated clean
|
||
snapshot closed that sun-only reference-GPU physical matrix, and one physical
|
||
integrated-AMD Auto safe-fallback row was also present. Those artifacts remain
|
||
valid evidence for the exact binaries and sun-only scope they measured; they
|
||
are not moon-alignment, source-transition, current-worktree, or final user-
|
||
acceptance evidence.
|
||
|
||
Stage 1's automated implementation and validation are complete. The authored
|
||
sun/dominant-moon/secondary-moon resolver and its direction-versus-energy
|
||
handoff are present and covered without inferring physical quality from unit
|
||
tests, screenshots, or historical sun-only rows. The subsequent live ACE round
|
||
covered the owner-reported shadow visibility/configuration, temporal
|
||
pixelation/shimmer, frame-pacing/desktop responsiveness, selection/fullscreen
|
||
regressions, and matched indoor/outdoor exposure. After the exposure correction
|
||
the owner accepted the live result. The exact evidence and limits are recorded
|
||
in the [Stage 1 live-gate report](../research/2026-08-22-atmospheric-stage1-live-gate.md).
|
||
|
||
Current authored-celestial Stage 1 automated gate (2026-08-22):
|
||
|
||
- The shader compiler reports **24/24** Vulkan shader pairs ready. Incremental
|
||
regeneration expands only pack includes and preserves all 18 pre-campaign
|
||
retail SPIR-V artifacts byte-for-byte; the exact SHA-256 oracle and complete
|
||
source-manifest checks pass. All selected-celestial binding-6 modules expose
|
||
the 336-byte ABI v1 layout, including source kind at offset 320.
|
||
- Focused Release validation passes **344/344** App renderer tests, **30/30**
|
||
standalone SDK/pack-validator tests, **14/14** Core sky-loader tests, and
|
||
**48/48** MossTank tests. Both external Tier-2 samples embed and validate the
|
||
current selected-celestial shader ABI without App or Vulkan dependencies.
|
||
- The repository's forced locked restore passes. The complete Release solution,
|
||
including all source, tests, tools, and SDK samples, builds with **0 warnings
|
||
and 0 errors** after that restore.
|
||
- The repository-owned fresh-process hermetic gate passes
|
||
**14,928/14,928** tests with zero skips or failures across 14 assemblies
|
||
**under the repository's hermetic lane filter** (Manual/Timing/Live/
|
||
InstalledDat/Diagnostic lanes excluded; a raw `dotnet test AcDream.slnx`
|
||
reports those lanes as skips/failures by design — VM4 correction);
|
||
`AcDream.App.Tests` contributes **5,823/5,823**. Evidence is under
|
||
`artifacts/atmospheric-rendering/stage1-moon-release-gate/`.
|
||
- The App total includes the 9,500-caster 256-frame zero-managed-allocation
|
||
steady-state fixture, warmed CPU/GPU sampling allocation gates, the complete
|
||
12-cycle Low/Medium/High/retail/resize/failure/recovery/frame-flight/
|
||
generation convergence fixture, and independent renderer/context/device
|
||
recreation. These prove the non-physical performance and lifetime contracts;
|
||
they do not claim physical frame pacing or image quality.
|
||
- A final path audit finds no source changes under `src/AcDream.Runtime`, no
|
||
physics or collision changes, and no changes to the retail GLSL sources or
|
||
tracked retail SPIR-V binaries. Pack-off production integration remains the
|
||
strict authoritative-path oracle.
|
||
|
||
The command-level record and evidence boundary are in the
|
||
[Stage 1 automated gate report](../research/2026-08-22-atmospheric-stage1-automated-gate.md).
|
||
|
||
Recorded pre-moon automated checkpoint (not a current moon-scope completion
|
||
claim):
|
||
|
||
- The repository-owned fresh-process Release test stage passes
|
||
**14,880/14,880** tests with zero skips or failures across 14 assemblies
|
||
(hermetic lane filter, as above).
|
||
`AcDream.App.Tests` contributes **5,783/5,783**; campaign-focused App cases
|
||
cover descriptor/asset/SPIR-V
|
||
validation, pack-off/no-op invariants, atomic asynchronous candidate swaps,
|
||
runtime fallback, declared settings, Tier-1/Tier-2/Tier-2+ graph execution,
|
||
all headline caster classes, topology caching, exact animated transforms,
|
||
Low/Medium/High/Auto policy, diagnostics, and the pack UI.
|
||
- Headless plugin-session tests pass **6/6**, including rejection of a
|
||
render-pack-only request before its DLL is loaded.
|
||
- The SDK validator suite passes **26/26** and builds/validates the external
|
||
`AcDream.RenderPacks.NoOp`, `AcDream.RenderPacks.AtmosphericTier2`, and
|
||
`AcDream.RenderPacks.ShadowsOnlyTier2` samples without App or Vulkan
|
||
references.
|
||
- The production catalog is revisioned rather than frozen at startup. The same
|
||
composed controller/UI observes external registration, withdrawal, and
|
||
corrected re-registration; an active withdrawn pack retires at the next
|
||
frame boundary, persists retail fallback, releases its asset/context owners,
|
||
and does not retry the removed registration. Runtime package admission now
|
||
matches the SDK: exactly one public constructible render-pack entry point and
|
||
at least one live registration, with transactional rollback for malformed,
|
||
multiple, internal, zero-registration, and partially failing packages.
|
||
- The retained 9,500-caster warmed-frame fixture performs no second-frame
|
||
scene-index copy, topology rebuild, sort, or classification and allocates
|
||
zero managed bytes. Animated-static, live-dynamic, and equipped-child root
|
||
and part transforms refresh through cached IDs/slots with exact float bits.
|
||
- Render and screenshot diagnostics now publish exact accepted counts for
|
||
terrain commands, outdoor statics, buildings, animated statics, local
|
||
players, remote players, non-player creatures, other live dynamics, and
|
||
equipped children. These labels stop at the authoritative evidence boundary:
|
||
static DAT publication does not distinguish a tree from other outdoor
|
||
scenery, and create-object render metadata does not distinguish a hostile
|
||
monster from a non-hostile NPC creature. Diagnostics therefore report
|
||
`OutdoorStatics` and `NonPlayerCreatures`; they never infer tree or monster
|
||
identity from a mesh or ID.
|
||
- The recording-RHI long-cycle gate repeatedly crosses Low, Medium, High, and
|
||
retail selection; resize; injected candidate failure and explicit recovery;
|
||
both frame-flight slots; render-generation replacement; and final renderer
|
||
disposal. Pack resources, pipeline-format leases, texture slots, retained
|
||
transforms, receiver candidates, and registrations converge exactly. A
|
||
second fixture proves that device recreation is old-renderer/context/device
|
||
teardown followed by an independent fresh device and activation generation.
|
||
- Therefore the deterministic lifecycle implementation, recording-RHI
|
||
convergence, and fresh-device recreation definition are locally closed. The
|
||
executable connected route and its contract assertions are implemented for
|
||
select/disable/re-enable, exact resize, authored time/weather changes, and
|
||
fresh-process recreation, but a contract-tested route is not connected-world
|
||
evidence; its ACE-backed execution and artifacts remain open below.
|
||
- The complete Release solution, including all three SDK samples, the
|
||
validator, shader compiler/generated manifest, and repository tools, builds
|
||
with **0 warnings and 0 errors**. This historical checkpoint could not repeat
|
||
locked restore because that managed workspace denied NuGet access to the
|
||
user-profile `NuGet.Config`; the later Stage 1 moon gate and final Stage 2
|
||
gate supersede that limitation and both report forced locked restore green.
|
||
|
||
The corresponding durable source/test entry points are:
|
||
|
||
- public contracts and SDK:
|
||
`src/AcDream.Plugin.Abstractions/Rendering/`, `docs/render-packs/`,
|
||
`tools/RenderPackValidator/`, `samples/AcDream.RenderPacks.*`, and
|
||
`tests/AcDream.RenderPackValidator.Tests/`;
|
||
- activation, compatibility, Auto, diagnostics, and built-in graph:
|
||
`src/AcDream.App/Rendering/Packs/` and
|
||
`tests/AcDream.App.Tests/Rendering/Packs/`;
|
||
- moving authored-celestial cascades, casters, receivers, and retained topology:
|
||
`src/AcDream.App/Rendering/DirectionalShadow*.cs`,
|
||
`src/AcDream.App/Rendering/Packs/AuthoredCelestialShadowSource.cs`,
|
||
`src/AcDream.App/Rendering/Scene/DirectionalShadowCasterFrame.cs`,
|
||
`src/AcDream.App/Rendering/Wb/WbDrawDispatcher.DirectionalShadows.cs`, and
|
||
`tests/AcDream.App.Tests/Rendering/DirectionalShadow*` plus
|
||
`tests/AcDream.App.Tests/Rendering/Packs/AuthoredCelestialShadowSourceResolverTests.cs`;
|
||
- retained Display UI and headless boundary:
|
||
`src/AcDream.App/UI/Layout/ConfigOptionsPageController.cs`,
|
||
`tests/AcDream.App.Tests/UI/Layout/ConfigOptionsPageControllerTests.cs`, and
|
||
`tests/AcDream.Headless.Tests/HeadlessPluginSessionTests.cs`.
|
||
|
||
Machine-local offline/physical evidence currently present under
|
||
`artifacts/atmospheric-rendering/` is gate evidence, but it is not a substitute
|
||
for connected-world or project-owner acceptance:
|
||
|
||
- `smoke-retail-720p/` records the pack-off `retail/off` path with zero pack
|
||
resources, casters, cascades, or classification calls;
|
||
- `accept-shadow-morning-200m/`, `accept-shadow-afternoon-200m/`, and
|
||
`accept-shadow-morning-close/` contain fixed-camera moving-sun shadow
|
||
screenshots plus metadata for 9,498 resident casters and three cascades;
|
||
these pre-moon captures do not prove moon alignment or source transitions;
|
||
- `volumetric-valid-camera-500m/` contains a High-preset volumetric diagnostic
|
||
capture; it is not a performance acceptance row;
|
||
- `matrix-clean-snapshot-dense-linear-v20/` is the current complete AMD Radeon
|
||
RX 9070 XT physical matrix: **30/30 rows pass** across
|
||
retail/Low/Medium/High/Auto, 1080p/1440p/4K, and capped/uncapped pacing. The
|
||
actual worktree's 4,397 source files were copied and hash-verified into an
|
||
isolated clean snapshot at commit `4876c970`; the Release App product version
|
||
names that exact commit, source and binary identities match, and tracked
|
||
status is empty. Its 18 active enhanced rows each own exact 2,048-sample
|
||
CPU/receiver/GPU windows, 9,498 casters, and zero warmed classification calls.
|
||
Six rows are retail and six 4K Low/Medium/Auto rows are accepted
|
||
resource-unavailable fail-safe outcomes;
|
||
- `matrix-final-v16-exact-auto/` and the two `current-low-1080p-*-v20/`
|
||
captures retain the optimization's predecessor/reference trail; the clean
|
||
snapshot matrix above supersedes them as current reference-adapter evidence;
|
||
- all six retail rows record zero pack resources, passes, casters, cascades,
|
||
draws, or dispatches. The six unavailable 4K Low/Medium/Auto rows likewise
|
||
record zero pack work and pass their strict paired-default framebuffer
|
||
comparisons instead of rendering a half-enabled graph;
|
||
- `igpu-auto-safe-fallback-v7-paired/` records physical Auto behavior on the
|
||
integrated **AMD Radeon(TM) Graphics** adapter (Vulkan 1.4.315, driver
|
||
2.0.353). After 180 stable Low samples, Auto failed safe with the exact reason
|
||
`GPU p99 19.308 ms (budget 3.000 ms), CPU p99 0.534 ms (budget 0.500 ms),
|
||
resident GPU bytes 41648404 (budget 67108864)`. The published state is
|
||
`retail/off`, has zero pack resources or work, and retains that visible
|
||
reason. Its comparison against the paired time-matched retail artifact
|
||
`igpu-retail-current-v6-time-matched/`, using `sky-mask.png`, differs in only
|
||
**56 / 1,536,000 compared pixels**, a **0.003645833% (0.00365%) sky-masked
|
||
pixel difference**, below the 0.1% gate. This closes physical weak-adapter
|
||
safe fallback, not active Low performance on that adapter or the remaining
|
||
GPU matrix;
|
||
- `compare-retained-transform.json` records the retained-transform image
|
||
comparison used by the 9,500-caster steady-state gate.
|
||
|
||
Stage 1 project-owner gate:
|
||
|
||
- **PASS — accepted by the project owner on 2026-08-22.** The acceptance closes
|
||
Stage 1's physical-display and desktop-performance stop. It authorizes Stage
|
||
2; it is not a substitute for Stage 2's connected scenario, long-lifetime,
|
||
package lifecycle, additional physical-GPU, or final pack-off/pack-on rows.
|
||
|
||
Stage 2 machine-local closeout result (2026-08-22):
|
||
|
||
The exact commands, commits, metrics, artifacts, and evidence limits are in the
|
||
[Stage 2 connected and closeout report](../research/2026-08-22-atmospheric-stage2-connected-gate.md).
|
||
|
||
1. **PASS, except the external second-client row.** The connected graphical
|
||
route covered moving local players, known monster encounters
|
||
reported under the authoritative `NonPlayerCreatures` category, and equipped
|
||
children; landblock publication/demotion; clear, overcast and rain;
|
||
outdoor/interior/dungeon transitions; portal travel and reconnect. Capture
|
||
the implemented select/disable/re-enable, resize, authored sun/moon source
|
||
transitions and weather, and
|
||
fresh-process renderer/context/device-recreation assertions against a real
|
||
ACE session, proving exact resource convergence and no stale maps/owners.
|
||
The implemented two-client gate proved the observer login and movement, but
|
||
ACE rejected the concurrent primary login when both used the available
|
||
account. The gate now requires dedicated observer environment credentials,
|
||
keeps them out of its artifacts, and permits independent character indexes;
|
||
a distinct-account connected run must close the authoritative nonzero
|
||
`RemotePlayers` row.
|
||
2. **EXTERNAL HARDWARE GATE.** Repeat the current clean-source RX 9070 XT
|
||
pack-off/Low/Medium/High/Auto × 1080p/1440p/4K × capped/uncapped matrix on
|
||
every other supported physical GPU class. The integrated-AMD Auto-to-retail
|
||
artifact proves weak-adapter safe fallback only; it does not prove active Low
|
||
or the complete matrix on that adapter. Automated weak-GPU fixtures, one
|
||
fallback row, and one high-end reference adapter do not prove the remaining
|
||
physical rows.
|
||
3. **FINAL OWNER GATE.** Complete the visual matrix for Tier-1 neutral values and private-view/UI
|
||
isolation; rays at dawn/noon/dusk, behind-camera and occluded states;
|
||
foliage cutouts; moving animated shadows under sun and moon; indoor gating;
|
||
source-transition continuity; temporal pixelation/shimmer; bias/cascade seam
|
||
review; sun-only volumetric weather/occluder behavior; and pack-off
|
||
restoration.
|
||
4. **PASS.** External install/select/update/remove/fail/recover flows passed in
|
||
six fresh connected graphical processes. The nine-stop Medium lifetime route
|
||
passed with graceful shutdown, as did the deterministic 12-cycle and
|
||
fresh-device convergence fixtures.
|
||
5. **FINAL OWNER GATE.** Obtain explicit project-owner acceptance of the final pack-off and pack-on
|
||
visual/performance matrix before changing this document to shipped.
|
||
|
||
### Slice 0 — Contract, capability probe, and acdream-default no-op
|
||
|
||
**Implementation:** complete. The BCL-only v1 ABI, live revisioned plugin
|
||
discovery/catalog, retained Display selection, compatibility/cost summaries,
|
||
strict SDK-equivalent entry admission, asynchronous candidate preparation,
|
||
frame-boundary activation/withdrawal/fallback, registration-scoped no-retry,
|
||
stable diagnostics, no-op sample, and headless exclusion are present and
|
||
automated. The checked-in default-path oracle and RX 9070 XT physical pack-off
|
||
rows pass; connected lifetime and graphical package evidence now pass. The
|
||
remaining supported physical GPU classes stay open.
|
||
|
||
Define the versioned BCL-only descriptor/registry, manifest fields, semantic
|
||
bindings, pack discovery, Display selection, diagnostics, and atomic
|
||
activation/fallback transaction. Implement a no-op conformance pack only.
|
||
|
||
**Acceptance:** `acdream default (retail-faithful)` remains selected on clean and upgraded
|
||
installs; pack discovery allocates no GPU resources; the disabled run has the
|
||
same pass list, pipeline set, draw/dispatch counts, deterministic framebuffer
|
||
digests, and resource ledger as the pre-campaign baseline; malformed,
|
||
unsupported, missing, and shader-invalid fixtures all report one precise
|
||
reason and render acdream's default path without partial resources or retry loops; headless
|
||
hosts load no render assemblies or pack assets.
|
||
|
||
### Slice 1 — Tier-1 world-colour and filmic stack
|
||
|
||
**Implementation:** complete. The pack-owned main-world target, bloom chain,
|
||
ACES filmic pass, colour grade, vignette, declared neutral settings, resize
|
||
recreation, and private-viewport/UI placement are implemented and automated.
|
||
The RX 9070 XT 1080p/1440p/4K physical budget rows pass. Project-owner visual
|
||
acceptance and the remaining supported physical GPU classes stay open.
|
||
|
||
Add the main-world intermediate and implement bloom, ACES filmic tonemapping,
|
||
colour grade, and vignette through the pack API. Supply half/quarter-resolution
|
||
variants and preserve private viewports/UI.
|
||
|
||
**Acceptance:** every effect can be independently set to its neutral value;
|
||
the preset is deterministic across resize/recreate; UI, paperdoll, portal, and
|
||
appraisal surfaces retain their accepted colours; 1080p/1440p/4K captures show
|
||
no clipping, haloing at the world/UI edge, stale frame, or resource leak; the
|
||
slice meets its preset GPU/VRAM budget.
|
||
|
||
Campaign VM VM3 (2026-08-22) moved the post stack to linear light: every
|
||
world/ray/volumetric read is decoded with the 2.2 display assumption; the
|
||
bloom intermediate is already linear (decoded once at extraction, so
|
||
downstream blur/composite reads need no further decode). Tonemap/grade/
|
||
vignette run in linear and the result is re-encoded; the post stack's
|
||
neutral settings are a numerical identity (measured on a real frame at
|
||
Campaign VM VM3: ≤1 LSB on 99.99 % of pixels; 95 foliage-silhouette pixels
|
||
— 58 isolated — differ by up to 73 LSB from cutout-edge rasterization between
|
||
two separate client runs, none on any surface).
|
||
|
||
### Slice 2 — Tier-1 screen-space sun rays
|
||
|
||
**Implementation:** complete. Authored sun projection, the screen-space
|
||
occlusion mask, declared sun/day-group/weather policy, pre-tonemap ray
|
||
composition, and deterministic disabled gates are implemented and automated.
|
||
Connected time/weather transitions pass; physical-display acceptance for
|
||
dawn/noon/dusk, behind-camera, occlusion, and edge-flicker behavior remains in
|
||
the final owner visual matrix.
|
||
|
||
Project the existing authored sun position, build a screen-space occlusion
|
||
mask, and composite weather-driven crepuscular rays before tonemapping. This
|
||
slice deliberately has no shadow-map dependency.
|
||
|
||
**Acceptance:** clear dawn/dusk produces visible raking rays, noon makes them
|
||
vanish, overcast/rain mutes them, the sun behind the camera or fully occluded
|
||
produces none, and camera edges do not streak or flicker. The pack descriptor's
|
||
sun-elevation and `activeDayGroup` policy deterministically produces those
|
||
states without a second weather/clock owner. The exact same scene with Tier 1
|
||
disabled returns to the Slice-0 digest from acdream's default
|
||
retail-faithful renderer.
|
||
|
||
### Slice 3 — Tier-2 moving authored sun-and-moon dynamic shadows
|
||
|
||
**Implementation:** Stage 1 automated and project-owner live gates complete.
|
||
Camera-relative stabilized cascades,
|
||
outdoor gating, opaque and alpha-cutout casters, terrain/world receivers,
|
||
headline caster membership, exact current animated transforms, bounded
|
||
resident replay, GPU-flight ownership, and cached topology/dynamic-transform
|
||
refresh were present at the sun-only checkpoint. The approved authored
|
||
sun/dominant-moon/secondary-moon resolver and direction-versus-energy handoff
|
||
are now present, and focused plus complete fresh-process automated validation
|
||
pass. The project owner's 2026-08-22 live round accepted source alignment,
|
||
temporal stability, desktop responsiveness, and the final exposure correction.
|
||
Per-class diagnostics cover
|
||
terrain commands, outdoor
|
||
statics, buildings, animated statics, local/remote players, non-player
|
||
creatures, other live dynamics, and equipped children without inventing tree
|
||
or hostile-monster identity. Fixed-camera morning/afternoon artifacts are not
|
||
moon evidence; the live-gate result and its exact boundary are recorded in the
|
||
[Stage 1 live-gate report](../research/2026-08-22-atmospheric-stage1-live-gate.md).
|
||
The machine-local Stage 2 connected and closeout matrix passes. The external
|
||
second-client, additional-GPU, and final owner rows above remain open.
|
||
|
||
This is the campaign's headline slice. Add camera-relative cascades, opaque
|
||
and alpha-cutout caster variants, animated SSBO transforms, shadow receivers,
|
||
texel stabilization, outdoor gating, and weather/authored-directional-energy
|
||
control. Select the exact rendered direction of the visible above-horizon sun,
|
||
dominant haloed moon, or secondary moon according to the
|
||
[celestial source contract](../research/2026-08-22-dereth-celestial-shadow-sources.md),
|
||
while retaining retail's one `DirColor * DirBright` energy channel. Trees,
|
||
monsters, players, houses/buildings, terrain, and ordinary outdoor statics
|
||
participate through existing scene ownership.
|
||
|
||
**Acceptance:** in fixed-camera and live dawn/noon/dusk/night captures, shadows
|
||
align with and change direction/length under Dereth's authored sun and selected
|
||
dominant/secondary moon; overlap and no-source transitions are stable and do
|
||
not snap to an unrelated body. Walking players and monsters cast and
|
||
self-shadow from their current animated poses; foliage casts leaf/branch
|
||
cutouts rather than rectangles; houses and procedural trees retain shadows
|
||
through landblock publication/demotion without popping outside the chosen
|
||
cascade transition tolerance; indoor/dungeon captures have no outdoor
|
||
celestial directional shadow; portal/reconnect/device recreation leaves zero
|
||
stale maps or owners. Acne, Peter-panning, cascade seams, distant depth-bias
|
||
leaks, temporal pixelation/shimmer, and desktop performance pass the live user
|
||
gate and subsequent Stage 2 matrix; the dense-Arwic CPU submission and GPU
|
||
budgets pass.
|
||
|
||
### Slice 4 — Quality scaling and automatic compatibility
|
||
|
||
**Implementation:** complete. Low/Medium/High declarations, capability and
|
||
memory admission, preset cost summaries, retained Display controls, the
|
||
built-in Automatic checkbox, hysteretic Auto, diagnostics, asynchronous
|
||
off-side candidate preparation, and atomic stable-boundary swaps are present
|
||
and automated. The source-identical clean-snapshot RX 9070 XT matrix passes all
|
||
30 current rows after the Low dense-pose CPU optimization. The integrated-AMD
|
||
physical row proves that persistently over-budget Low returns Auto atomically to
|
||
retail with a visible reason and a paired-retail framebuffer match. Active Low
|
||
on that adapter and additional supported-adapter matrices remain open.
|
||
|
||
Land the Low/Medium/High presets, memory ceilings, capability-based preset
|
||
availability, stable cascade fitting, resize handling, and optional hysteretic
|
||
Auto selection. Auto may change resolution/range only at a stable frame
|
||
boundary and must expose its current choice.
|
||
|
||
**Acceptance:** every supported preset retains all headline caster classes;
|
||
weak-hardware fixtures select a valid lower preset or fail safely to acdream's
|
||
default renderer;
|
||
changing preset cannot leak, stall the render thread, invalidate streaming, or
|
||
leave mixed-resolution resources; the quality/performance table is populated
|
||
with measured physical-hardware results.
|
||
|
||
### Slice 5 — Tier-2+ volumetric shafts
|
||
|
||
**Implementation:** complete for the recorded sun-only scope. The declared
|
||
volumetric pass reuses directional-shadow depth only when the selected source
|
||
is the authored sun, consumes authored sun/weather/indoor inputs, composites
|
||
before tonemapping, and has independent quality/step settings and automated
|
||
failure gates. The reference-GPU low-sun 2,048-sample enabled/neutral A/B passes
|
||
its incremental cost target. Moon selection does not enable moon shafts.
|
||
Connected weather/lifecycle transitions pass; physical-display
|
||
occluder/weather acceptance in the final owner matrix and additional physical
|
||
GPU classes remain open.
|
||
|
||
Reuse the directional shadow map for world-space light shafts only while its
|
||
source is the authored sun. Drive density, strength, and colour from authored
|
||
sun/weather inputs and composite before tonemapping. A selected moon produces
|
||
directional shadows but no rays or volumetric shafts.
|
||
|
||
**Acceptance:** shafts respect terrain, trees, houses, and moving creatures;
|
||
clear low sun is strongest, overcast and indoor scenes are muted/off; disabling
|
||
shafts leaves Tier-2 shadow output unchanged; the incremental cost stays within
|
||
the Tier-2+ budget.
|
||
|
||
### Slice 6 — Pack SDK and campaign closeout
|
||
|
||
**Implementation:** SDK deliverables complete and the Stage 1 project-owner
|
||
gate passed on 2026-08-22. The v1
|
||
manifest schema, semantic binding table, compatibility/failure guide,
|
||
validator, built-in pack, and three buildable external samples are present and
|
||
automated. Connected graphical package lifecycle and long-run convergence pass.
|
||
The distinct-account second-client remote-player row, remaining physical GPU
|
||
classes, and final project-owner acceptance remain open; the 30-row RX 9070 XT
|
||
reference matrix is complete.
|
||
|
||
Publish the manifest/schema, semantic binding table, sample no-op pack,
|
||
Atmospheric pack, compatibility diagnostics, authoring/validation tool, and
|
||
failure-handling guidance. Run the full automated, connected, physical-display,
|
||
performance, lifetime, portal, and screenshot matrix.
|
||
|
||
**Acceptance:** a clean external sample builds without App or Vulkan
|
||
references; install/select/update/remove/fail/recover flows work; pack-off
|
||
evidence from acdream's default retail-faithful renderer remains authoritative
|
||
and unchanged; all resource ledgers
|
||
converge after long play, reconnect, portal travel, pack disable, and device
|
||
recreation; the project owner accepts the visual matrix before the campaign is
|
||
declared shipped.
|
||
|
||
## Performance budget and measurement
|
||
|
||
The [measured pre-campaign baseline](../research/2026-08-21-terrain-and-atmospheric-rendering-findings.md#performance-baseline-and-the-binding-constraint)
|
||
is **519.7 FPS with CPU/GPU p50 of 1.869/1.096 ms**, and dense towns are
|
||
CPU-submission-bound. Fullscreen work may occupy currently idle GPU time, but
|
||
it is not treated as free. Shadow cascades must protect the CPU submission
|
||
path.
|
||
|
||
| Preset | Incremental GPU p50 / p99 at 1080p | Incremental render-CPU p50 / p99 | Pack-owned resident GPU memory |
|
||
|---|---:|---:|---:|
|
||
| Low | ≤ 2.0 / 3.0 ms | ≤ 0.15 / 0.50 ms | ≤ 64 MiB |
|
||
| Medium | ≤ 3.25 / 4.50 ms | ≤ 0.25 / 0.75 ms | ≤ 128 MiB |
|
||
| High | ≤ 4.50 / 6.00 ms | ≤ 0.35 / 1.00 ms | ≤ 256 MiB |
|
||
|
||
The current physical reference matrix is
|
||
`artifacts/atmospheric-rendering/matrix-clean-snapshot-dense-linear-v20/` on an
|
||
AMD Radeon RX 9070 XT (Vulkan 1.4.349, driver 2.0.395). The source-identical
|
||
isolated commit and Release binary both identify `4876c970`; tracked source
|
||
status is empty. All 30 rows pass. At capped 1080p, the exact 2,048-sample
|
||
windows are:
|
||
|
||
| Selection | Incremental render-CPU p50 / p99 | Inclusive GPU p50 / p99 | Resident pack memory |
|
||
|---|---:|---:|---:|
|
||
| Low | 0.108 / 0.164 ms | 0.900 / 1.002 ms | 39.719 MiB |
|
||
| Medium | 0.116 / 0.144 ms | 1.001 / 1.023 ms | 73.590 MiB |
|
||
| High | 0.121 / 0.145 ms | 1.240 / 1.273 ms | 113.556 MiB |
|
||
| Auto (settled High) | 0.122 / 0.146 ms | 1.211 / 1.222 ms | 113.556 MiB |
|
||
|
||
Every uncapped active row also passes. Across capped and uncapped active rows,
|
||
the maximum measured p50/p99 and resident memory are: Low 0.108/0.164 ms CPU,
|
||
1.070/1.080 ms GPU, 60.868 MiB; Medium 0.117/0.194 ms CPU, 1.152/1.163 ms GPU,
|
||
103.583 MiB; High 0.121/0.159 ms CPU, 2.237/2.252 ms GPU, 238.141 MiB; and Auto
|
||
0.122/0.166 ms CPU, 1.482/1.494 ms GPU, 145.856 MiB. All six retail rows record
|
||
zero pack resources/work. At 4K, Low needs 131,302,400 bytes and Medium/initial
|
||
Auto need 198,440,960 bytes, so those six capped/uncapped rows correctly report
|
||
`ResourceUnavailable`, create no pack resources/work, and pass their strict
|
||
paired-default framebuffer comparisons. This closes the current reference
|
||
adapter, not the connected receiver A/B route or other supported/weak physical
|
||
GPU classes.
|
||
|
||
Tier 2+'s separate low-sun physical A/B is recorded in
|
||
`artifacts/atmospheric-rendering/volumetric-performance-ab-1080p.json`. Both
|
||
runs pin High, 1080p uncapped, clear weather, 16.667° sun elevation, the same
|
||
50 m / 180° / 10° camera, 9,498 casters, four cascades, and exact 2,048-sample
|
||
windows. Enabling one volumetric draw over the neutral-strength run adds
|
||
**0.189 ms GPU p50 / 0.219 ms p99**, **0.009 ms CPU p50 / 0.007 ms p99**, and
|
||
4,147,200 resident bytes. The measured GPU p50 passes the Tier-2+ ≤0.40 ms
|
||
reference target; connected weather/occluder behavior and other adapters still
|
||
require their own rows.
|
||
|
||
acdream's default path has a stricter gate: zero new enhancement passes,
|
||
images, buffers, submissions, or shader variants, with CPU/GPU deltas within
|
||
the existing run-to-run noise envelope and deterministic reference captures
|
||
unchanged. `NoOpRenderPackProductionIntegrationTests` pins the pass list,
|
||
pipeline set, draw/dispatch tuple, framebuffer SHA-256, and resource ledger of a
|
||
**2x2 synthetic, one-draw composition fixture on a recording device that does
|
||
not rasterize** — it proves the controller arm adds nothing to that shape, not
|
||
that the production frame is unchanged. The matrix's six physical retail rows
|
||
record zero pack work at all three resolutions and both pacing modes. The
|
||
actual pack-off pixel and production-performance invariance against the
|
||
pre-campaign build `6c79d35c` was established later by Campaign VM slice VM0
|
||
([report](../research/2026-08-22-vm0-default-path-invariance.md), corrected
|
||
2026-08-22).
|
||
|
||
Measurement protocol:
|
||
|
||
- Use existing asynchronous GPU timestamps and frame diagnostics. Never add a
|
||
`glFinish`/device-idle-style measurement fence to the frame loop.
|
||
- Runtime Auto compares the declared incremental CPU budget with pack-added
|
||
target-preparation, shadow, post, and volumetric recording only. The complete
|
||
enhanced main-world receiver recording is retained separately as an absolute
|
||
CPU diagnostic; it is not itself an incremental delta. GPU accounting remains
|
||
conservatively inclusive of the complete enhanced receiver pass and every
|
||
resolved pack pass, exactly once after asynchronous resolution. Identical
|
||
pack-off/on runs remain the authority for the final receiver CPU delta and
|
||
the complete physical incremental A/B result.
|
||
- Run capped and uncapped Release builds; record CPU/GPU p50, p95, and p99,
|
||
FPS, draw/dispatch submissions, shadow-caster count, cascade draw count,
|
||
transient/retained GPU bytes, and process working/private memory.
|
||
- Compare pack off, Low, Medium, and High with identical camera paths, render
|
||
resolution, active day group, authored celestial/time keyframe, entity set,
|
||
and warmed residency.
|
||
- Cover pinned dense Arwic, a foliage-heavy outdoor route, a building cluster,
|
||
moving-player/monster combat, dawn/noon/dusk/night plus sun/moon/no-source
|
||
transitions, clear/overcast/rain, a dungeon, portal travel, resize, reconnect,
|
||
and a long lifetime run.
|
||
- Measure 1920x1080, 2560x1440, and 3840x2160 on each supported physical GPU
|
||
class. Report—not hide—unavailable presets.
|
||
- No cascade may rerun CPU PView/portal traversal or issue per-object draws.
|
||
The pass records CPU classification calls and submission counts so this is
|
||
an enforced gate, not an architectural hope.
|
||
- Pipeline creation and pack validation occur before atomic activation. Normal
|
||
play may not hitch on first shadow, weather, caster, or quality use.
|
||
|
||
## Quality scaling for weak hardware
|
||
|
||
These are starting envelopes to validate, not asset or world guarantees.
|
||
Distances are metres and are always clamped to current resident world data.
|
||
|
||
| Setting | Bloom/rays | Directional shadows | Volumetric shafts | Approx. depth-map memory at 32-bit depth |
|
||
|---|---|---|---|---:|
|
||
| Off / acdream default | Off | Off | Off | 0 MiB |
|
||
| Low | Quarter resolution | 2 × 768² cascades, about 72 m maximum reach | Off by default | 4.5 MiB |
|
||
| Medium | Half resolution | 3 × 1536² cascades, about 144 m maximum reach | Quarter resolution | 27 MiB |
|
||
| High | Half/full as measured | 4 × 2048² cascades, about 240 m maximum reach | Half resolution | 64 MiB |
|
||
|
||
Additional scaling rules:
|
||
|
||
- Prefer reducing cascade count, shadow resolution, reach, bloom/ray
|
||
resolution, and sample count before removing a feature's semantic
|
||
correctness.
|
||
- Preserve alpha-tested foliage and animated transforms at every shadow
|
||
quality. A cheaper preset may look softer or end sooner; it may not turn a
|
||
tree into a rectangle or freeze a monster's shadow.
|
||
- Clamp resource dimensions and bytes before allocation. A capability probe
|
||
that cannot support Low disables the pack and explains why.
|
||
- Preset availability uses the selected Vulkan adapter's probed 2-D image and
|
||
array-layer limits. Optional pack memory receives at most one eighth of its
|
||
device-local heap, capped at 256 MiB resident and 512 MiB transient; Auto
|
||
starts at Low when Medium is unavailable and acdream's default remains the fallback if
|
||
Low cannot fit.
|
||
- Optional Auto quality uses long hysteresis and stable frame-boundary swaps;
|
||
it never oscillates cascade layouts frame to frame. If Low stays over its
|
||
declared runtime GPU/CPU/resident budgets for 180 stable samples, Auto
|
||
retires the complete pack and returns to acdream's default with the measured
|
||
and declared limits in the visible failure reason.
|
||
- 4K defaults may choose lower post-process resolution because Tier 1 pays
|
||
approximately four times the 1080p pixel workload.
|
||
|
||
## Constraints and traps
|
||
|
||
This list carries forward every item in the findings' measured
|
||
[shadow-specific constraints](../research/2026-08-21-terrain-and-atmospheric-rendering-findings.md#shadow-specific-constraints)
|
||
and adds the current renderer's ownership and lifecycle boundaries.
|
||
|
||
1. **The renderer is the shipped pass-based Vulkan RHI.** Design against
|
||
`IGpuDevice` / `IGpuFrame` / `IGpuPassEncoder` and explicit pass/pipeline
|
||
descriptions. Do not revive an OpenGL backend or build a parallel renderer.
|
||
2. **The current PView graph is authoritative.** Shadow and atmosphere passes
|
||
consume its retained scene; they do not introduce a competing visibility
|
||
owner or change punch/seal, shared-alpha, particle, or private-viewport
|
||
ordering.
|
||
3. **CPU submission is the limiting dimension.** Reusing the full bounded
|
||
resident caster set is preferable to CPU-reculling it per cascade. GPU
|
||
culling is the only planned escalation.
|
||
4. **Alpha-tested foliage needs sampling and discard.** Reusing the existing
|
||
empty `portal_depth` fragment shader would cast solid tree rectangles.
|
||
5. **Animated casters use the existing N.5 SSBO transforms.** A second pose,
|
||
animation tick, or entity owner is forbidden.
|
||
6. **Indoors has no outdoor celestial directional shadow.** Dungeon/EnvCell
|
||
authored ambient and local lighting wins; outdoor sun/moon directional
|
||
shadows, sun rays, and sun shafts are gated off.
|
||
7. **Cascades are camera-relative and streaming-bounded.** They may not use a
|
||
fixed Dereth-wide extent, request landblocks, retain retired generations, or
|
||
draw stale portal destinations.
|
||
8. **Depth bias is specified in meaningful eye/world units.** A constant NDC
|
||
bias spans approximately `b*d²/near` metres of eye depth at distance and can
|
||
recreate issue #129's door-shaped holes through hills. Bias, normal offset,
|
||
cascade projection, near/far fitting, and reversed-depth conventions must be
|
||
tested together at near and far ranges.
|
||
9. **“Shadow” is an overloaded project term.** Existing `shadow_objects` and
|
||
`CPhysicsObj::add_shadows_to_cells` are collision registration, not light
|
||
shadows. New names use `DirectionalShadowMap`, `ShadowCaster`, or
|
||
`CelestialDirectionalShadow`; never generic `ShadowObject`.
|
||
10. **Authored celestial position, directional energy, and weather are
|
||
inputs.** Do not invent another celestial clock, light-energy channel,
|
||
weather state, or hard-coded dawn/noon schedule. The directional map uses
|
||
the visible above-horizon sun/dominant moon/secondary moon's exact rendered
|
||
direction but retail's single interpolated `DirColor * DirBright` colour/
|
||
energy channel, per the
|
||
[celestial source research](../research/2026-08-22-dereth-celestial-shadow-sources.md).
|
||
Rays and shafts remain sun-only and use the pack's declared sun-elevation
|
||
curve and categorical `activeDayGroup` mapping. The decomp evidence proves
|
||
the category reaches the frame, not an authored numeric ray intensity, so
|
||
the enhancement mapping must remain explicit pack policy.
|
||
11. **Atmosphere ordering is deliberate.** Rays/shafts composite before
|
||
tonemapping; retained UI and private viewports remain outside main-world
|
||
post-processing.
|
||
12. **Transparency remains ordered.** The pack cannot flatten the retail
|
||
world-alpha queue into an unordered shadow/post pass. Truly translucent
|
||
surfaces cast no opaque shadow until separately designed.
|
||
13. **Generation and GPU-flight lifetimes remain exact.** Pack images,
|
||
descriptors, and pipelines retire through existing fences and converge on
|
||
disable, resize, portal, reconnect, reset, failure, and device recreation.
|
||
14. **4K is a distinct performance row.** Tier-1 effects scale with pixels;
|
||
passing at 1080p is not evidence for 4K.
|
||
15. **Do not repeat closed investigations.** High-res DAT precedence is not
|
||
dropping overrides, AC detail textures are colour/alpha rather than normal
|
||
maps, and the engine's historical DOT3 capability does not turn those
|
||
assets into PBR inputs; these points are already falsified in the findings.
|
||
16. **Caster evidence must not exceed source identity.** Diagnostics separately
|
||
count terrain commands, outdoor statics, buildings, animated statics,
|
||
local/remote players, non-player creatures, other live dynamics, and
|
||
equipped children. Outdoor statics include trees but have no authoritative
|
||
tree discriminator; non-player creatures include monsters but have no
|
||
render-only hostile-monster-versus-NPC discriminator. Visual/connected
|
||
acceptance must name those limits instead of fabricating narrower counts.
|
||
|
||
## What this does NOT do
|
||
|
||
- It does **not** change acdream's default retail-faithful rendering path, its
|
||
expected output, or its authority in fidelity tests.
|
||
- The Atmospheric shader pack does **not** own or depend on #226 detail
|
||
texturing or the terrain-normal parity correction. Those remain separate
|
||
Track A ports even though the project owner authorized their implementation
|
||
in the same worktree.
|
||
- It does **not** add PBR or fabricate normal, roughness, metalness, or material
|
||
maps that AC's assets do not contain.
|
||
- It does **not** change terrain vertices, collision triangles, walkability,
|
||
slope response, physics shadow lists, movement, projectiles, or any Runtime
|
||
physics/collision owner.
|
||
- It does **not** change gameplay rules/state, network messages or ordering, or
|
||
any Runtime gameplay/network owner.
|
||
- It does **not** extend view distance, streaming radius, landblock residency,
|
||
or PView visibility to find more shadow casters.
|
||
- It does **not** add an indoor sun or replace authored EnvCell/local lights.
|
||
- It does **not** turn moon texture brightness or mesh luminosity into another
|
||
world-light energy channel, and it does not produce moon rays or moon shafts.
|
||
- It does **not** post-process retained UI or silently restyle private
|
||
paperdoll, appraisal, or portal viewports.
|
||
- It does **not** promise that every pack or quality preset runs on unsupported
|
||
hardware; compatibility failure is explicit and safely returns to acdream's default renderer.
|
||
- Campaign AR does **not** outrank active M4 gameplay work. The project owner's
|
||
explicit reprioritization authorizes this campaign without changing M4's
|
||
milestone priority; #268 + TS-8 are already complete and retired.
|
||
|
||
## Completion gate
|
||
|
||
The requirement ledger and the exact remaining external rows are consolidated
|
||
in the [Campaign AR completion audit](../research/2026-08-22-atmospheric-campaign-completion-audit.md).
|
||
|
||
The design, implementation, Stage 1 owner gate, and every available
|
||
machine-local Stage 2 connected, performance, lifetime, package, shader, build,
|
||
and complete-test gate are complete. The campaign becomes **shipped** only
|
||
after the distinct-account second-client remote-player row, remaining physical-
|
||
hardware rows, and final visual gates above pass and the project owner accepts
|
||
both sides of the final matrix:
|
||
|
||
- **pack off:** unchanged output, performance, ownership, and lifecycle from
|
||
acdream's authoritative default retail-faithful renderer; and
|
||
- **pack on:** moving authored sun-and-moon directional shadows from trees,
|
||
monsters, players, and buildings; sun-only rays/shafts; scalable atmosphere,
|
||
safe compatibility fallback, measured budgets, and clean long-lived resource
|
||
convergence.
|