Skip to content

Vulkan optimization: scene-reading water and a TAA overhaul - #87

Open
CanReader wants to merge 28 commits into
stagingfrom
vulkan-optimization
Open

CanReader wants to merge 28 commits into
stagingfrom
vulkan-optimization

Conversation

@CanReader

Copy link
Copy Markdown
Owner

What this changes

Brings the vulkan-optimization branch into staging: the scene-reading water (refraction, absorption and screen-space reflections on Vulkan and OpenGL, plus the DirectX wave fixes), the debug --autofly / -campose flags, shadow caster culling, and a TAA overhaul on Vulkan. TAA is now on by default with RCAS sharpening, distant textures stay sharp, and water no longer trembles while moving.

Why

On Vulkan, distant leaves turned to mush even with the camera standing still, and water trembled while moving.

  • TAA false motion. The reprojection inverted the view-projection in float32. Far from the world origin inverse(VP) * VP drifted from identity, so a still camera got about 1 px of false motion per frame and history smeared. The engine now builds one current-to-previous clip matrix in double precision (engine commit 095c4bc).
  • Softness. RCAS sharpening runs after TAA (engine 1f643ac, "Sharpen" slider, default 0.5), and the block atlas samples one mip sharper while TAA is on.
  • Water trembling. Water marks itself in the HDR scene alpha (engine 2088c94) and TAA leans on the current frame there only in proportion to camera motion. The water blur and reflection rays no longer use screen-space or per-frame noise.
  • TAA checkbox. The settings panel called SetTAAEnabled(false) every frame, so the checkbox could not keep TAA on.

Engine dependency

This needs CanReader/SleakEngine branch vulkan-optimization (for example VertexLayoutDesc::transparentReadsScene and Application::SetSharpenStrength). The PR checks build against engine main, so they will fail until that branch reaches engine main. Run the CI workflow manually with engine_ref: vulkan-optimization to verify against the matching engine.

How it was verified

  • Builds on Linux (Debug, Vulkan validation layer on, no validation errors)
  • Loaded a world and played it (headless -capture runs of an existing save, still and with --autofly at 8 and 30 m/s; OpenGL ran 900 frames without shader errors)
  • Placed and broke blocks
  • Saved, quit, reloaded, and the world was intact
  • Not runtime tested (explain why below)

Measured on captures of the same save:

Before After
Still camera, error vs an 8-frame supersampled reference 3.7% 1.1%
Tree sharpness with sharpening (no change in flicker) 10.75 13.20
Water lake-bed lag at 30 m/s 0.66 0.49
Water flicker at 8 m/s 1.67 1.67

Block placement and save/reload were not exercised; nothing in these commits touches them.

Checklist

  • Shader changes updated all backend variants and the committed .spv (water: Vulkan and OpenGL; the DirectX variants have no scene-read blur or reflection code)
  • Save format changes bumped WorldMeta::CURRENT_VERSION and handle old worlds (no save format changes)
  • Collision changes kept the single-pass MTV resolution intact (no collision changes)
  • New event handlers are unregistered on scene teardown (no new event handlers)

dependabot Bot and others added 28 commits August 30, 2026 13:42
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 9.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](actions/github-script@v7...v9)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '9'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 6.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](actions/cache@v4...v6)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 2 to 3.
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v2...v3)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](softprops/action-gh-release@v2...v3)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
…ns/github-script-9

ci: bump actions/github-script from 7 to 9
…ns/cache-6

ci: bump actions/cache from 4 to 6
…ns/checkout-7

ci: bump actions/checkout from 4 to 7
…dabot/fetch-metadata-3

ci: bump dependabot/fetch-metadata from 2 to 3
…rops/action-gh-release-3

ci: bump softprops/action-gh-release from 2 to 3
List --gpuprofile, -capture and -capture-frame in the help text, and load
chunks on the main thread during a capture so chunk completion order, and
with it the captured frame, is the same on every run.
--autofly <m/s> flies the player along +Z at a fixed height with no
input, so chunk streaming can be exercised and benchmarked. Like -world
it only exists in Debug builds. Help text also lists --syncval.
The Vulkan water shader applied ACES and then fog in LDR, but it draws into
the HDR scene that the composite tonemaps again, so water came out pale and
washed out. It now outputs linear HDR with fog applied the way the deferred
lighting pass fogs terrain, and the composite does the only tonemap.
…shader

The wave normal re-evaluated the six-term height field four times for a
central difference; the same difference is now computed in closed form,
which differs only by float rounding. The 16-tap shadow PCF is skipped where
the facing smoothstep zeroes it, with explicit-LOD taps after the branch.
A visible column within the caster distance now casts only if its bounds
are not wholly outside a clip plane of the next shadow pass's light
view-projection. Visibility runs after the light update, so the matrix is
exactly the one that pass replays this frame's casters with; the 2 m margin
only absorbs float error. At -rd 12 shadow draws drop from 167 to 128 at
the spawn view and from about 208 to 151 while flying.
The altitude margin above the build limit is now AUTOFLY_CLEARANCE
instead of a bare number.
-campose x,y,z,yaw,pitch freezes the camera of a new game scene at a fixed
pose with gravity, input and the HUD off, so captures and screenshots frame
the same view on every backend.
The voxel format now reads the scene behind its transparent pass. Water
refracts the bottom by the wave slope, absorbs it with depth (Beer-Lambert
with in-scattering), softens the contact line, adds caustics and shore foam,
and reflects terrain with a screen-space march over the sky cubemap. Wave
octaves are derived from a few parameters and fade out by pixel footprint,
which removes the distant aliasing and the black streaks from reflections
that dipped below the horizon. The vertex shader applies the TAA jitter.
The OpenGL water shares the Vulkan shading body. It inverts the inline ACES
and fog of the stored frame to work in linear light, then tonemaps and fogs
its result like the rest of the GL frame.
The DirectX water uses the same derived, footprint-filtered wave octaves
and widens the sun highlight by the filtered slope. Reflection directions
below the horizon reuse the horizon color instead of going black. These
variants are not built or run here.
Seen from above, the few long octaves that survive the distance filter
summed into a visible lattice. Wave coordinates are now domain-warped by
slow noise, each octave takes its direction, phase and wavelength jitter
from a hash of its index with irrational spacing, and noise patches vary
swell and gust amplitude. Past a set distance the surface settles toward a
mirror and the removed slope widens the glint. Bottoms that the fog has
already hidden fade into the water body instead of tinting it blue.
Same shared water body as Vulkan: domain-warped, hashed wave octaves with
noise-varied amplitude, a calmer far field, and fogged bottoms that fade
into the water body, which removes the saturated blue band near the fog.
The DirectX water uses the same domain-warped, hashed wave octaves, noise
amplitude patches and far-field calming as the GLSL variants. These
variants are not built or run here.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant