Film Grain Shader

film grain shader effect on scene with pirate ship and sea shore, low poly art

Film grain is one of the final effects that you apply to add a bit of stylized look or realism to your game. The slight imperfections it adds makes scene look more natural.

How it works?

Film grain is post processing screen space shader; which takes whole rendered scene as texture & applies grains to it.

The grains are just white noise. Their intensity & size can be adjusted. Additionally, we can generate animated noise for animated film grains.

Implementation

  1. Pass screen texture, grain size, amount, and other uniforms.
  2. Sample screen texture in fragment shader.
  3. Generate pseudo-random noise.
  4. Add noise to screen texture.
  5. Clamp the final color to keep it in range (0, 1) & apply to the fragment color.

The following implementation is for Godot 4; but the Godot shader language is almost same as GLSL.

Shader Code

shader_type canvas_item;

uniform sampler2D screen_texture : hint_screen_texture;
uniform float grain_amount : hint_range(0.0, 1.0) = 0.05; // Adjust the amount of grain
uniform float grain_size : hint_range(0.1, 10.0) = 1.0; // Adjust the size of the grain
uniform bool animate = false;

void fragment() {
	// Sample the original screen texture
	vec4 original_color = texture(screen_texture, SCREEN_UV);
	
	float noise = 0.0;
	
	if (animate) {
		// Generate random noise
		noise = (fract(sin(dot(UV * TIME, vec2(12.9898, 78.233))) * 43758.5453) - 0.5) * 2.0;
	} else {
		 noise = (fract(sin(dot(UV, vec2(12.9898, 78.233))) * 43758.5453) - 0.5) * 2.0;
	}
	// Add noise to the original color
	original_color.rgb += noise * grain_amount * grain_size;
	
	// Clamp the final color to make sure it stays in the valid range
	COLOR = clamp(original_color, 0.0, 1.0);
}