Builtin Library
README.md
rt_ao
Ray-traced ambient occlusion: the settings the rt_ao render feature traces on,
and the lifetime of the pass that draws it.
local rtAo = require("@builtin::modules.rt_ao")
renderer.setRaytrace(true) -- the acceleration structure the rays walk
rtAo.set({ quality = "medium" }) -- starts the pass
rtAo.get() -- the settings in force
rtAo.qualityLevels() -- rays per pixel and grid resolution per level
rtAo.stats() -- the grid the running pass actually built
rtAo.active() -- is the pass running
rtAo.clear() -- off, settings kept
What it costs
The rays a frame traces is rays × grid pixels, and the trace pass measures
linear in that product and flat in the scene's entity count. A quality level
picks both numbers:
| quality | rays per pixel | grid resolution | rays per 1920×1080 frame |
|---|---|---|---|
low | 3 | half | 1.6 M |
medium | 6 | half | 3.1 M |
high | 6 | full | 12.4 M |
ultra | 12 | full | 24.9 M |
medium is the default. high is the same estimate per texel on the frame's
own grid, at four times the rays.
Occlusion is low-frequency almost everywhere, so a half-resolution grid holds the shading: a depth-aware upsample carries it back to the frame weighted by the depth of the surface each texel describes, so silhouettes survive it. What a half-resolution grid loses is the innermost pixel of a sharp crease.
The other knobs
| field | effect |
|---|---|
radius | World-space occlusion reach — how long a ray is, so how big a crease has to be to darken. Also sizes the distance the filter behind the trace stops smoothing over, so changing it rebuilds the pass. |
strength | How far the darkening goes where the hemisphere is fully closed, in [0, 1]. 0 turns occlusion off and releases the pass. |
What runs
One compute pass traces the hemisphere into the grid; where the grid is coarser than the frame, a depth-aware upsample lifts it; the shared denoising filter carries the estimate across frames and smooths it across this one; a last pass multiplies the result into the scene colour, and a blit puts it on screen.
rtAo.stats().dispatches counts them, and rtAo.stats().traceTarget is the
occlusion term on its own, for a readback.
Needs the deferred path for @scene.normal (the default), and
renderer.setRaytrace(true) for the structure the rays walk. Runs on the
hardware ray-query backend and the software one alike.