Postprocessing: where to run an effect
Choose between 2D color processing, a live render texture and a 3D depth pass.
Choose where the effect runs
First identify the data the effect needs. Processing the color of a displayed image and reading a 3D camera’s depth are different tasks.
| Task | Approach | Working example |
|---|---|---|
| desaturation, color filter, processing a displayed image | canvas_item ShaderMaterial on a ColorRect drawn after the image | Screen-reading shaders |
| two effects with the second reading the first result | explicitly refresh the screen copy between passes | BackBufferCopy chain |
| a separate camera for a portrait, monitor or preview | SubViewport with a camera and a consumer of its ViewportTexture | Live texture |
| surface distance, depth-based haze | spatial shader in the same 3D viewport, hint_depth_texture and reconstructed position | Depth-based 3D postprocessing |
The canvas_item example does not transfer the source room’s depth buffer into the UI. The spatial example does not guarantee processing every UI or transparent material. Choose the processing stage by the data required, not by which Entity type is easiest to add.
Run the accepted 2D chain
Download the screen-effects project. Reckfell 1.0.0, C# SDK, Forward+/Vulkan. Open project.reckfell, build C# and run Main.rscene. Before running, choose root Preview=Grayscale; Original shows the source and Chained shows diagnostic inversion of the gray result.
The scene contains a live 3D source and the sequence Display → TonePass → Copy → InvertPass. With Copy disabled, the second screen-reading shader reads the shared original copy instead of the desaturated image. CopyMode=Viewport between passes gives it the first pass’s result. Simply adding another ColorRect does not make the second pass’s input equal the first pass’s output.
CanvasLayer helps place effects and UI in the intended layers. It is not a universal command to recapture screen_texture. Control actual draw order and BackBufferCopy explicitly. The linked guide contains complete code and the SCREEN_UV explanation; the shader does not need duplicating here.
Run the 3D depth pass
Download the depth project. The same engine and SDK requirements apply. Preview=Haze adds haze using reconstructed distance, Original disables the pass, and Distance shows a diagnostic mask.
This pass is a child of the active camera. It reads that camera’s viewport, uses INV_PROJECTION_MATRIX and does not write its own depth. Compatibility and Forward+ differ in their depth-to-NDC conversion; the shader already includes both branches. Do not replace them with one untested formula.
The 3D color copy is taken at a specific rendering stage. It is not an arbitrary final frame containing every transparent object, particle and UI element. Material priority does not change the capture stage. The depth guide explains the details and contains complete code.
Check your effect
- Obtain the source image with the effect disabled first.
- Neutral parameters should preserve its color. If the frame changes already, check repeated fog/lighting, tonemapping, alpha and the copy stage.
- Change one parameter at a time. Do not adjust camera and exposure simultaneously to hide a shader error.
- Temporarily disable the explicit copy in a chain. If the expected first effect disappears from the second result, check draw order and copy placement.
- For depth, use surfaces at known distances and check Near/Far, projection and renderer changes. A plausible gray mask alone does not prove a correct formula.
The examples are accepted against the current local build. Numerical depth reconstruction is accepted in OpenGL and Vulkan; the full interior and illustrated effects only in Forward+/Vulkan. These examples are not performance measurements, a complete Gaussian blur, a universal compositor for every buffer or application-export acceptance.