Skip to content

Planar Reflection

App: apps/planar_reflection_demo/

Demonstrates planar reflection (engine PLM-239 / ADR 0078). A row of five coloured cubes floats above a transparent water plane at y = 0; the cubes appear mirrored in the water. With Graphics.setPlanarReflection(true, 0.0), the engine renders the scene once more from the main camera mirrored across the plane into a half-res reflection target (mesh set 0 binding 7), and the water shader samples it at its own screen UV — proving a global reflection feed reaches any lit/water shader with no per-draw binding.

Terminal window
% ./plume3d planar_reflection_demo

An oblique camera looks across the water at a grazing angle (the angle that shows a reflection best); the five cubes hover above the surface and their mirror images sit below it in the water. The demo captures a screenshot at frame 90.

  • Loads a scene shader and a water shader, and marks the water plane transparent so it is excluded from its own reflection (the reflection renders the opaque phase only):

    _plane = Graphics.newMesh(plane(16), "triangles", _water) // water plane at y=0
    _plane.blendMode = "alpha" // TRANSPARENT → excluded from its own reflection
  • Enables planar reflection across the water plane y = 0 — sticky state, set once in init():

    Graphics.setPlanarReflection(true, 0.0) // persists until changed
  • Draws the row of cubes above the water (y = 1.6) so their reflection is visible below, then draws the water plane last — its shader samples the reflection at set 0 binding 7.

  • The water shader (shaders/src/water.slang) #include "plume3d.slang" (the mesh ABI) and reads the reflection at a screen-space UV derived from the clip position:

    float2 screenUv = i.ClipPos.xy / i.ClipPos.w * 0.5 + 0.5;
    float3 refl = plume3d_reflection(screenUv).rgb;
    float3 col = lerp(float3(0.06, 0.12, 0.20), refl, 0.75); // water tint under the reflection
  • The reflection is single-camera in v1 — one reflection plane, skipped under split-screen / composite.
  • Control the mirror’s sharpness/cost with Graphics.setPlanarReflectionScale (default 0.5 = half-res).
  • The reflected content should be above the plane; oblique below-plane clipping of opaque geometry beneath the water is a documented follow-up (ADR 0078).

See Graphics → Planar reflection (A#4). Screenshot-verified (the cubes appear mirrored in the water).