Gaussian blur for Godot 4.3 Canvase layer
I made it with Chat GPT … I don’t know how it works … but i know that Chat GPT needed alot of help to get here so here you go …
EDIT: the one pass shader made my fps go down from 700 to 16 … so i updated it to 2 pass shader and a static kernel … this got things back up to 400 fps … not great for a blur but this is my best
you will have to create a canvase stack and 2 shader one vertical and the other horzantail … it is a smiple uncomment in the code … I also added a soft blur transtion to non blured … the varubles are exproted and the preview tells the full story …
2025/01/04 edit: godot 4.5
fixed the Horizontal blur being a veritcal blur
notes:
– if you are looking for a static 5 pixel Gaussian blur just go with godot documented shader
godot shader docs
after testing this shader drops the fps at 5 pixels from 600 to 300 while godot shader holds it at 400
– both shaders tank fps from 70 to 10 on moblie so they are not recommended
– using this shader in two passes causes major problems with button and ui, espcially when using custom viewports, even after looking into the layer order in the scene tree or the canvas custome proparty
– this shader breaks when used in viewports, it simply show a dark side untile you change the window size a bunch (shaking the game viewport in engine) then it start working, and somtimes it just works then breaks when the viewport size changes, most importantly it is broken in a relese build
though i am dropping the effect in my project because none of the gaussian blur effects tested had good proformnacei still know that it can be done as unreal has an blur effect that has almost no impact on proformance, so it can be done I just don’t know how
Shader code
// A Gaussian blur shader for Godot 4.3 - 4.5
shader_type canvas_item;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
// The radius of the blur effect (number of pixels to blur, NOT USED).
uniform int blur_radius : hint_range(1, 32) = 8;
// Controls the intensity of the blur. (NOT USED)
uniform float blur_strength : hint_range(0.1, 10.0) = 10.0;
// Direction of the fade: 0 = left, 1 = right, 2 = top, 3 = bottom.
uniform int fade_direction : hint_range(0, 3) = 0;
// Sets the cutoff point for the blur fade (0.0 to 1.0).
uniform float fade_cutoff : hint_range(0.0, 1.0) = 0.2;
// Controls the sharpness of the fade transition.
uniform float fade_intensity : hint_range(0.1, 10.0) = 2.0;
// Precomputed weights for the Gaussian kernel. (NOT USED)
float gaussian_weight(float i, float sigma) {
return exp(-0.5 * (i * i) / (sigma * sigma));
}
// Precomputes the weights for the Gaussian kernel.
void calculate_kernel(out float kernel[32], int radius, float sigma) {
float sum = 0.0;
for (int i = 0; i <= radius; i++) {
kernel[i] = gaussian_weight(float(i), sigma);
sum += i == 0 ? kernel[i] : 2.0 * kernel[i];
}
for (int i = 0; i <= radius; i++) {
kernel[i] /= sum;
}
}
// Computes the fade factor based on the direction and UV coordinates.
float calculate_fade(vec2 uv) {
float fade = 0.0;
if (fade_direction == 0) {
fade = uv.x; // Left to right
} else if (fade_direction == 1) {
fade = 1.0 - uv.x; // Right to left
} else if (fade_direction == 2) {
fade = uv.y; // Top to bottom
} else {
fade = 1.0 - uv.y; // Bottom to top
}
// Normalize fade based on cutoff and intensity.
if (fade < fade_cutoff) {
return 1.0; // Full blur
}
// Scale fade factor smoothly to 0 at the edge.
fade = (fade - fade_cutoff) / (1.0 - fade_cutoff);
return clamp(pow(1.0 - fade*2.0, fade_intensity), 0.0, 1.0);
}
void fragment() {
vec2 resolution = SCREEN_PIXEL_SIZE;
vec2 uv = SCREEN_UV;
// Calculate the fade factor.
float fade_factor = calculate_fade(uv);
// Gaussian kernel weights.
float kernel[32] ;//= gaussian_32; // remove this varuble and enable the next line
calculate_kernel(kernel, blur_radius, blur_strength);
vec4 final_color = vec4(0.0);
// Horizontal blur pass.
//for (int i = -blur_radius; i <= blur_radius; i++) {
//final_color += texture(SCREEN_TEXTURE, uv + vec2(float(i),0.0) * resolution, 0.0).rgba * kernel[abs(i)];
//}
// Vertical blur pass.
//for (int i = -blur_radius; i <= blur_radius; i++) {
//final_color += texture(SCREEN_TEXTURE, uv + vec2(0.0, float(i)) * resolution).rgba * kernel[abs(i)];
//}
//One pass blur ... ***VERY BAD PROFORMANCE***
for (int x = -blur_radius; x <= blur_radius; x++) {
for (int y = -blur_radius; y <= blur_radius; y++) {
float weight = kernel[abs(x)] * kernel[abs(y)];
vec2 offset = vec2(float(x), float(y)) * resolution;
final_color += texture(SCREEN_TEXTURE, uv + offset).rgba * weight;
}
}
// Output the blurred color.
final_color.a = fade_factor;
COLOR = final_color;
}


“i used chatgpt and it runs bad” what a shock
it is my first shade … i did learn more about gaushain blur created a custom kernel and it still runs bad
looked online for GLSL shaders found similar implementations still runs bad … split the shader into to steps using two canvas layers … still runs badly … watched Acerola’s video on making shaders, wrote a C program to generate the kernel and use it as static input …
all of them combined tanked the fps by about 70% which is still insane …
Note that i am trying to run at lest 8*8 Gaussian blur in real time on top of actively moving objects .. I know it is possible because unreal has a built in blur widget that gets the job done perfectly … I tried digging that up but failed
so please if you have a better way share it … with that being said for menus this still works fine i guess … i just came back to copy it and give it another shot