There are different ways to perform blur and this is one of the most common way to do it in a shader. It’s a two step method with first a horizontal blur and then a vertical blur. By splitting the work in two directions (two passes) you can save a lot of computation.

The method can be divided in the following parts:

- Render the scene you want to blur to a texture (could be downsampled)
- Render a screen aligned quad with the horizontal blur shader to a texture
- Render a screen aligned quad with the vertical blur shader to the screen or texture depending on what you want to use it for

The following image shows how the blur works when splitted up in two directions.

Here’s the horizontal blur shader.

Vertex Shader (GLSL) . This shader screen align a quad with width 1. Any method to render a screen aligned quad will work. So you’re free to use other shaders.

varying vec2 vTexCoord; // remember that you should draw a screen aligned quad void main(void) { gl_Position = ftransform();; // Clean up inaccuracies vec2 Pos; Pos = sign(gl_Vertex.xy); gl_Position = vec4(Pos, 0.0, 1.0); // Image-space vTexCoord = Pos * 0.5 + 0.5; } |

Fragment Shader (GLSL)

uniform sampler2D RTScene; // the texture with the scene you want to blur varying vec2 vTexCoord; const float blurSize = 1.0/512.0; // I've chosen this size because this will result in that every step will be one pixel wide if the RTScene texture is of size 512x512 void main(void) { vec4 sum = vec4(0.0); // blur in y (vertical) // take nine samples, with the distance blurSize between them sum += texture2D(RTScene, vec2(vTexCoord.x - 4.0*blurSize, vTexCoord.y)) * 0.05; sum += texture2D(RTScene, vec2(vTexCoord.x - 3.0*blurSize, vTexCoord.y)) * 0.09; sum += texture2D(RTScene, vec2(vTexCoord.x - 2.0*blurSize, vTexCoord.y)) * 0.12; sum += texture2D(RTScene, vec2(vTexCoord.x - blurSize, vTexCoord.y)) * 0.15; sum += texture2D(RTScene, vec2(vTexCoord.x, vTexCoord.y)) * 0.16; sum += texture2D(RTScene, vec2(vTexCoord.x + blurSize, vTexCoord.y)) * 0.15; sum += texture2D(RTScene, vec2(vTexCoord.x + 2.0*blurSize, vTexCoord.y)) * 0.12; sum += texture2D(RTScene, vec2(vTexCoord.x + 3.0*blurSize, vTexCoord.y)) * 0.09; sum += texture2D(RTScene, vec2(vTexCoord.x + 4.0*blurSize, vTexCoord.y)) * 0.05; gl_FragColor = sum; } |

And here’s the vertical blur shader.

Vertex Shader (GLSL) (the same as for the blur in horizontal direction)

varying vec2 vTexCoord; // remember that you should draw a screen aligned quad void main(void) { gl_Position = ftransform();; // Clean up inaccuracies vec2 Pos; Pos = sign(gl_Vertex.xy); gl_Position = vec4(Pos, 0.0, 1.0); // Image-space vTexCoord = Pos * 0.5 + 0.5; } |

Fragment Shader (GLSL)

uniform sampler2D RTBlurH; // this should hold the texture rendered by the horizontal blur pass varying vec2 vTexCoord; const float blurSize = 1.0/512.0; void main(void) { vec4 sum = vec4(0.0); // blur in y (vertical) // take nine samples, with the distance blurSize between them sum += texture2D(RTBlurH, vec2(vTexCoord.x, vTexCoord.y - 4.0*blurSize)) * 0.05; sum += texture2D(RTBlurH, vec2(vTexCoord.x, vTexCoord.y - 3.0*blurSize)) * 0.09; sum += texture2D(RTBlurH, vec2(vTexCoord.x, vTexCoord.y - 2.0*blurSize)) * 0.12; sum += texture2D(RTBlurH, vec2(vTexCoord.x, vTexCoord.y - blurSize)) * 0.15; sum += texture2D(RTBlurH, vec2(vTexCoord.x, vTexCoord.y)) * 0.16; sum += texture2D(RTBlurH, vec2(vTexCoord.x, vTexCoord.y + blurSize)) * 0.15; sum += texture2D(RTBlurH, vec2(vTexCoord.x, vTexCoord.y + 2.0*blurSize)) * 0.12; sum += texture2D(RTBlurH, vec2(vTexCoord.x, vTexCoord.y + 3.0*blurSize)) * 0.09; sum += texture2D(RTBlurH, vec2(vTexCoord.x, vTexCoord.y + 4.0*blurSize)) * 0.05; gl_FragColor = sum; } |

