3

I'm trying to implement a gaussian blur on a Texture2D and have had trouble trying to find any good tutorials etc.

I've finally managed to find a nice piece of one-pass sample code and it visibly does blur the image a tiny bit but I want to be able to make it more blurrier and less blurrier over time and I don't know enough about how Gaussian blurring works to realise this.

I guess it must be something to do with the PixelKernel and BlurWeights but I don't really know what these values are for/what changing them does.

So my question is basically:

Is this a good way of doing Gaussian blur in HLSL/XNA? If so, how do I make the scene blurrier? As an added bonus, can you point me to a nice explanation of how Gaussian Blur works in the context of a shader?

Thanks for your time,

TS

P.S.

Just Realised I should include the code:

sampler2D Tex0;

float TintColour;
int TexHeight = 640;
int TexWidth = 480;

const int KernelSize = 7;
float2 PixelKernel[7] = 
{
    {-3, 0},
    {-2, 0},
    {-1, 0},
    {0, 0},
    {1, 0},
    {2, 0},
    {3, 0},
};

const float BlurWeights[7] = 
{
    0.064759,
    0.120985,
    0.176033,
    0.199471,
    0.176033,
    0.120985,
    0.064759,
};

struct VertexShaderOutput
{
    float2 TexCoord0 : TEXCOORD0;
};

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float4 colour = 0;

float2 TexSize = float2(1.0/TexHeight, 1.0/TexWidth);

for(int p = 0; p < 7; p++)
{
    colour += tex2D(Tex0, input.TexCoord0 + (PixelKernel[p] * TexSize)) * BlurWeights[p];
}

colour.a = 1.0f;

return colour;
}

technique Technique1
{
    pass Pass1
    {
        // TODO: set renderstates here.

        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
poncho
  • 1,100
  • 2
  • 15
  • 38
  • have a look at [3D Graphics with XNA Game Studio 4.0](http://www.google.co.il/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0CCQQFjAB&url=http%3A%2F%2Fvrac.castelbrazelbub.net%2FGentoomen%2520Library%2FComputer%2520Graphics%2FPackt.-.3D.Graphics.with.XNA.Game.Studio.4.0.pdf&ei=U5x1UKqQBsjMsgaZ14CIAg&usg=AFQjCNHTf0gc6mssUlaDwZ5OYmpRwQKICA&sig2=8o0V0d2yKGZ_lXhLos8-ZA&cad=rja), chapter 2 & 8, especialy pg.214. – gilad hoch Oct 10 '12 at 16:04
  • To get any kind of strong/wide and correct blur, you're going to need a 2-pass effect. One pass can't sample enough pixels (and certainly can't do so fast enough); two passes decreases complexity from n^2 to 2n, allowing much larger sampling areas and stronger blur. – ssube Oct 10 '12 at 16:06
  • Ah okay @peachykeen thanks for the response, I heard that the 2-pass way was more efficient and better but I couldn't find a nice tutorial/example of it anywhere - especially for HLSL (because I haven't done multipass stuff in HLSL before). – poncho Oct 10 '12 at 16:11
  • XNA may handle most of the messy parts for you (multiple surfaces and such), and the actual HLSL code is very simple. The idea is to blur vertically, then horizontally; because complexity is 2n, you can blur a 10 pixel radius with 20 samples (vs 100 for single-pass). I've pulled some basic code from an old shader here: http://pastebin.com/eBf0W9F1 but there are many other implementations. If you're working on a bloom or depth of field effect, there are pre- and post-passes that get added to that. The passes can be repeated for more blur. – ssube Oct 10 '12 at 18:02
  • Note: just noticed the snippet I posted is used spaced samples. Grabbed the wrong pair of passes, those are meant for a second (even wider) blur run. You'd typically want to use 1/2/3/4 (instead of the 1/3/5/7 given) for initial blur. – ssube Oct 10 '12 at 18:11
  • Check out the [XNA Bloom Sample](http://xbox.create.msdn.com/en-US/education/catalog/sample/bloom) that demonstrates how to do this effect in two passes. – Andrew Russell Oct 11 '12 at 04:56
  • Ah cool thanks everyone! I've got it working based on the page 214 @giladhoch sent a link for but now I'm having a problem with drawing other things on top of the image. I'm using Kinect and blurring the Color feed from it after capturing it as a Texture2D but I want to be able to display Icons on top using SpriteBatch. This used to work when the Tex2D from the kinect in a SB Begin/End with the icons but now that it uses the RenderCapture and the PostProcessor classes either my Icons don't draw or my Icons draw but the kinect image doesn't. Does anyone know how I'd get around this? – poncho Oct 11 '12 at 12:37
  • Ah - ignore the last message this seems to now be working. I know it's not good practice to use multiple SpriteBatches but it seems like the only way I can do it to only apply the blur to one texture2d and have the others display normally. Thanks everyone for all the help! I will try and return the favour when I become an XNA guru :) – poncho Oct 11 '12 at 12:40
  • @user319256 you should answer your own question here. – gilad hoch Oct 11 '12 at 13:26

1 Answers1

1

This is quite outdated by someone might still be looking for answer so:

If you want some decent quality that can be competitive in modern market (Unreal Engine 3 - 4 and similar) then solution is multipass 2-pass gaussian blur.

As you´ve been told use two pass guassian blur reducing complexing of computation. Now, when you have algorithm for that what you want to do is multiple passes on different resolution, let´s start with 3.

Make 1/2 render target of full screen, do your two pass blur, keep result. Make 1/4 render target of original, blur. Make 1/8 render target of origina, blur.

Each one will have different kernel (use stronger blur for lower resolution), now you are done with it combine all RTs into result with decent quality.

3 resolutions are actually kinda old school, used in Unreal Engine 3 (udk) for bloom, Unreal engine 4 use 5 + full res buffer blur is being considered.

Of course you can also consider box blur, personally I would use multipass box blur with large kernel on lower count of overall passes, but this requires some testing.

  • Thanks for the information @user3821985 - I managed to get it working with the standard XNA framework because it make it easy to get to the kinect data in c# but unreal sounds like a cool/more powerful way to do it (if the kinect data is directly accessible). – poncho Jun 08 '15 at 02:52