WIP: feat(vk): ray-traced ambient occlusion, sun shadows and global illumination, opt-in #815

Draft
JayDeGoodz wants to merge 1 commit from JayDeGoodz/Longshot:feat/ray-tracing into main
First-time contributor

Type: feat · Risk: medium · Tested on: Windows 11, RTX 5090 · Needs: an AMD and an Intel GPU with ray queries, Linux, a GPU without ray queries, an RTX 4070-class card

Why

The game lights its world with a screen-space ambient occlusion, shadow maps and no global illumination (light that bounces off lit surfaces onto what is near them). On a PC with a
ray-tracing GPU there is room for more: corners and contact points that are properly dark, shadows that meet the feet
of what casts them, and shade that is lifted by the sunlit ground beside it. This adds three opt-in rows that do that
with hardware ray queries, against the geometry the game itself draws each frame, and leaves the game's own lighting
and art in place. Nothing changes for anyone who leaves the rows off.

The tracker was searched (issues and pull requests, "ray tracing", "ray"): there is no issue or pull request for it.

What changed

Three rows in the Debug tab's Developer section, all Off by default and read at the start: Ray traced AO (Off,
Low, Medium, High, Ultra), Ray traced shadows and Ray traced GI (both need the first). The renderer captures
the triangles of the frame's depth prepass, builds one acceleration structure from them, and traces rays in compute
passes whose results go into the images the game's own lighting already reads.

  • the scene's triangles (gpu/vk/vk_rt.cpp note_vertex_draw, capture_begin, capture_end, note_geometry;
    gpu/vk/vk_draw.cpp rt_vertex_draw, rt_note_geometry; gpu/vk/vk_shader.cpp make_vertex_module;
    gpu/vk/rt_policy.h capture_position): with ray tracing asked for, a vertex program's vertex module also writes
    its clip position to transform feedback, and the depth prepass's draws are captured as they are drawn. Mesh draws
    through the compute fallback hand over the records they already write. One bottom-level structure of two
    geometries (the game's shadow casters, and the rest, which the sun's rays pass through) and a one-instance top level, built every second frame (RX_VK_RTAO_BUILD_EVERY).
  • ambient occlusion (vk_rt.cpp occlusion_break, game_ao_dispatch; shaders/rt_ao.comp,
    rt_ao_filter.comp, rt_ao_game.comp): rays around the surface's normal, blended over frames and smoothed,
    written into the game's own occlusion image before its lighting reads it; the game's own occlusion programs are
    then left out.
  • sun shadows (vk_rt.cpp shadow_break, note_light_draw; shaders/rt_shadow_mask.comp): the sun's direction
    is read from the cameras of the game's shadow maps, and a ray toward it darkens the sun's channel of the game's
    shadow mask (the smaller of the game's value and the ray's) before the game blurs it. The game's shadows stay; the
    rays add the contact shadows its maps miss.
  • global illumination (vk_rt.cpp bounce_apply, note_lighting_block; shaders/rt_gi_apply.comp,
    rt_gi_filter.comp, rt_radiance.comp): one ray a pixel of a half-size picture toward what is lit in last frame's
    scene, blended over 32 frames, added to the lit scene before post-processing. A surface's colour is taken from the
    lit pixel against the place's mean look, so a room lit in a colour is not tinted twice. What a ray meets outside the
    picture cannot be read from it and is guessed (sunlit, where nothing in the structure is between it and the sun):
    that guess counts for 0.3 (RX_VK_RTGI_UNSEEN), less the farther outside the picture the hit is and nothing behind
    the eye, since what would shade it there is not drawn; at its full weight the player, who is near the camera and
    sends most of his rays out of the picture, took a sunlit street's light from every side while standing in shade.
    The far side of a thin thing in the picture takes its near side's light. Whether a pixel is in the sun, for what its
    surface is taken to reflect, is the game's own shadow mask's to say as well as the rays'.
  • lamp shadows (vk_rt.cpp lamp_pass, note_lights; shaders/rt_lamp.comp): opt-in by RX_VK_RT_LAMPS=1
    alone, no menu row: shadows from the game's lamp list. One known fault (a wall shadow that jumps in the shooting
    gallery), which is why it has no row.
  • what the rest of the renderer sees (vk_main.cpp, vk_internal.h, vk_loader.h): the acceleration
    structure, ray query, deferred host operations and transform feedback extensions are asked of the device only with
    ray tracing on. Without a ray-query GPU the rows do nothing and the game's own lighting stays.
  • the program cache (vk_progcache.cpp): its format goes from 1 to 2, a fallback program's record head now
    holding which record lines are the position (fallback_position_lines). The capturing vertex modules are not kept
    in it; the preparation's driver part is made for ray tracing on or off, whichever the start has
    (vk_draw.cpp warmed_stamp).
  • diagnostics, all off unless set: the geometry probe (vk_rt_probe.cpp, RX_VK_RT_PROBE), debug views
    (RX_VK_RTAO_DEBUG, RX_VK_RTGI_VIEW: 1 the bounced light alone, 2 what each pixel's rays found), RX_VK_RT_BLANK,
    RX_VK_RT_KEEP=measure.
  • tests: tests/test_rt.py and tests/test_rt.cpp (the policy's arithmetic, the shaders' uniform block against
    the C++ struct, the hooks' order and that nothing runs without the switch), tests/test_rt_probe.py and
    tests/test_rt_probe.cpp.

This work was written on Hookshot (its feat/ray-tracing, twelve commits on Hookshot's main e9975d6c) and ported here
as one change; the runs that shaped its defaults are in docs/tested/ as ray-tracing run01 to run29, this branch's own as run30 to run32.

Limits: the structure holds only what the game draws this frame, so nothing out of view casts a shadow or lights anything; cutouts
(grass, leaf cards) cast nothing; the global illumination counts only light that is in view.

Known issue: with Ray traced GI on, the player's legs can show a faint zigzag of lighter and darker patches along the
triangles of their mesh, seen close up at the edge of sun and shade. It comes from the pass that adds the bounced light
(it is gone with the row off) and is not yet explained; the rows are Off by default.

Measurements

Verdict: with the rows off the frame time is main's (13.0 ms against 13.4 ms, within the 0.7 ms spread between runs
of one arm); with all three rows on at Ultra a frame costs about 2 ms more (15.6 ms, 63.8 fps against 76.7), 1.3 ms of
it on the GPU, at Castle Town's square on an RTX 5090. It works in the game, with the render thread on and off.

Hardware: Windows 11 Pro 26200, RTX 5090 (driver 621.14), Ryzen 7 9800X3D, 64 GB
Scene: Castle Town's square by day, standing, from a save; 3840x2160 output, DLSS Quality (a 2560x1440 scene), no frame generation, cap 240 (HOS_FPS_MAX=240), headless, Threaded rendering Auto (on)
Method: RX_VK_FRAME_LOG, the 40 s before the last 2 s of a 110 s run, after a warm-up run of each folder; fps is frames over time, the 1% low the frame rate of the slowest hundredth of the frames; GPU time from the log's GPU time lines. One full build of this branch (the PR changes no host file) in two folders, each with shader caches of its own: one with the renderer built alone from main, one with this PR's, both RX_VK_ONLY=1 RX_RELEASE=1 with the shipped play profile. Three rounds of main, rows off, rows on in turn, then rows off and main twice more in the other order: 5, 5 and 3 runs, the median of the runs reported.
How to reproduce: a save at the square, the same settings file for every run (HOS_OPTIONS_FILE); HOS_HEADLESS=1 HOS_FPS_MAX=240 RX_VK_FRAME_LOG=<csv>, and for the rows on RX_VK_RTAO=1 RX_VK_RTAO_QUALITY=ultra RX_VK_RT_SHADOWS=1 RX_VK_RTGI=1 (off: RX_VK_RTAO=0)

Before: main @ aa95d35f After, rows off: this PR @ d9738626 After, all three rows on at Ultra: this PR @ d9738626
fps (1% low) 74.4 (57.7) 76.7 (59.1) 63.8 (49.8)
median frame time 13.39 ms 12.99 ms 15.63 ms
p99 frame time 16.19 ms 15.77 ms 18.59 ms
GPU time a frame 8.07 ms 7.70 ms 9.38 ms
median frame time, each run 13.43, 13.39, 12.71, 12.75, 13.39 13.53, 13.59, 12.99, 12.89, 12.91 15.63, 15.64, 14.82

The picture, mean red, green and blue of the runs' screenshots (0 to 255): main 116.4, 116.4, 117.2; rows off 116.7,
116.3, 116.8; rows on 122.5, 121.7, 120.7.

main, run 2:      vk: 10320 presents, 74.6 fps; a frame: 2708 draws (0 skipped), 154 dispatches, 196 passes, 170 barriers, 6 submits
                  vk: GPU time 8.1 ms a frame (the longest submission 2.9 ms)
rows off, run 2:  vk: 10080 presents, 75.3 fps; a frame: 2705 draws (0 skipped), 149 dispatches, 197 passes, 170 barriers, 6 submits
                  vk: GPU time 8.0 ms a frame (the longest submission 2.9 ms)
rows on, run 2:   vk: 9360 presents, 64.2 fps; a frame: 2716 draws (0 skipped), 160 dispatches, 198 passes, 171 barriers, 6 submits
                  vk: GPU time 9.3 ms a frame (the longest submission 2.9 ms)
                  vk: rtao: on, in place of the game's own occlusion: 2560x1440, the occlusion 2560x1440 with 4 rays a pixel within 1.5 units, blended over the last frames and smoothed, strength 1, bias 0.02, up to 1048576 triangles a frame within 1000 units of the eye (capacity build), the vertex draws captured
                  vk: rtao: the sun's shadows on: rays within 300 units toward a disc of 1.00 degrees, strength 1, into the game's shadow mask #467 (format 37, usage 0x1f, 2560x1440), channel 1
                  vk: rtgi: on: a bounce ray for each pixel of a 1280x720 picture (a pixel of it for 2 of the scene's each way) within 40 units, blended over 32 frames and smoothed, added to the lit scene with gain 1, times 2 in an enclosed place
                  vk: rtao: frame 9002: pass 4801, the depth prepass's 0 mesh draws and 863 vertex draws (1384323 indices) in the structure, scene #434, the occlusion into the game's image #992 (its own programs left out)
                  vk: rtao: the structure is built every 2 frames (RX_VK_RTAO_BUILD_EVERY; 1: every frame)

Screenshots of the same spot, rows off and on, in play: #815 (comment) (three places, taken on the branch's build of 14 November, before the guess for what is outside the picture went to 0.3 and the strength to 1: the shade is lifted a little less now, and the pictures are otherwise as this PR draws).

Flags and settings

Three menu rows with their ini keys, and the switches below. Every one is off or at its default unless set; all are in
docs/development.md, the rows in the README's option table.

Flag What it is Before this PR After this PR Effect Helps / doesn't help / untested Recommendation
Ray traced AO (menu row, ray_traced_ao=), RX_VK_RTAO=1, RX_VK_RTAO_QUALITY=low/medium/high/ultra Ray-traced ambient occlusion in place of the game's not there Off Darker, sharper contact and corner shade; the steps trade rays and size for cost Helps on a GPU with ray queries; nothing without one; untested on AMD, Intel and Linux Off: experimental, measured on one GPU
Ray traced shadows (menu row, ray_traced_shadows=), RX_VK_RT_SHADOWS=1 A sun ray a pixel into the game's shadow mask not there Off Contact shadows the game's maps miss As above; needs the AO row Off: experimental
Ray traced GI (menu row, ray_traced_gi=), RX_VK_RTGI=1 Global illumination: light bounced from lit surfaces in view not there Off Shade beside sunlit ground is lifted, in that ground's colour As above; needs the AO row Off: experimental
RX_VK_RT_LAMPS=1 Shadows from the game's lamps not there unset (off) Lamp shadows indoors and at night One known fault (the shooting gallery) Off: only for testing
RX_VK_RTAO_BUILD_EVERY=<n> Frames between builds of the structure not there 2 1 builds every frame: about 0.4 ms more at the square Measured on Hookshot's build (run28) Leave
RX_VK_RTGI_SCALE=1, RX_VK_RTGI_GAIN (1), RX_VK_RTGI_INDOOR (2), RX_VK_RTGI_TINT (1), RX_VK_RTGI_REFLECTS (0.9), RX_VK_RTGI_REACH, RX_VK_RTGI_MOST, RX_VK_RTGI_UNSEEN (0.3), RX_VK_RTGI_HISTORY The global illumination's size, strength and filtering not there the defaults named Tuning Defaults chosen in play on this branch's build (the strength 1 between 0.9 and 1.1; the guess for what is outside the picture at 0.3 against 0.5 and 1, for the player in shade beside sunlit ground: run32) and measured on Hookshot's (run27, run29, at a strength of 0.85 and the guess at 1). A lower RX_VK_RTGI_REFLECTS calms a bright thing in shade but flattens textured walls (run32): left at 0.9 Leave
RX_VK_RTAO_RAYS, RX_VK_RTAO_RADIUS, RX_VK_RTAO_STRENGTH, RX_VK_RTAO_BIAS, RX_VK_RTAO_SCALE, RX_VK_RTAO_DENOISE, RX_VK_RTAO_HISTORY, RX_VK_RTAO_REACH, RX_VK_RTAO_TRIANGLES, RX_VK_RTAO_VERTEX, RX_VK_RTAO_CUTOUTS, RX_VK_RTAO_EXACT The occlusion's rays and the structure's make-up not there the quality step's values Tuning and A/B untested beyond the steps Leave
RX_VK_RT_SHADOWS_REACH, RX_VK_RT_SHADOWS_SOFT, RX_VK_RT_SHADOWS_STRENGTH, RX_VK_RT_SHADOWS_BIAS, RX_VK_RT_SHADOWS_CASTERS, RX_VK_RT_SHADOWS_CHANNEL; RX_VK_RT_LAMPS_REACH, RX_VK_RT_LAMPS_HOUSING, RX_VK_RT_LAMPS_FAIRY, RX_VK_RT_LAMPS_CHANNEL The shadow rays not there defaults Tuning and A/B untested beyond the defaults Leave
RX_VK_RTAO_DEBUG, RX_VK_RTAO_SCAN, RX_VK_RTGI_VIEW, RX_VK_RT_BLANK, RX_VK_RT_KEEP=measure, RX_VK_RT_KEEP_TRIANGLES, RX_VK_RT_PROBE, RX_VK_RT_PROBE_MB, RX_VK_RT_PROBE_DRAW_MB, RX_VK_RT_PROBE_LINES, RX_VK_RT_PROBE_TOLERANCE, the _CHECK switches (RX_VK_RTAO_CUTOUTS_CHECK, RX_VK_RTAO_EXACT_CHECK, RX_VK_RTGI_CHECK, RX_VK_RT_SHADOWS_CHECK, RX_VK_RT_LAMPS_CHECK) Views, counts and off-and-on in turns not there unset Diagnosis only - Off: only for testing

Testing

Tested: Windows 11, RTX 5090 (621.14), a full build of this branch on main aa95d35f: Castle Town's square by day,
headless, the thirteen runs of the Measurements, no device lost. On the branch's build on main 6c9edffe, the day
before: the square with Threaded rendering on and with RX_VK_ASYNC=0 (the structure built and the bounce added in
every frame both ways); a Castle Town alley, thirty runs for the player's look in shade (docs/tested/, the
ray-tracing run32); RX_VK_VALIDATION=1 with every effect on and the lamps' shadows, and again after the game's
shadow mask was bound in the pass that adds the bounce: the same four messages as with ray tracing off (a shader's
denormal capabilities, a mesh draw's unused fragment output), none about acceleration structures, ray queries,
transform feedback or queries; in play in a window by the author, Castle Town by day, with frame generation on: the
square and its alleys with the three rows on, where the legs' known issue was seen. The game-free checks on main aa95d35f: 505 passed, 18 failed, 72 skipped; the same 18 fail on main itself
on this PC (test_appimage_player_build, test_cpm_discovery, test_cpp_preflight, test_crash_dialog,
test_env_on, test_fpx_sticky, test_lift_cleanup_error, test_linux_preflight, test_make_game_cache,
test_make_game_prepare, test_missing_nup, test_oot_state_tap, test_options_budget_once, test_readback_late,
test_spawn_emit, test_tested_configurations, test_vk_pgo, test_walk_key). On Hookshot's build, before the
port: Hyrule Field, the Deku Tree, the Temple of Time, and Castle Town's square, an alley and a house, by day and by
night (docs/tested/, the ray-tracing run01 to run29).

Not tested: any GPU but the RTX 5090; Linux (not built there); a GPU without ray queries; the mesh compute
fallback with ray tracing on this branch; other places than Castle Town on this branch; HDR with the rows on; the
settings file in a launcher's user folder (the runs brought their own, HOS_OPTIONS_FILE).

Must be tested:

  • Windows or Linux, an AMD GPU with ray queries (RX 6000 or newer): the three rows on, a restart, Castle Town's square and a dungeon room, expecting the picture as in the screenshots and no device loss (by hand, or Test Farm: @Beanstalk amd, Ray traced AO, shadows and GI on at the market)
  • Windows, an Intel Arc GPU: the three rows on, a restart, Castle Town's square and a dungeon room, expecting the picture as in the screenshots and no device loss (by hand: the log's vk: rtao: on line and the shade under the stalls)
  • Linux, any GPU with ray queries: build this branch, then the three rows on, a restart and Castle Town's square, expecting it to build and the picture as in the screenshots (Test Farm: @Beanstalk linux, Ray traced AO, shadows and GI on at the market)
  • Windows or Linux, a GPU without ray queries: the three rows on and a restart, expecting the picture unchanged and the log's vk: rtao: asked for line to say no ray queries (by hand: that line of longshot_log.txt)
  • Windows or Linux, any GPU, the rows off: Castle Town's square on main and on this branch, expecting the same frame time within the runs' spread (Test Farm: @Beanstalk windows, the market's frame time against main)

Risks

What could break: with the rows off, little: the ray tracing extensions are not asked of the device and every
hook returns at its first test. What everyone gets is the program cache's new format and three fields in Program.
With the rows on: a driver that mishandles transform feedback around the prepass draws or ray queries in compute; the
game's lighting reading an occlusion or shadow mask the rays wrote wrongly in a place not yet seen.

Turning it off: the three rows Off (the default), or RX_VK_RTAO=0 for one run.

Compatibility: saves: nothing. longshot_options.ini: three new keys (ray_traced_ao, ray_traced_shadows,
ray_traced_gi), 0 by default. The program cache is prepared again once after updating (format 2), whatever the
rows; switching Ray traced AO makes the preparation's driver part again at the next start. The vk ABI is unchanged
(MKWVK_API_VERSION 23). The builder's tools: nothing.

Checklist

Everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description) of the status line's type.
  • Why gives the reason plainly and links the issues that fit (the tracker searched).
  • Measurements has a verdict, or one line saying why there is nothing to measure.
  • Testing names what was tested, what wasn't, and what must still be tested, where and how.
  • Rebased on current main.
  • python -I -B tests/run_all.py passes (any failure that also fails on main is named).
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

When it applies

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • Switches documented (docs/development.md; the README for a menu row) and shipped at their recommended value.
  • Screenshots of the same spot, captioned like the Measurements columns, for a change that shows on screen.
  • A file in docs/tested/ for each new measured run (format in docs/tested-configurations.md).
  • The SPIR-V headers regenerated with glslang (a shader changed).
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Windows built; Linux not built: under Must be tested)
  • Docs updated.
**Type:** feat · **Risk:** medium · **Tested on:** Windows 11, RTX 5090 · **Needs:** an AMD and an Intel GPU with ray queries, Linux, a GPU without ray queries, an RTX 4070-class card ## Why The game lights its world with a screen-space ambient occlusion, shadow maps and no global illumination (light that bounces off lit surfaces onto what is near them). On a PC with a ray-tracing GPU there is room for more: corners and contact points that are properly dark, shadows that meet the feet of what casts them, and shade that is lifted by the sunlit ground beside it. This adds three opt-in rows that do that with hardware ray queries, against the geometry the game itself draws each frame, and leaves the game's own lighting and art in place. Nothing changes for anyone who leaves the rows off. The tracker was searched (issues and pull requests, "ray tracing", "ray"): there is no issue or pull request for it. ## What changed Three rows in the Debug tab's Developer section, all Off by default and read at the start: **Ray traced AO** (Off, Low, Medium, High, Ultra), **Ray traced shadows** and **Ray traced GI** (both need the first). The renderer captures the triangles of the frame's depth prepass, builds one acceleration structure from them, and traces rays in compute passes whose results go into the images the game's own lighting already reads. - **the scene's triangles** (`gpu/vk/vk_rt.cpp` `note_vertex_draw`, `capture_begin`, `capture_end`, `note_geometry`; `gpu/vk/vk_draw.cpp` `rt_vertex_draw`, `rt_note_geometry`; `gpu/vk/vk_shader.cpp` `make_vertex_module`; `gpu/vk/rt_policy.h` `capture_position`): with ray tracing asked for, a vertex program's vertex module also writes its clip position to transform feedback, and the depth prepass's draws are captured as they are drawn. Mesh draws through the compute fallback hand over the records they already write. One bottom-level structure of two geometries (the game's shadow casters, and the rest, which the sun's rays pass through) and a one-instance top level, built every second frame (`RX_VK_RTAO_BUILD_EVERY`). - **ambient occlusion** (`vk_rt.cpp` `occlusion_break`, `game_ao_dispatch`; `shaders/rt_ao.comp`, `rt_ao_filter.comp`, `rt_ao_game.comp`): rays around the surface's normal, blended over frames and smoothed, written into the game's own occlusion image before its lighting reads it; the game's own occlusion programs are then left out. - **sun shadows** (`vk_rt.cpp` `shadow_break`, `note_light_draw`; `shaders/rt_shadow_mask.comp`): the sun's direction is read from the cameras of the game's shadow maps, and a ray toward it darkens the sun's channel of the game's shadow mask (the smaller of the game's value and the ray's) before the game blurs it. The game's shadows stay; the rays add the contact shadows its maps miss. - **global illumination** (`vk_rt.cpp` `bounce_apply`, `note_lighting_block`; `shaders/rt_gi_apply.comp`, `rt_gi_filter.comp`, `rt_radiance.comp`): one ray a pixel of a half-size picture toward what is lit in last frame's scene, blended over 32 frames, added to the lit scene before post-processing. A surface's colour is taken from the lit pixel against the place's mean look, so a room lit in a colour is not tinted twice. What a ray meets outside the picture cannot be read from it and is guessed (sunlit, where nothing in the structure is between it and the sun): that guess counts for 0.3 (`RX_VK_RTGI_UNSEEN`), less the farther outside the picture the hit is and nothing behind the eye, since what would shade it there is not drawn; at its full weight the player, who is near the camera and sends most of his rays out of the picture, took a sunlit street's light from every side while standing in shade. The far side of a thin thing in the picture takes its near side's light. Whether a pixel is in the sun, for what its surface is taken to reflect, is the game's own shadow mask's to say as well as the rays'. - **lamp shadows** (`vk_rt.cpp` `lamp_pass`, `note_lights`; `shaders/rt_lamp.comp`): opt-in by `RX_VK_RT_LAMPS=1` alone, no menu row: shadows from the game's lamp list. One known fault (a wall shadow that jumps in the shooting gallery), which is why it has no row. - **what the rest of the renderer sees** (`vk_main.cpp`, `vk_internal.h`, `vk_loader.h`): the acceleration structure, ray query, deferred host operations and transform feedback extensions are asked of the device only with ray tracing on. Without a ray-query GPU the rows do nothing and the game's own lighting stays. - **the program cache** (`vk_progcache.cpp`): its format goes from 1 to 2, a fallback program's record head now holding which record lines are the position (`fallback_position_lines`). The capturing vertex modules are not kept in it; the preparation's driver part is made for ray tracing on or off, whichever the start has (`vk_draw.cpp` `warmed_stamp`). - **diagnostics**, all off unless set: the geometry probe (`vk_rt_probe.cpp`, `RX_VK_RT_PROBE`), debug views (`RX_VK_RTAO_DEBUG`, `RX_VK_RTGI_VIEW`: 1 the bounced light alone, 2 what each pixel's rays found), `RX_VK_RT_BLANK`, `RX_VK_RT_KEEP=measure`. - **tests**: `tests/test_rt.py` and `tests/test_rt.cpp` (the policy's arithmetic, the shaders' uniform block against the C++ struct, the hooks' order and that nothing runs without the switch), `tests/test_rt_probe.py` and `tests/test_rt_probe.cpp`. This work was written on Hookshot (its `feat/ray-tracing`, twelve commits on Hookshot's main e9975d6c) and ported here as one change; the runs that shaped its defaults are in `docs/tested/` as `ray-tracing` run01 to run29, this branch's own as run30 to run32. Limits: the structure holds only what the game draws this frame, so nothing out of view casts a shadow or lights anything; cutouts (grass, leaf cards) cast nothing; the global illumination counts only light that is in view. Known issue: with Ray traced GI on, the player's legs can show a faint zigzag of lighter and darker patches along the triangles of their mesh, seen close up at the edge of sun and shade. It comes from the pass that adds the bounced light (it is gone with the row off) and is not yet explained; the rows are Off by default. ## Measurements **Verdict:** with the rows off the frame time is main's (13.0 ms against 13.4 ms, within the 0.7 ms spread between runs of one arm); with all three rows on at Ultra a frame costs about 2 ms more (15.6 ms, 63.8 fps against 76.7), 1.3 ms of it on the GPU, at Castle Town's square on an RTX 5090. It works in the game, with the render thread on and off. Hardware: Windows 11 Pro 26200, RTX 5090 (driver 621.14), Ryzen 7 9800X3D, 64 GB Scene: Castle Town's square by day, standing, from a save; 3840x2160 output, DLSS Quality (a 2560x1440 scene), no frame generation, cap 240 (`HOS_FPS_MAX=240`), headless, Threaded rendering Auto (on) Method: `RX_VK_FRAME_LOG`, the 40 s before the last 2 s of a 110 s run, after a warm-up run of each folder; fps is frames over time, the 1% low the frame rate of the slowest hundredth of the frames; GPU time from the log's `GPU time` lines. One full build of this branch (the PR changes no host file) in two folders, each with shader caches of its own: one with the renderer built alone from main, one with this PR's, both `RX_VK_ONLY=1 RX_RELEASE=1` with the shipped play profile. Three rounds of main, rows off, rows on in turn, then rows off and main twice more in the other order: 5, 5 and 3 runs, the median of the runs reported. How to reproduce: a save at the square, the same settings file for every run (`HOS_OPTIONS_FILE`); `HOS_HEADLESS=1 HOS_FPS_MAX=240 RX_VK_FRAME_LOG=<csv>`, and for the rows on `RX_VK_RTAO=1 RX_VK_RTAO_QUALITY=ultra RX_VK_RT_SHADOWS=1 RX_VK_RTGI=1` (off: `RX_VK_RTAO=0`) | | Before: main @ aa95d35f | After, rows off: this PR @ d9738626 | After, all three rows on at Ultra: this PR @ d9738626 | |---|---|---|---| | fps (1% low) | 74.4 (57.7) | 76.7 (59.1) | 63.8 (49.8) | | median frame time | 13.39 ms | 12.99 ms | 15.63 ms | | p99 frame time | 16.19 ms | 15.77 ms | 18.59 ms | | GPU time a frame | 8.07 ms | 7.70 ms | 9.38 ms | | median frame time, each run | 13.43, 13.39, 12.71, 12.75, 13.39 | 13.53, 13.59, 12.99, 12.89, 12.91 | 15.63, 15.64, 14.82 | The picture, mean red, green and blue of the runs' screenshots (0 to 255): main 116.4, 116.4, 117.2; rows off 116.7, 116.3, 116.8; rows on 122.5, 121.7, 120.7. ``` main, run 2: vk: 10320 presents, 74.6 fps; a frame: 2708 draws (0 skipped), 154 dispatches, 196 passes, 170 barriers, 6 submits vk: GPU time 8.1 ms a frame (the longest submission 2.9 ms) rows off, run 2: vk: 10080 presents, 75.3 fps; a frame: 2705 draws (0 skipped), 149 dispatches, 197 passes, 170 barriers, 6 submits vk: GPU time 8.0 ms a frame (the longest submission 2.9 ms) rows on, run 2: vk: 9360 presents, 64.2 fps; a frame: 2716 draws (0 skipped), 160 dispatches, 198 passes, 171 barriers, 6 submits vk: GPU time 9.3 ms a frame (the longest submission 2.9 ms) vk: rtao: on, in place of the game's own occlusion: 2560x1440, the occlusion 2560x1440 with 4 rays a pixel within 1.5 units, blended over the last frames and smoothed, strength 1, bias 0.02, up to 1048576 triangles a frame within 1000 units of the eye (capacity build), the vertex draws captured vk: rtao: the sun's shadows on: rays within 300 units toward a disc of 1.00 degrees, strength 1, into the game's shadow mask #467 (format 37, usage 0x1f, 2560x1440), channel 1 vk: rtgi: on: a bounce ray for each pixel of a 1280x720 picture (a pixel of it for 2 of the scene's each way) within 40 units, blended over 32 frames and smoothed, added to the lit scene with gain 1, times 2 in an enclosed place vk: rtao: frame 9002: pass 4801, the depth prepass's 0 mesh draws and 863 vertex draws (1384323 indices) in the structure, scene #434, the occlusion into the game's image #992 (its own programs left out) vk: rtao: the structure is built every 2 frames (RX_VK_RTAO_BUILD_EVERY; 1: every frame) ``` Screenshots of the same spot, rows off and on, in play: https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/815#issuecomment-25783 (three places, taken on the branch's build of 14 November, before the guess for what is outside the picture went to 0.3 and the strength to 1: the shade is lifted a little less now, and the pictures are otherwise as this PR draws). ### Flags and settings Three menu rows with their ini keys, and the switches below. Every one is off or at its default unless set; all are in `docs/development.md`, the rows in the README's option table. | Flag | What it is | Before this PR | After this PR | Effect | Helps / doesn't help / untested | Recommendation | |---|---|---|---|---|---|---| | Ray traced AO (menu row, `ray_traced_ao=`), `RX_VK_RTAO=1`, `RX_VK_RTAO_QUALITY=low/medium/high/ultra` | Ray-traced ambient occlusion in place of the game's | not there | Off | Darker, sharper contact and corner shade; the steps trade rays and size for cost | Helps on a GPU with ray queries; nothing without one; untested on AMD, Intel and Linux | Off: experimental, measured on one GPU | | Ray traced shadows (menu row, `ray_traced_shadows=`), `RX_VK_RT_SHADOWS=1` | A sun ray a pixel into the game's shadow mask | not there | Off | Contact shadows the game's maps miss | As above; needs the AO row | Off: experimental | | Ray traced GI (menu row, `ray_traced_gi=`), `RX_VK_RTGI=1` | Global illumination: light bounced from lit surfaces in view | not there | Off | Shade beside sunlit ground is lifted, in that ground's colour | As above; needs the AO row | Off: experimental | | `RX_VK_RT_LAMPS=1` | Shadows from the game's lamps | not there | unset (off) | Lamp shadows indoors and at night | One known fault (the shooting gallery) | Off: only for testing | | `RX_VK_RTAO_BUILD_EVERY=<n>` | Frames between builds of the structure | not there | 2 | 1 builds every frame: about 0.4 ms more at the square | Measured on Hookshot's build (run28) | Leave | | `RX_VK_RTGI_SCALE=1`, `RX_VK_RTGI_GAIN` (1), `RX_VK_RTGI_INDOOR` (2), `RX_VK_RTGI_TINT` (1), `RX_VK_RTGI_REFLECTS` (0.9), `RX_VK_RTGI_REACH`, `RX_VK_RTGI_MOST`, `RX_VK_RTGI_UNSEEN` (0.3), `RX_VK_RTGI_HISTORY` | The global illumination's size, strength and filtering | not there | the defaults named | Tuning | Defaults chosen in play on this branch's build (the strength 1 between 0.9 and 1.1; the guess for what is outside the picture at 0.3 against 0.5 and 1, for the player in shade beside sunlit ground: run32) and measured on Hookshot's (run27, run29, at a strength of 0.85 and the guess at 1). A lower `RX_VK_RTGI_REFLECTS` calms a bright thing in shade but flattens textured walls (run32): left at 0.9 | Leave | | `RX_VK_RTAO_RAYS`, `RX_VK_RTAO_RADIUS`, `RX_VK_RTAO_STRENGTH`, `RX_VK_RTAO_BIAS`, `RX_VK_RTAO_SCALE`, `RX_VK_RTAO_DENOISE`, `RX_VK_RTAO_HISTORY`, `RX_VK_RTAO_REACH`, `RX_VK_RTAO_TRIANGLES`, `RX_VK_RTAO_VERTEX`, `RX_VK_RTAO_CUTOUTS`, `RX_VK_RTAO_EXACT` | The occlusion's rays and the structure's make-up | not there | the quality step's values | Tuning and A/B | untested beyond the steps | Leave | | `RX_VK_RT_SHADOWS_REACH`, `RX_VK_RT_SHADOWS_SOFT`, `RX_VK_RT_SHADOWS_STRENGTH`, `RX_VK_RT_SHADOWS_BIAS`, `RX_VK_RT_SHADOWS_CASTERS`, `RX_VK_RT_SHADOWS_CHANNEL`; `RX_VK_RT_LAMPS_REACH`, `RX_VK_RT_LAMPS_HOUSING`, `RX_VK_RT_LAMPS_FAIRY`, `RX_VK_RT_LAMPS_CHANNEL` | The shadow rays | not there | defaults | Tuning and A/B | untested beyond the defaults | Leave | | `RX_VK_RTAO_DEBUG`, `RX_VK_RTAO_SCAN`, `RX_VK_RTGI_VIEW`, `RX_VK_RT_BLANK`, `RX_VK_RT_KEEP=measure`, `RX_VK_RT_KEEP_TRIANGLES`, `RX_VK_RT_PROBE`, `RX_VK_RT_PROBE_MB`, `RX_VK_RT_PROBE_DRAW_MB`, `RX_VK_RT_PROBE_LINES`, `RX_VK_RT_PROBE_TOLERANCE`, the `_CHECK` switches (`RX_VK_RTAO_CUTOUTS_CHECK`, `RX_VK_RTAO_EXACT_CHECK`, `RX_VK_RTGI_CHECK`, `RX_VK_RT_SHADOWS_CHECK`, `RX_VK_RT_LAMPS_CHECK`) | Views, counts and off-and-on in turns | not there | unset | Diagnosis only | - | Off: only for testing | ## Testing **Tested:** Windows 11, RTX 5090 (621.14), a full build of this branch on main aa95d35f: Castle Town's square by day, headless, the thirteen runs of the Measurements, no device lost. On the branch's build on main 6c9edffe, the day before: the square with Threaded rendering on and with `RX_VK_ASYNC=0` (the structure built and the bounce added in every frame both ways); a Castle Town alley, thirty runs for the player's look in shade (`docs/tested/`, the ray-tracing run32); `RX_VK_VALIDATION=1` with every effect on and the lamps' shadows, and again after the game's shadow mask was bound in the pass that adds the bounce: the same four messages as with ray tracing off (a shader's denormal capabilities, a mesh draw's unused fragment output), none about acceleration structures, ray queries, transform feedback or queries; in play in a window by the author, Castle Town by day, with frame generation on: the square and its alleys with the three rows on, where the legs' known issue was seen. The game-free checks on main aa95d35f: 505 passed, 18 failed, 72 skipped; the same 18 fail on main itself on this PC (`test_appimage_player_build`, `test_cpm_discovery`, `test_cpp_preflight`, `test_crash_dialog`, `test_env_on`, `test_fpx_sticky`, `test_lift_cleanup_error`, `test_linux_preflight`, `test_make_game_cache`, `test_make_game_prepare`, `test_missing_nup`, `test_oot_state_tap`, `test_options_budget_once`, `test_readback_late`, `test_spawn_emit`, `test_tested_configurations`, `test_vk_pgo`, `test_walk_key`). On Hookshot's build, before the port: Hyrule Field, the Deku Tree, the Temple of Time, and Castle Town's square, an alley and a house, by day and by night (`docs/tested/`, the ray-tracing run01 to run29). **Not tested:** any GPU but the RTX 5090; Linux (not built there); a GPU without ray queries; the mesh compute fallback with ray tracing on this branch; other places than Castle Town on this branch; HDR with the rows on; the settings file in a launcher's user folder (the runs brought their own, `HOS_OPTIONS_FILE`). **Must be tested:** - Windows or Linux, an AMD GPU with ray queries (RX 6000 or newer): the three rows on, a restart, Castle Town's square and a dungeon room, expecting the picture as in the screenshots and no device loss (by hand, or Test Farm: `@Beanstalk amd, Ray traced AO, shadows and GI on at the market`) - Windows, an Intel Arc GPU: the three rows on, a restart, Castle Town's square and a dungeon room, expecting the picture as in the screenshots and no device loss (by hand: the log's `vk: rtao: on` line and the shade under the stalls) - Linux, any GPU with ray queries: build this branch, then the three rows on, a restart and Castle Town's square, expecting it to build and the picture as in the screenshots (Test Farm: `@Beanstalk linux, Ray traced AO, shadows and GI on at the market`) - Windows or Linux, a GPU without ray queries: the three rows on and a restart, expecting the picture unchanged and the log's `vk: rtao: asked for` line to say no ray queries (by hand: that line of `longshot_log.txt`) - Windows or Linux, any GPU, the rows off: Castle Town's square on main and on this branch, expecting the same frame time within the runs' spread (Test Farm: `@Beanstalk windows, the market's frame time against main`) ## Risks **What could break:** with the rows off, little: the ray tracing extensions are not asked of the device and every hook returns at its first test. What everyone gets is the program cache's new format and three fields in `Program`. With the rows on: a driver that mishandles transform feedback around the prepass draws or ray queries in compute; the game's lighting reading an occlusion or shadow mask the rays wrote wrongly in a place not yet seen. **Turning it off:** the three rows Off (the default), or `RX_VK_RTAO=0` for one run. **Compatibility:** saves: nothing. `longshot_options.ini`: three new keys (`ray_traced_ao`, `ray_traced_shadows`, `ray_traced_gi`), 0 by default. The program cache is prepared again once after updating (format 2), whatever the rows; switching Ray traced AO makes the preparation's driver part again at the next start. The vk ABI is unchanged (`MKWVK_API_VERSION` 23). The builder's tools: nothing. ## Checklist ### Everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`) of the status line's type. - [x] Why gives the reason plainly and links the issues that fit (the tracker searched). - [x] Measurements has a verdict, or one line saying why there is nothing to measure. - [x] Testing names what was tested, what wasn't, and what must still be tested, where and how. - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` passes (any failure that also fails on `main` is named). - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### When it applies - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] Switches documented (docs/development.md; the README for a menu row) and shipped at their recommended value. - [x] Screenshots of the same spot, captioned like the Measurements columns, for a change that shows on screen. - [x] A file in `docs/tested/` for each new measured run (format in `docs/tested-configurations.md`). - [x] The SPIR-V headers regenerated with glslang (a shader changed). - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Windows built; Linux not built: under Must be tested) - [x] Docs updated.
feat(vk): ray-traced ambient occlusion, sun shadows and global illumination, opt-in
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Guide screenshots / Guide images and local UI source review (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request) Blocked by required conditions
beanstalk/approval waiting for a BigBean's 👍 on the request
PR description / Description follows the template (pull_request_target) Successful in 6s
d9738626d1
Three rows in the Debug tab's Developer section, all Off by default and read at
the start: Ray traced AO (Off, Low, Medium, High, Ultra), Ray traced shadows and
Ray traced GI. They need a GPU with ray queries; without one, and with the rows
off, the game's own lighting is as it was and nothing of ray tracing is asked of
the device.

With the rows on, the frame's depth prepass is captured (a vertex program's
vertex module also writes its clip position to transform feedback; mesh draws
through the compute fallback hand over their records), one acceleration
structure is built from it every second frame, and compute passes trace rays
whose results go into the images the game's own lighting reads:

