# [Shader Library] Gaussian Blur Post Processing Filter in GLSL

*A cute nurse half blurred in GeeXLab*

Gaussian blur is a filter widely used in computer graphics. In real time 3D, Gaussian blur is used in many effects like

**depth of field**or

**bloom**.

*Depth of field effect uses Gaussian blur filter*

Many years ago, I wrote a tutorial about image filtering with GLSL where I gave an example of Gaussian filter. Few days ago, Daniel Rakos wrote a detailed article about an efficient Gaussian blur with linear sampling.

Since I’m always looking for new effects and shaders for GeeXlab, I decided to implement Daniel’s work in a GeeXLab demo.

Basically, the gaussian blur filter works with two passes: one vertical and the other horizontal. Why two passes? Wikipedia gives us the answer:

A Gaussian blur effect is typically generated by convolving an image with a kernel of Gaussian values. In practice, it is best to take advantage of the Gaussian Blur’s linearly separable property by dividing the process into two passes. In the first pass, a one-dimensional kernel is used to blur the image in only the horizontal or vertical direction. In the second pass, another one-dimensional kernel is used to blur in the remaining direction. The resulting effect is the same as convolving with a two-dimensional kernel in a single pass, but requires fewer calculations.

Here is the complete vertical gaussian filter used in the demo (you can download the demo at the end of the post):

[Vertex_Shader] void main(void) { gl_Position = ftransform(); gl_TexCoord[0] = gl_MultiTexCoord0; } [Pixel_Shader] uniform sampler2D sceneTex; // 0 uniform float rt_w; // render target width uniform float rt_h; // render target height uniform float vx_offset; float offset[3] = float[]( 0.0, 1.3846153846, 3.2307692308 ); float weight[3] = float[]( 0.2270270270, 0.3162162162, 0.0702702703 ); void main() { vec3 tc = vec3(1.0, 0.0, 0.0); if (gl_TexCoord[0].x<(vx_offset-0.01)) { vec2 uv = gl_TexCoord[0].xy; tc = texture2D(sceneTex, uv).rgb * weight[0]; for (int i=1; i<3; i++) { tc += texture2D(sceneTex, uv + vec2(0.0, offset[i])/rt_h).rgb \ * weight[i]; tc += texture2D(sceneTex, uv - vec2(0.0, offset[i])/rt_h).rgb \ * weight[i]; } } else if (gl_TexCoord[0].x>=(vx_offset+0.01)) { tc = texture2D(sceneTex, gl_TexCoord[0].xy).rgb; } gl_FragColor = vec4(tc, 1.0); }

And here is the complete horizontal gaussian filter used in the demo:

[Vertex_Shader] void main(void) { gl_Position = ftransform(); gl_TexCoord[0] = gl_MultiTexCoord0; } [Pixel_Shader] uniform sampler2D sceneTex; // 0 uniform float rt_w; // render target width uniform float rt_h; // render target height uniform float vx_offset; float offset[3] = float[]( 0.0, 1.3846153846, 3.2307692308 ); float weight[3] = float[]( 0.2270270270, 0.3162162162, 0.0702702703 ); void main() { vec3 tc = vec3(1.0, 0.0, 0.0); if (gl_TexCoord[0].x<(vx_offset-0.01)) { vec2 uv = gl_TexCoord[0].xy; tc = texture2D(sceneTex, uv).rgb * weight[0]; for (int i=1; i<3; i++) { tc += texture2D(sceneTex, uv + vec2(offset[i])/rt_w, 0.0).rgb \ * weight[i]; tc += texture2D(sceneTex, uv - vec2(offset[i])/rt_w, 0.0).rgb \ * weight[i]; } } else if (gl_TexCoord[0].x>=(vx_offset+0.01)) { tc = texture2D(sceneTex, gl_TexCoord[0].xy).rgb; } gl_FragColor = vec4(tc, 1.0); }

The *vx_offset* uniform allows to control the X position of the vertical red line:

*vx_offset = 0.71*

*vx_offset = 0.12*

The

*vx_offset*is controled by the tweak bar and the value is divided by 100: 71 gives 0.71.

**And what about the background image???**

Just visit this page: KusoPOP Nurse by *VampBeauty or this one: vampbeauty.com 😉

With that kind of image, post FX coding is a real pleasure…

## DOWNLOAD

*Left-click to download (right-click disabled)*

[download#164#image]

### *** You need GeeXLab 0.2.4 or higher to run this demo. ***

Unzip the demo somewhere, start GeeXLab and drop in the main window the demo source code (*GaussianBlur_Effect_Demo.xml*). Gaussian blur shaders are localized in the PostFX_GaussianBlur_Lib.xml file. The shortcut [Ctrl+R] in GeeXLab allows to reload the demo once you have modified the source code.

Enjoy!

*looks at shots* ummm such a nice advertising posters. I like this tool now 😀 we all must have it )))

The math fact is that some convolution kernel are separable : If a square matrix could be obtained from a row and a col vector, the matrix is separable.

Here the explanation :

http://blogs.mathworks.com/steve/2006/10/04/separable-convolution/

Thanks for the separable convolution link. The explanation is simple and clear.

Nice post and nice image 😀

I’m glad to see that my work inspired you to write the demo and article!

Nice to have this in the collection! Since your post, Daniel’s fixed his code’s weights a bit so that they sum to one. I’d recommend fixing your weights to match his.

Thanks Eric, updated!

Pingback: Real-Time Rendering · Quick Gaussian Filtering

ulala that girl is HaWT, any hd pic of that? hehe

You could make tc a vec4 and change all the

“texture2D(sceneTex, ).rgb” to

“texture2D(sceneTex, )” and

“gl_FragColor = vec4(tc, 1.0);”

to

“gl_FragColor = vec4(tc);”

and the alpha value is blended as well!

nice boobs 😮

I see a picture of Linda Le(Vampy bit Me) there. Nice.