reckfellENGINE

Screen-reading shaders: frame copies and chained effects

Desaturate the displayed image and pass the result correctly to a second effect.

On this page

Run the example

Download the project. Requires Reckfell 1.0.0 with the C# SDK and Forward+/Vulkan. Open project.reckfell, build C# and run Main.rscene. Choose root Preview=Original for the room, Grayscale for desaturation, or Chained for the diagnostic chain. At runtime call SetPreview(mode) after _Ready.

A separate SubViewport renders the room and a TextureRect displays it. A canvas_item shader then reads the displayed image. Source creation and the complete C# controller are in the live-texture guide.

Original image:

Original live room texture before the screen effect

The same texture desaturated by the screen shader:

Reading screen_texture and desaturating it in canvas_item

Read screen coordinates

ScreenTone.reckfellshader:

Shader
shader_type canvas_item;
render_mode unshaded;
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear;
uniform float desaturate : hint_range(0.0, 1.0) = 0.0;
void fragment() {
    vec4 source = textureLod(screen_texture, SCREEN_UV, 0.0);
    float gray = dot(source.rgb, vec3(0.2126, 0.7152, 0.0722));
    COLOR = vec4(mix(source.rgb, vec3(gray), desaturate), source.a);
}

hint_screen_texture binds the sampler to a copy of the current viewport’s screen. SCREEN_UV provides coordinates for that screen; UV belongs to the ColorRect’s own geometry. Moving or shrinking the rectangle keeps SCREEN_UV aligned with the image behind it.

repeat_disable prevents wrapping beyond texture edges; filter_linear selects linear sampling. textureLod(..., 0.0) reads the base level here. This example does not implement mipmap blur; increasing LOD without a suitable filter is not a complete blur solution.

At desaturate=0 the shader returns the original color. At 1 all RGB channels equal a weighted gray value. Source alpha is preserved. The ColorRect must draw after the TextureRect and cover the effect area; a white ColorRect without its ShaderMaterial simply covers the image.

Chain two passes

The second shader, ScreenInvert.reckfellshader:

Shader
shader_type canvas_item;
render_mode unshaded;
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear;
void fragment() {
    vec4 source = textureLod(screen_texture, SCREEN_UV, 0.0);
    COLOR = vec4(vec3(1.0) - source.rgb, source.a);
}

The first 2D item using hint_screen_texture obtains a screen copy unless BackBufferCopy has already prepared one. Subsequent screen-reading shaders normally reuse that copy. They do not automatically receive the preceding effect’s output.

The example’s draw order with equal z_index:

  1. Display shows the live room texture.
  2. TonePass desaturates it.
  3. Copy with CopyMode=Viewport copies the desaturated frame.
  4. InvertPass reads the refreshed copy and inverts it.

Disabling Copy makes inversion read the original colored room instead of TonePass’s gray output. Pixel checks confirm that the second pass contains color again. Chained enables the copy, so its result stays gray.

Diagnostic inversion after desaturation; not a finished game color grade:

Two sequential passes: grayscale followed by diagnostic inversion

Copy only the required region

CopyMode=Rect uses Copy.Rect in the BackBufferCopy’s local coordinates. In the accepted case Copy is at the origin, Rect=(0, 0, 1280, 1440), and the second ColorRect draws only the left half. It sees TonePass’s result within that half; the first pass remains visible on the right.

Do not sample beyond the region actually copied: up-to-date contents are not guaranteed there. If a shader offsets its sample coordinates, the copy region must cover those offsets. Start with Viewport and reduce the region after obtaining the correct result.

Diagnose the result

SymptomCheck
no visible effectcanvas_item, assigned ShaderMaterial, ColorRect size and draw order
repeated or misaligned imageSCREEN_UV instead of local UV, repeat_disable
second effect loses the firstBackBufferCopy between passes and CopyMode other than Disabled
adding UI changes the chainactual draw order, z_index and CanvasLayer
stale pixels near effect edgesRect does not cover the sampling area
a 3D shader behaves differentlythis example processes an already displayed texture in 2D, not spatial screen-reading

Accepted in current Forward+/Vulkan: live scene, neutral pass, desaturation, SCREEN_UV on a half-screen rectangle, cached screen-copy reuse, full and rectangular BackBufferCopy. 3D depth/normals, mipmap blur, Compatibility and chain performance are not accepted here. Spatial effects need a separate 3D postprocessing explanation.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.