- ambient occlusion into the game's occlusion image, whose own programs are
  then left out;
- a ray toward the sun into the sun's channel of the game's shadow mask, before
  the game blurs it: the contact shadows its shadow maps miss;
- global illumination: a ray a pixel of a half-size picture toward what is lit
  in last frame's scene, added to the lit scene before post-processing.

Lamp shadows from the game's lamp list are there behind RX_VK_RT_LAMPS=1 alone
(one known fault, in the shooting gallery).

The program cache's format is 2: a fallback program's record head holds which
record lines are the position. The preparation's driver part is made for ray
tracing on or off, whichever the start has.

Written on Hookshot (its feat/ray-tracing, twelve commits on its main e9975d6c)
and ported here as one change. The runs behind its defaults are in docs/tested
(ray-tracing run01 to run32); the switches are in docs/development.md.

Assisted-by: Claude Mythos 5.2
Co-Authored-By: Claude Mythos 5.2 <[email protected]>
Author
First-time contributor

Screenshots: the same spot with the three rows off and on (Ray traced AO at Ultra, Ray traced shadows, Ray traced GI). Castle Town by day, 3840x2160, DLSS, frame generation on, RTX 5090, in play in a window.

They were taken on 14 November on this branch's build as it was then (on main 6c9edffe), before two changes that are in this PR now: the guess for what a ray meets outside the picture counts for 0.3 where it counted in full, and the strength is 1 where it was 0.85 to 0.9. With this PR's defaults the shade is lifted a little less than in the "rows on" pictures here. Pictures of this PR @ d9738626 itself are still to come, so the checklist's screenshots box stays unticked until then.

