Xor Shaders
  • Tutorials
  • About

#5 Blur shaders part 1

1/1/2015

8 Comments

 
Make sure you check out the last tutorial. Today, you will learn how to make three blur shaders.
You will make radial blur. Motion blur and gaussian blur will be covered in part 2.

Multiple pixels

Shaders only process one pixel at a time. For bluring, we want the pixel to mix with the surrounding pixels. That is how we would achieve our blur. The easiest way to do this is to use "texture2D()" multiple times with different coordinates. We will make the radial blur first, because it's easier to understand. Radial blur is actually a form of motion blur, but in our case, motion blur will be side to side while radial will give an illusion of depth. 

Radial blur

The radial blur effect we are creating will be produced by mixing the texture with different scaled versions of the texture. So the simplest way to do that is to scale the texture coordinates. Doubling the coordinates, makes the texture half the size, while halving it doubles the size. The reason to this is because the texture coordinates are in the 0 to 1 range so halving it would make the range 0 to 0.5 so, the texture is stretched to twice the size. So keep this in mind when scaling multiplying the texture coordinates. We will make our first radial blur have 10 sizes and blur between them.
We will multiply the textures coordinates by numbers less than 1 to make the textures slightly smaller. Then we'll average the values returned at those coordinates. Your code should look like this:

vec4 Color = (texture2D( gm_BaseTexture, v_vTexcoord )
+ texture2D( gm_BaseTexture, v_vTexcoord*0.99+0.5*0.01 )
+ texture2D( gm_BaseTexture, v_vTexcoord*0.98+0.5*0.02 )
+ texture2D( gm_BaseTexture, v_vTexcoord*0.97+0.5*0.03 )
+ texture2D( gm_BaseTexture, v_vTexcoord*0.96+0.5*0.04 )
+ texture2D( gm_BaseTexture, v_vTexcoord*0.95+0.5*0.05 )
+ texture2D( gm_BaseTexture, v_vTexcoord*0.94+0.5*0.06 )
+ texture2D( gm_BaseTexture, v_vTexcoord*0.93+0.5*0.07 )
+ texture2D( gm_BaseTexture, v_vTexcoord*0.92+0.5*0.08 )
+ texture2D( gm_BaseTexture, v_vTexcoord*0.91+0.5*0.09 )) * 0.1;

gl_FragColor =  Color *  v_vColour;

This code may look confusing, but what it does is rather simple. It gets the average of the different coordinates and centers them with the "+0.5" part. The shader looks like this:
Picture
On the left, is the background before the shader, while on the one on the right is after. We will need some knowledge of integers and for statements before we can finish.

integers

Integers have the fraction part. It is much like a float, but should always be without the fraction.
So if we set a float to 0 it would cause an error, but if we set and integer to 0, it would work as long as you don't mix it with floats. The only way to mix the different variable types is to use their functions (int() converts floats to ints and float() does the opposite). Here is an example:

int i = 4;
float j = 0.5+float(i);

That  code would set i to 4 and j to 4.5. These are used in "for statements" which are particularly useful in blur shaders.

Constants

Constants are variables that are set once and can't be changed. They are constant and so you want to set them first. They are set outside of "void main()" in the format "const variabletype variable = value". An example could be 


const int Number = 48;

That sets the integer "Number" to 48 as an unchanging constant.

For statement in shaders

So to start out this shader you'll need to know how to use a "for statement". The for statement repeats a certain code until specified to stop (they cannot repeat more than 255 times).
So platforms do not run loops well, so keep that in mind when making games. When you use them, you must start with defining a variable (most often an integer), then you check if the variable is less then the number of times we want it to repeat (for our example) , and lastly we add to our variable. Rather than using commas to separate the parts, we use semi-colons.
An example would look like this:

for(int i = 0;i < 16;i++)
{
//code that you want to repeat
}

Now what that does is it sets variable i to 0 (an integer), then checks if i is less than 16. If it is, it will add one to i (i++) and will repeat until i is equal to or greater than 16.

Finishing the radial blur

Now we will use a for statement to blur more than 10 coordinates. We'll start by adding a constant called "Quality" (make sure it's before the "void main()") and set it to 16, then add this code:

vec4 Color;
float v;
for( float i=0.0;i<1.0;i+=1.0/float(Quality) )
{
        v = 0.9+i*0.1;//convert "i" to the 0.9 to 1 range
        Color += texture2D( gm_BaseTexture, v_vTexcoord*v+0.5-0.5*v);
}
Color /= float(Quality);
gl_FragColor =  Color *  v_vColour;


This code defines the vector "Color" and the float "v" (they are set to 0). Then the for statement repeats the code the number of times defined by "Quality". The final result of color is averaged by dividing the total by "Quality". Your full code should look something like this:

