Skip to content

Refraction

App: apps/refraction_demo/

Demonstrates opaque-colour capture for transparent refraction (engine PLM-238 / ADR 0075). With Graphics.opaqueCaptureEnabled(true), the engine renders the opaque scene, copies it into a capture texture, then renders the transparent draws — which sample that texture at a screen-space UV and offset it to refract. Four opaque colour bands sit behind one transparent quad; the quad bends the bands through it.

Terminal window
% ./plume3d refraction_demo

Four full-height colour bands (red / green / blue / yellow) are drawn opaque at a far depth, with one transparent quad in front. The band boundaries are straight outside the quad and wavy inside it — because the quad samples the captured bands at a time-wobbled UV. That is the proof: the opaque phase is captured and reaches the transparent draw. With capture off (or no post effect) the quad reads white instead.

  • Draws four opaque bands with an ordinary mesh shader (Graphics.newMesh + Graphics.drawMesh).

  • Marks the centre quad transparent so it renders in the second (post-copy) phase:

    _quad.blendMode = "alpha" // classify as transparent → samples the opaque copy
  • Each frame in draw(), enables capture, draws the opaque bands then the quad, and adds a passthrough post effect (opaque capture needs the offscreen path):

    Graphics.opaqueCaptureEnabled(true) // split opaque → copy → transparent
    for (b in _bands) Graphics.drawMesh(b) // opaque phase
    Graphics.drawMesh(_quad) // transparent phase — samples the opaque copy
    Graphics.addPostEffect("shaders/present", []) // passthrough present drives the offscreen path
  • The water shader #include "plume3d.slang" (the mesh ABI) and samples the capture at set 0 binding 6 with a screen-space UV, wobbled by the frame clock:

    float2 wobble = float2(sin(input.ScreenUV.y * 30.0 + plume3d_time() * 3.0),
    cos(input.ScreenUV.x * 30.0 + plume3d_time() * 3.0)) * 0.035;
    float4 behind = plume3d_opaqueColor(input.ScreenUV + wobble);
    return float4(behind.rgb * float3(0.65, 0.82, 1.0), 1.0); // cool water tint

See Graphics.opaqueCaptureEnabled and the opaque-colour refraction guide. Screenshot-verified (the bands bend inside the quad).