And this is a scene without blur.

And this is the same scene but with gaussian blur.

You can tweak the blur radius to change the size of the blur and change the number of samples in each direction.

Cost for separable blur shader : 9+9 = 18 (number of texture samples)

Cost for shader if blured in one pass: 9*9 = 81 (number of texture samples)

So splitting up in two directions saves a lot.

The gaussian weights are calculated accordingly to the gaussian function with standard deviation of 2.7. These calculations were done in the excel document found [2].

Here’s a description of blur shaders and other image processing shaders in DirectX:

[1] http://ati.amd.com/developer/shaderx/ShaderX2_AdvancedImageProcessing.pdf

More info about calculating weights for separable gaussian blur:

[2] http://theinstructionlimit.com/?p=40

SatoshiWhy vertex shader?

Why vTexCoord = Pos * 0.5 + 0.5;

adminPost authorSorry for confusing you, this vertex shader might not be useful for everyone since it’s goal is to align a simple quad to the view and stretch it to cover the entire screen. If you’re already sending in a screen aligned quad, you can skip the vertex shader!

SatoshiPicture is wrong!

middle pixel is too dark. blur = 5/25

Sorry for my bad english

JustinIsn’t this just a box filter blur? Gaussian blurs are weighted based on their distance from the center. In your pixel shader you just take the average of all the pixels. This works fine in practice, but calling it a Gaussian blur is misleading.

JustinI take that back. You ARE weighting the neighbors based on their distance. Sorry about that. However, their weight is based on a linear decay, not a Gaussian function.

adminPost authorYes, I’m using the distance, but as you say, the weights are not really gaussian weights. But they are actually close enough to look good. I will add the “true” gaussian weights to this example since it’s more correct that way.

Thanks for the feedback!

Promit RoyYour filter weights are wrong somewhere.

2 * (0.05 + 0.09 + 0.12 + 0.15) + 0.16 = 0.98

This is probably the reason for #2′s darkness problem, and if you try to use this blur with VSM for example the results will be completely wrong.

JohnThanks for this, I’m looking for a good blur effect to blur a particle system so that I can make stuff like fire, fireworks, pulsating clouds etc …. I reckon this might do the trick!

LukeI am a student and doing Image Processing Coursework

Do you apply the Gaussian mask to the RGB components ot the YCbCr components of the image?

I have tried and both seem to produce the same result.

homerWhat if i need to use different radius size?

Florian MärklIn both vertical and horizontal fragment shaders you have written:

// blur in y (vertical)

You should change that to avoid confusion

ChrisWhat happens at the borders when texture2D is trying to read pixels outside the image? For example when vTexCoord.x is 0 and you call texture2D to access pixels at vTexCoord.x – 4 * blursize? What is the texture2D return value in this case and how does it contribute to the filter kernel?

Pingback: ND2D – Blur - nulldesign // lars gerckens

Arely KampsI am so grateful for your blog post.Much thanks again. Cool.

Ceausescu n-a muritRTBlurH? ussless article. incomplte!

inessindycheap viagra online – cheap viagra , http://cheapqualityviagra.com/#9110 buy generic viagra

Pingback: Faster Gaussian Blur in GLSL | xissburg

court reporter u quiz siteHey there! I know this is kinda off topic however , I’d figured I’d

ask. Would you be interested in exchanging links

