56 KiB
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, especially the measured renderer baseline and the requested tier model. The approved celestial identity, priority, transform, and direction-versus- energy contract are pinned by the Dereth celestial shadow-source research.
Opt-in contract
- 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.
- 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. - One pack owns the enhancement graph. Packs do not stack. This prevents ambiguous pass ordering, incompatible HDR conventions, and unbounded GPU cost.
- 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.
- 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_LOSTcannot 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. - 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.
- 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 |
| 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.
Tier 2 headline: Dereth's moving authored sun-and-moon shadows
The measured renderer state
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.
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:
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, andAfterToneMapBeforePrivateViewports; - renderer-owned scene replays such as
OutdoorDirectionalShadowCasters, with requested cascade views and existing caster/material classes (Terrain,OpaqueWorld,AlphaCutoutWorld,AnimatedOpaque, andAnimatedAlphaCutout); 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, orEnvCell), 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
activeDayGroupvalues 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
- Discover manifests and descriptors without creating GPU objects.
- Show compatibility and estimated cost in Display settings. Unsupported packs remain visible with the exact missing capability; they cannot be selected.
- 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.
- Atomically activate the candidate only after every required object exists. Until then acdream's default path continues rendering.
- Persist
pack id + pack version + preset, never a positional index. If the pack disappears or becomes incompatible, selectacdream defaultand retain the failure notice. - 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.
- 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.
Frame-graph placement
With the pack off, the frozen retail graph is unchanged. With a pack selected, the renderer builds a separate enhancement graph:
- Update the existing immutable world frame, including authored sky objects, the retail directional colour/energy channel, and weather.
- Outdoors, select the visible above-horizon sun/dominant moon/secondary moon direction and render Tier-2 cascaded shadow depth from the resident caster set.
- Render the main world to the pack's world-colour intermediate, using pack-selected pipeline variants to sample the shadow map where requested.
- Preserve the established PView, punch/seal depth discipline, shared-alpha ordering, particle ordering, and world transparency boundaries.
- Generate screen-space sun occlusion/rays or, only while the shadow source is the sun, shadow-map volumetrics.
- Composite rays/shafts before tonemapping, so bloom sees them and the filmic curve rolls them off instead of clipping them.
- Apply tonemap, colour grade, and vignette to the main world image.
- 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.
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;
AcDream.App.Testscontributes 5,823/5,823. Evidence is underartifacts/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.
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.
AcDream.App.Testscontributes 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, andAcDream.RenderPacks.ShadowsOnlyTier2samples 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
OutdoorStaticsandNonPlayerCreatures; 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.*, andtests/AcDream.RenderPackValidator.Tests/; - activation, compatibility, Auto, diagnostics, and built-in graph:
src/AcDream.App/Rendering/Packs/andtests/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, andtests/AcDream.App.Tests/Rendering/DirectionalShadow*plustests/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, andtests/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-offretail/offpath with zero pack resources, casters, cascades, or classification calls;accept-shadow-morning-200m/,accept-shadow-afternoon-200m/, andaccept-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 commit4876c970; 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 twocurrent-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 reasonGPU 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 isretail/off, has zero pack resources or work, and retains that visible reason. Its comparison against the paired time-matched retail artifactigpu-retail-current-v6-time-matched/, usingsky-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.jsonrecords 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.
- PASS, except the external second-client row. The connected graphical
route covered moving local players, known monster encounters
reported under the authoritative
NonPlayerCreaturescategory, 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 nonzeroRemotePlayersrow. - 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.
- 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.
- 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.
- 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.
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. 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,
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 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 pre-campaign
pass list, pipeline set, draw/dispatch tuple, framebuffer SHA-256, and complete
resource ledger; the matrix's six physical retail rows independently record
zero pack work at all three resolutions and both pacing modes.
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 and adds the current renderer's ownership and lifecycle boundaries.
- The renderer is the shipped pass-based Vulkan RHI. Design against
IGpuDevice/IGpuFrame/IGpuPassEncoderand explicit pass/pipeline descriptions. Do not revive an OpenGL backend or build a parallel renderer. - 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.
- 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.
- Alpha-tested foliage needs sampling and discard. Reusing the existing
empty
portal_depthfragment shader would cast solid tree rectangles. - Animated casters use the existing N.5 SSBO transforms. A second pose, animation tick, or entity owner is forbidden.
- 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.
- 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.
- Depth bias is specified in meaningful eye/world units. A constant NDC
bias spans approximately
b*d²/nearmetres 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. - “Shadow” is an overloaded project term. Existing
shadow_objectsandCPhysicsObj::add_shadows_to_cellsare collision registration, not light shadows. New names useDirectionalShadowMap,ShadowCaster, orCelestialDirectionalShadow; never genericShadowObject. - 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 * DirBrightcolour/ energy channel, per the celestial source research. Rays and shafts remain sun-only and use the pack's declared sun-elevation curve and categoricalactiveDayGroupmapping. The decomp evidence proves the category reaches the frame, not an authored numeric ray intensity, so the enhancement mapping must remain explicit pack policy. - Atmosphere ordering is deliberate. Rays/shafts composite before tonemapping; retained UI and private viewports remain outside main-world post-processing.
- 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.
- 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.
- 4K is a distinct performance row. Tier-1 effects scale with pixels; passing at 1080p is not evidence for 4K.
- 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.
- 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.
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.