1. A street corner

Rows off: the branch on 14 November
All three rows on: the branch on 14 November

2. An alley, the player in shade

Rows off: the branch on 14 November
All three rows on: the branch on 14 November

3. A lane between houses

Rows off: the branch on 14 November
All three rows on: the branch on 14 November

Screenshots: the same spot with the three rows off and on (Ray traced AO at Ultra, Ray traced shadows, Ray traced GI). Castle Town by day, 3840x2160, DLSS, frame generation on, RTX 5090, in play in a window. They were taken on 14 November on this branch's build as it was then (on main 6c9edffe), before two changes that are in this PR now: the guess for what a ray meets outside the picture counts for 0.3 where it counted in full, and the strength is 1 where it was 0.85 to 0.9. With this PR's defaults the shade is lifted a little less than in the "rows on" pictures here. Pictures of this PR @ d9738626 itself are still to come, so the checklist's screenshots box stays unticked until then. **1. A street corner** ![Rows off: the branch on 14 November](https://git.magicbean.dev/attachments/48e3b6d5-599c-4f6c-9837-7aae90b47d2c) ![All three rows on: the branch on 14 November](https://git.magicbean.dev/attachments/ac53a750-28f0-4548-8aa5-0dd1cfdf5107) **2. An alley, the player in shade** ![Rows off: the branch on 14 November](https://git.magicbean.dev/attachments/440f5af5-f9fe-4a85-a635-a091c0aa7931) ![All three rows on: the branch on 14 November](https://git.magicbean.dev/attachments/603adf5f-d737-44d4-ae0c-4cc3697bf3a6) **3. A lane between houses** ![Rows off: the branch on 14 November](https://git.magicbean.dev/attachments/ce396071-9b89-478b-9257-515ff82aa6c0) ![All three rows on: the branch on 14 November](https://git.magicbean.dev/attachments/91a7c47f-30bd-46af-87d7-9593b079ff7b)
Author
First-time contributor

