Screen Effects
Pro Extension
Pro screen effects are shader-based fullscreen post-processing effects.
Rendering Paths
| Scene / renderer | Path |
|---|---|
| 2D (any renderer) | CanvasLayer + ColorRect with a canvas_item shader |
| 3D + Compatibility / Mobile | Same CanvasLayer overlay (CompositorEffect is unavailable) |
| 3D + Forward+ | CompositorEffect compute shader on a WorldEnvironment |
Routing is automatic. If compositor setup fails under Forward+, the effect falls back to CanvasLayer and logs a warning.
Available Effects
| Effect | What it does | Key params |
|---|---|---|
vignette |
Darkens screen edges | max_intensity, radius, smoothness, color |
chromatic_aberration |
RGB channel split | intensity, direction |
pixelation |
Pixelates the screen | pixel_size |
blur |
Gaussian blur | strength |
scanlines |
CRT scanline overlay | line_count, opacity |
distortion |
Wave/noise distortion | strength, speed |
How It Works
Each screen effect extends GFFScreenEffectBase and:
- Chooses a render path (see table above).
- For CanvasLayer: finds or creates a fullscreen overlay and animates shader uniforms.
- For Forward+ compositor: attaches a compute
CompositorEffect, maps animated uniforms to push constants (effect.x/effect.y, plusextrafor time / baked params), and cleans up on restore. - On finish or stop, removes owned overlays / compositor effects, or restores uniforms if an overlay was reused.
If the shader cannot be compiled, the effect pushes a warning and does nothing.
Project Setup (3D)
To get the compositor path in a 3D game:
- Set Project → Project Settings → Rendering → Renderer → Rendering Method to Forward+ (desktop) or Mobile.
- Prefer a scene
WorldEnvironmentif you already have one; GFF will reuse it. Otherwise it creates a temporary one for the effect and frees it on cleanup. - Compatibility renderer always uses the CanvasLayer path — that is expected, not a bug.
Code Example
# Fullscreen vignette on damage
GameFeelFlow.play("vignette", $Player)
# Chromatic aberration with custom intensity
var params = GFFParams.create(1.0, 0.5)
params.with_float("intensity", 0.8)
GameFeelFlow.play("chromatic_aberration", $Player, params)
# Pixelation that restores after play
var effect = GFFPixelation.new()
effect.duration = 1.0
effect.restore_after_play = true
GameFeelFlow.play(effect, $Player)
Performance Notes
- Each effect creates at most one overlay / compositor attachment per play owner. Replaying the same effect reuses what it owns.
- Canvas overlays are cheap for simple shaders; compositor compute runs once per view after transparent passes.
- Avoid stacking many different screen effects on the same target simultaneously.
- For persistent screen effects (e.g. permanent vignette), create the overlay once and animate uniforms manually instead of replaying the effect every frame.
Custom Screen Effects
To create your own screen effect, extend GFFScreenEffectBase:
@tool
class_name GFFMyEffect
extends GFFScreenEffectBase
const SHADER_CODE := """
shader_type canvas_item;
uniform float my_param : hint_range(0.0, 1.0) = 0.0;
void fragment() {
COLOR = vec4(my_param, 0.0, 0.0, 1.0);
}
"""
func _get_shader_code() -> String:
return SHADER_CODE
func _get_effect_key() -> String:
return "my_effect"
func _get_animated_uniforms(params: GFFParams, intensity: float) -> Dictionary:
return {"my_param": [0.0, intensity]}
# Optional: Forward+ 3D compute path (snippet runs inside GFFCompositorEffectBase template)
func _get_compute_code() -> String:
return """
color.rgb = mix(color.rgb, vec3(1.0, 0.0, 0.0), params.effect.x);
"""
