Blur Effect with Shader

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Chain
:warning: Old Version Published before Godot 3 was released.

Greetings!
I am going to make this short. I have a game where i want to blur the background. Everything is set already set up, i take the last frame, apply it to a TextureFrame and add a Blur Shader (from Godot Sample Projects) to it. Done.

The thing is the shader looks more glitchy than real blur and i can only turn it up to a certain amount without it completely freaking out.

I looked through some websites but couldn’t find anything useful. Can anyone give me the code for such a blur shader? (I only need shaders for that one thing so I don’t want to invest a huge amount of time in learning them, tough eventually i’ll do that)

Current code (Fragment Shader from Godot Sample Projects):

float radius = 0.009;
float divider = 9.2;
vec3 col = vec3(0);

col+= texscreen(SCREEN_UV+vec2(radius,-0));
col+= texscreen(SCREEN_UV+vec2(-radius,0));
col+= texscreen(SCREEN_UV+vec2(0,0));

col+= texscreen(SCREEN_UV+vec2(-radius,-radius));
col+= texscreen(SCREEN_UV+vec2(radius,-radius));
col+= texscreen(SCREEN_UV+vec2(0,-radius));

col+= texscreen(SCREEN_UV+vec2(0,radius));
col+= texscreen(SCREEN_UV+vec2(-radius,radius));
col+= texscreen(SCREEN_UV+vec2(radius,radius));

col/=divider;
COLOR.rgb=col;
:bust_in_silhouette: Reply From: Zylann

This shader blurs using a 3x3-pixel averaging filter (9 texscreens in a square pattern), like, it filters only in a radius of 1. If you want to blur a larger radius, you need a bigger filter (so a 5x5 filter for radius of 3, 7x7 filter for radius of 5 etc).
Problem is, you cannot just add zillions of texture fetches by making the filter bigger, because it will make your shader terribly expensive in a somewhat exponential way.

There is a nice property of such a filter system though: applying it multiple times will blur more, and adding more steps requires more GPU at a linear cost rather than “exponential” cost.
Unfortunately, I don’t know how to apply the same screen shader multiple times, maybe using several BackBufferCopy nodes?

You can also complement your shader by rendering the blurred thing to a downscaled texture, and render that texture with filter enabled, which will add a cheap linear smoothing on top of your blur. It won’t be as accurate as a blur you would get in an image processing program, but it should look good enough for a game.
(Also note that Godot 3.0 uses similar techniques to render bloom and depth-of-field).

Another performance tip: usually you can blur by fetching only 4 pixels in a “+” pattern rather than all 9 pixels. It is a bit less accurate but the difference won’t be much noticeable, and you’ll double performance of your shader.

Hello. Do you know where I could get a code snippet for such a blur? Because I understand what you are saying but i dont know how to apply it, since i dont understand the shading language.

Chain | 2017-12-08 12:42

Taking your own code snippet and removing some lines, you get a cross-blur shader:

float radius = 0.009; // Note: do you understand what this radius actually is?
float divider = 4.0; // reduced this to 4 because we fetch 4 pixels
vec3 col = vec3(0);

col+= texscreen(SCREEN_UV+vec2(radius,0));
col+= texscreen(SCREEN_UV+vec2(-radius,0));

col+= texscreen(SCREEN_UV+vec2(0,-radius));
col+= texscreen(SCREEN_UV+vec2(0,radius));

col/=divider;
COLOR.rgb=col;

But this blur performs great only if you fetch neighbor pixels, not an arbitrary radius, otherwise it won’t look great.
Unfortunately I don’t know how to easily apply this shader multiple times or downscale its input…

Zylann | 2017-12-08 19:10

float radius = 0.009; // Note: do you understand what this radius actually is?

No I don’t really know what it does. I also don’t know how to apply a shader multiple times. I’ve tried multiplying the material and applying it, but that didn’t work.

Chain | 2017-12-08 19:36

In Godot 3.0 there are more options, you can use mipmaps to blur larger areas while keeping a low cost in a single pass. It’s still compiling on my end at the moment but you can have a look at the latest screen-space demos for 3.0 here: GitHub - godotengine/godot-demo-projects: Demonstration and Template Projects

Zylann | 2017-12-08 19:40

My project is on Godot 2. Can I easily transfer my project, without everything corrupting or crashing? And isnt’t 3.0 very instable?

Chain | 2017-12-08 20:00

Godot 3.0 is in beta 1, it’s not ready yet for production but it does have more flexible ways to blur the screen like you want. The best way to migrate is to do a big review on all your project though, there is a converted worked on in 2.1.4 but it doesn’t do everything.

In 2.1 I don’t know more about blurring (at least in 2D) :confused:

Zylann | 2017-12-08 20:12

Ok, anyway, thanks for your help :slight_smile:

Chain | 2017-12-08 22:03