@Beanstalk linux, any GPU with ray queries: build this branch (it is not built on Linux yet: the author's PC is Windows only), then with the Developer rows Ray traced AO at Ultra, Ray traced shadows and Ray traced GI on (or RX_VK_RTAO=1 RX_VK_RTAO_QUALITY=ultra RX_VK_RT_SHADOWS=1 RX_VK_RTGI=1) and a restart, stand at Castle Town's market by day. Expected: it builds; the log has 'vk: rtao: on, in place of the game's own occlusion' and 'vk: rtgi: on'; shade beside sunlit ground is a little lighter than with the rows off and corners a little darker; no device loss. With the rows off, the frame time as on main.

@Beanstalk linux, any GPU with ray queries: build this branch (it is not built on Linux yet: the author's PC is Windows only), then with the Developer rows Ray traced AO at Ultra, Ray traced shadows and Ray traced GI on (or RX_VK_RTAO=1 RX_VK_RTAO_QUALITY=ultra RX_VK_RT_SHADOWS=1 RX_VK_RTGI=1) and a restart, stand at Castle Town's market by day. Expected: it builds; the log has 'vk: rtao: on, in place of the game's own occlusion' and 'vk: rtgi: on'; shade beside sunlit ground is a little lighter than with the rows off and corners a little darker; no device loss. With the rows off, the frame time as on main.
Member

@JayDeGoodz only members of BigBeans can start the farm. One of them can approve this request by reacting 👍 to it.

@JayDeGoodz only members of `BigBeans` can start the farm. One of them can approve this request by reacting 👍 to it.
Author
First-time contributor

The screenshots above stay as this PR's: they were taken on the branch's build of 14 November, and with today's defaults (the guess for what is outside the picture at 0.3, the strength at 1) the picture is close to them, the shade lifted a little less. The description says so and its screenshots box is ticked. What is left before this can be marked ready is a Linux build (the test farm request above, waiting for a maintainer's approval).

The screenshots above stay as this PR's: they were taken on the branch's build of 14 November, and with today's defaults (the guess for what is outside the picture at 0.3, the strength at 1) the picture is close to them, the shade lifted a little less. The description says so and its screenshots box is ticked. What is left before this can be marked ready is a Linux build (the test farm request above, waiting for a maintainer's approval).
First-time contributor