varying vec2 v_vTexcoord;
varying vec4 v_vColour;
const int Quality = 16;

void main()
{
    vec4 Color;
    float v;
    for( float i=0.0;i<1.0;i+=1.0/float(Quality) )
    {
            v = 0.9+i*0.1;//convert "i" to the 0.9 to 1 range
            Color += texture2D( gm_BaseTexture, v_vTexcoord*v+0.5-0.5*v);
    }
    Color /= float(Quality);
    gl_FragColor =  Color *  v_vColour;
}


Quality can be changed to any value that suits your purpose. For smaller textures, use smaller numbers and for larger textures, use larger numbers.

DOWNLOAD EXAMPLE
Please share if these help you out!
8 Comments
Jupelius
1/11/2015 12:03:40 am

Can you apply these effects for objects? Or do i have to draw a application surface with these shaders? I tryed to make effect, where a character would get motionblur, or something like that.

The problem i encounter is that, when i manipulate the coordinate, it offsets the graphics and shows a partially other graphics instead. It goes for a real mess.

with you exact codelines, background images will be okei. Sprites are okey, if i make only one sprite for whole game ;) But when adding a second sprite, the effect suddenly missforms somehow.

i think the reason is that gamemaker(1.4) makes all the textures in a Texture Groups. So does the texture coordinate start with zero, or does it gets it from Group Textures and start where it was been saved by gamemaker.

Or Im i just too far away from my skill zone ;)
Im looking different tutorials for shaders, and yours are one that helps to understand a lot to a beginner like me.

I also tried debugging like this.
gl_FragColor = vec4(1.0);
gl_FragColor.a = float(v_vTexcoord.y);
And it does different alpha blend for different images. I know my sprites are not squres. And my main character is the tallest sprite. It seems to blend right with Y values, but sucks if i chance it to X values.

I also did try this to make it work for all sprites, but didnt seem to work.
gl_FragColor.a = clamp(float(v_vTexcoord.y),float(0),float(1));

What im kind of trying to do first is to set different kind of shaders, lets say you would walk on lava and want to have a intence red color rise to character. Like directional color manipulation and stuff. Also dissforming and things, as i learn those, but would be nice to get these simple tasks to work :)

Reply
Xor
1/12/2015 02:00:48 am

Hello Jupelius. Your texturing problem does have to do with texture pages. If you want to fix this you can apply the shader to sprites with "Used for 3D" checked (they have to be a size of 16 by 16, 32 by 32, 64 by 64, etc). You could also try apply the shader to application surface in the draw GUI event. The problem was caused by the size of your sprites so it's best to stick power of 2 sized sprites. In my next tutorial I tell how I would offset the blur along with how to make a motion blur and gaussian blur.

Reply
Eric
9/4/2016 09:14:40 pm

When using the radial blur on a view size that is not a power of 2 the center of the blur is off center. How would you fix this?

Reply
Xor link
9/6/2016 04:22:27 pm

Try applying the shader to a surface. Then you draw anything you need to on the surface and add the blur after. This should work because the surface isn't on the main texture page so It won't be using texture page coordinates.

Reply
jon
11/16/2017 06:36:54 am

hello Xor thanks for this tutorials on shaders
is there any way to make them work better on pixel games ?
ive set the Quality to 2 and still got 3 player images on the screen...

the other blur shader you ve made GAUSSIAN blur worked perfectly... but i dont if its of my level having to much grey color !?! it gives the level a cloudy or mist effect like its raining

Reply
Xor link
11/16/2017 02:24:43 pm

Hello Jon! Glad my tutorials are helpful to you.
Send me an email with details about this gray color you are seeing and I'll see what I can do. Are you applying the shader to the application surface or individual sprites? Are you seeing gray on the edges or on the whole image? Thanks!

Reply
jon
11/17/2017 06:12:10 am

hi xor thanks for taking the time
ive just emailed you throw the website

I think the problem is really the color of the level it gives a nice gaussian blur effect but it stays inside of the images ( i think the effect is to big for smaller images ) ill had to mix up a few shaders to give the effect of luminous colors and blur around the edges... dont know if its the right way to do it :D

Indieklem link
10/15/2022 07:43:19 pm

Thanks for theses tutorials.
Looking to make a shadow with shader in GameMaker Studio for every objects of the room and the gaussian blur is the first step :)

Reply



Leave a Reply.

    Tutorials

    New tutorial at GMshaders.com!

    Categories

    All
    3D
    Beginner
    Intermediate

    Archives

    October 2021
    November 2019
    January 2019
    May 2016
    August 2015
    June 2015
    March 2015
    February 2015
    January 2015
    December 2014

    RSS Feed

Powered by Create your own unique website with customizable templates.