Builtin Library
- ..
- README.md2.0 KB
- module.wgsl15.9 KB
README.md
screenReflection
A reflection traced against the scene already drawn, for the fragment that asks.
#include "@builtin::shaderModules.screenReflection"
let traced = zero_trace_reflection(world_position, reflect_dir, zero_reflection_defaults());
let reflected = mix(environment, traced.rgb, traced.a);
zero_trace_reflection answers with the radiance found along reflect_dir in
rgb and how far to trust it in a. A miss answers zero confidence, so the
blend above leaves the caller's own environment untouched and a material needs
no branch.
Why a function and not a pass
A pass over the screen can only trace what the depth buffer holds, and the depth buffer holds opaque geometry. A sheet of glass is not in it, so such a pass has no pixel to trace for it and no normal to trace with — which is why a screen-space pass cannot give a transparent surface a reflection at all.
A fragment has what the pass lacks. It knows where it is, which way it faces and how rough it is, in whatever queue it draws and on whichever render path drew the frame. So it traces its own ray and the answer is about the surface being shaded rather than about whatever stands behind it.
What it marches
zero::scene_depth for the geometry and zero::scene_color for the light on
it — the scene as it stood before the caller drew. For a surface in the
transparent queue that is the lit opaque scene, which is what it should see
reflected. For an opaque surface it is the picture its neighbours shaded into.
Both are read-only storage textures already in group 0, so a material pays no texture slot for this and the trace adds nothing to the binding budgets.
Settings
zero_reflection_defaults() suits a mirror-ish surface at room scale. A
material that wants its own reach, thickness, step budget or strength fills a
ZeroReflectionTrace itself.
A rough surface is the caller's business: one ray describes a mirror, and a material that scatters over a wide lobe should weigh the result down or not ask for it.