or maybe guest writing a blog article or vice-versa? My website covers a lot of the same subjects as yours and

I believe we could greatly benefit from each other.

If you are interested feel free to send me an e-mail. I look forward to

hearing from you! Fantastic blog by the way!

Weight loss after babyrloaqhbnfsfoefsjoh, Weight loss drug, aqHkmOz, [url=http://aboutweightloss.co.uk/]Weight loss herbal[/url], uQxXJcr, http://aboutweightloss.co.uk/ Weight loss healthy, EWdclVK.

Nick WiggillHi admin,

You mentioned that vertex shaders are not necessary if you’re already passing in a screen-aligned quad. In that case, how would you make the draw call? As you surely do not need to pass any geometry in for the blur passes?

Thanks,

Nick

Nick WiggillNot to worry, I’m just being silly. Of course I will be passing in the fullscreen quad’s geometry via glDrawElements.

Pingback: Desfoque Gaussiano Mais Rápido em GLSL | xissburg

Pingback: Custom Blur Shader for Unity3D | Ana Todor Blog Journey | blur shader

préstamos rápidosHi there this is kinda of off topic but I was wondering if blogs use WYSIWYG editors or if you have

to manually code with HTML. I’m starting a blog soon but have no coding know-how so I wanted to get guidance from someone with experience. Any help would be greatly appreciated!

Pingback: Magic in-depth | Harmony & Rainbow Factory

KieraDoes your website have a contact page? I’m having problems locating it but, I’d like to

send you an email. I’ve got some recommendations for your blog you might be interested in hearing. Either way, great site and I look forward to seeing it develop over time. Thanks, so much appreciated!

celine shoulder bagJust wanna input on few general things, The website design is perfect, the content is really fantastic. “To imagine is everything, to know is nothing at all.” by Anatole France.

stop premature ejaculationHmm is anyone else having problems with the images on this blog loading?

I’m trying to find out if its a problem on my end or if it’s the blog.

Any responses would be greatly appreciated.

สัตว์แปลกI appreciate for this perfect topic & description of this question. You’ve made it out better than any presentation I’ve seen. Also thx for citing my text on it. Your’s takes it higher.

กลูต้าIsn’t this just a box filter blur? Gaussian blurs are weighted based on their distance from the center.

เปิดหารThanks for this, I’m looking for a good blur effect to blur a particle system so that I can make stuff like fire

ทัวร์พม่าI believe we could greatly benefit from each other.

ทัวร์เวียดนามIf you are interested feel free to send me an e-mail. I look forward to

hearing from you! Fantastic blog by the way!

ทัวร์ลาวThe commenting policy makes perfect sense, as long as it’s applied reasonably neutrally.

รับทำเว็บไซต์If, for instance, a comment that simply stated “This incident shows how the Chinese treat all Westerners as barbarians and are ignorant.” were let through, then I think there is a problem. But if Mark applies his rule in a viewpoint-neutral way, then I applaud the effort.

prestamos onlineExcelente articulo,estos temas no son faciles de entender, pero con este tipo de articulos se entiende bastante bien,gracias.

www.flickr.comWonderful work! That is the kind of information that are supposed to be shared across the internet.

Shame on Google for not positioning this publish upper! Come on over and talk over with my website

. Thanks =)

Louis Vuitton HandbagsWhen I initially commented I clicked the “Notify me when new comments are added” checkbox and now

each time a comment is added I get several emails

with the same comment. Is there any way you can remove people

from that service? Thank you!

bliss bath productsSimon Neil of japanese stone bunch Biffy Clyro executes with the major degree of

the moment special day of the whole “c within the Park” tracks festival

inside Kinross on june 12, 2008. The expensive vacation event honors the fiskars 6201 momentum’s

15th anniversary this current year with title of the article functions

such as the Verve, anger Against The contraption,

and R.E.M. likely to conduct throughout the three-day festival.

AFP Photo/Ed Jones

Here is my weblog bliss bath products

google authorship programYes! Finally someone writes about iron chef.