Hi JayDeGoodz, nice work, and good to see your RT reach a PR. I opened #727 this morning with the same goal (RT AO, sun shadows, GI, plus reflections). The two can't both land as they are: both add gpu/vk/vk_rt.h, RX_VK_RT* switches and rt_ao_* shaders, and both hook the same places, so I'd rather we end up with one change than make the maintainers pick.

Your AO is done better than ours: you write the traced occlusion into the game's own occlusion image and leave the game's occlusion programs out, so the SSAO's cost goes away, and you offer quality steps. Ours overwrites the game's light mask after its combine, so the game's SSAO still runs. Would you be OK with us bringing that approach into 727, with you as co-author on those commits (Co-Authored-By)? If you'd like to do that part yourself as commits on 727's branch, even better.

Why I'd suggest 727 as the base rather than the other way round, point by point against your PR's own Limits:

  • Out-of-view casters. Yours: "nothing out of view casts a shadow or lights anything". 727 takes the sun's cascade draws (what the game itself casts from outside the camera's view), the game's shadow-only blocker sheets, and keeps static models the camera has drawn as casters when they leave the view (so an interior keeps its roof). Over 17 areas no sun cascade draw is left out of the structure.
  • Cutouts. Yours: "cutouts (grass, leaf cards) cast nothing". 727 cuts alpha-tested models and mesh-shader cards by opacity micromaps made from the game's own alpha textures, so fences, leaf cards and grass cast their real shapes.
  • Foliage in the default mode. 727 captures the mesh-shader grass, ferns and leaves with native mesh shaders too (the compute fallback run for capture only), plus particles placed by their vertex stage through transform feedback.
  • The sun shadow replaces the game's. Yours takes the darker of the game's value and the ray's, so the game's blurry maps stay under it. 727 writes the traced shadow in the game's place (the world, characters and plants), with a gate that hands back the game's own only if the structure is clearly broken.
  • GI off screen. Yours guesses hits outside the picture (at 0.3) and counts only light in view. 727 injects GI into the game's lighting programs' ambient and shades every hit from material records with its own sun ray, so off-screen and behind-the-camera hits are lit properly.
  • No program cache change. 727 builds bottom levels from the game's buffers in place (static models once, characters re-skinned, the ground evaluated), so vertex modules and the program cache format stay as they are; turning RT on or off prepares nothing again.
  • Reflections on water, metal and glass are in 727 already.

What yours has that 727 lacks, and that I'd like to bring over with credit: the AO into the game's occlusion image with its programs left out, and the quality steps. Your measurement runs and docs/tested/ files are also further along than ours.

One question: your Hookshot runs include night. Which save or recipe got you there? Ours is stuck at 06:00 early in the story.

Hi JayDeGoodz, nice work, and good to see your RT reach a PR. I opened https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/727 this morning with the same goal (RT AO, sun shadows, GI, plus reflections). The two can't both land as they are: both add `gpu/vk/vk_rt.h`, `RX_VK_RT*` switches and `rt_ao_*` shaders, and both hook the same places, so I'd rather we end up with one change than make the maintainers pick. Your AO is done better than ours: you write the traced occlusion into the game's own occlusion image and leave the game's occlusion programs out, so the SSAO's cost goes away, and you offer quality steps. Ours overwrites the game's light mask after its combine, so the game's SSAO still runs. Would you be OK with us bringing that approach into 727, with you as co-author on those commits (`Co-Authored-By`)? If you'd like to do that part yourself as commits on 727's branch, even better. Why I'd suggest 727 as the base rather than the other way round, point by point against your PR's own Limits: - **Out-of-view casters.** Yours: "nothing out of view casts a shadow or lights anything". 727 takes the sun's cascade draws (what the game itself casts from outside the camera's view), the game's shadow-only blocker sheets, and keeps static models the camera has drawn as casters when they leave the view (so an interior keeps its roof). Over 17 areas no sun cascade draw is left out of the structure. - **Cutouts.** Yours: "cutouts (grass, leaf cards) cast nothing". 727 cuts alpha-tested models and mesh-shader cards by opacity micromaps made from the game's own alpha textures, so fences, leaf cards and grass cast their real shapes. - **Foliage in the default mode.** 727 captures the mesh-shader grass, ferns and leaves with native mesh shaders too (the compute fallback run for capture only), plus particles placed by their vertex stage through transform feedback. - **The sun shadow replaces the game's.** Yours takes the darker of the game's value and the ray's, so the game's blurry maps stay under it. 727 writes the traced shadow in the game's place (the world, characters and plants), with a gate that hands back the game's own only if the structure is clearly broken. - **GI off screen.** Yours guesses hits outside the picture (at 0.3) and counts only light in view. 727 injects GI into the game's lighting programs' ambient and shades every hit from material records with its own sun ray, so off-screen and behind-the-camera hits are lit properly. - **No program cache change.** 727 builds bottom levels from the game's buffers in place (static models once, characters re-skinned, the ground evaluated), so vertex modules and the program cache format stay as they are; turning RT on or off prepares nothing again. - **Reflections** on water, metal and glass are in 727 already. What yours has that 727 lacks, and that I'd like to bring over with credit: the AO into the game's occlusion image with its programs left out, and the quality steps. Your measurement runs and `docs/tested/` files are also further along than ours. One question: your Hookshot runs include night. Which save or recipe got you there? Ours is stuck at 06:00 early in the story.
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Guide screenshots / Guide images and local UI source review (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request) Blocked by required conditions
beanstalk/approval waiting for a BigBean's 👍 on the request
PR description / Description follows the template (pull_request_target) Successful in 6s
This pull request is marked as a work in progress.
Some workflows are waiting to be reviewed.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'feat/ray-tracing:JayDeGoodz-feat/ray-tracing'
git switch 'JayDeGoodz-feat/ray-tracing'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!815
No description provided.