Gaussian Blur with Depth Preservation


This post will show a simple implementation of a gaussian blur effect with edge preservation.

Sometimes (like in fluid rendering) we need to perform a gaussian blur but we also need to still with edge preservation. The following code shows how to achieve this.

First, we need to calculate the Gaussian Blur Kernel and sent them to the GPU:

   
private float sigma;
        private float[] kernel;
        private Vector2[] offsetsHoriz;
        private Vector2[] offsetsVert;
        private int radius;
        private float amount;
        void ComputeKernel(int blurRadius, float blurAmount)
        {
            radius = blurRadius;
            amount = blurAmount;

            kernel = null;
            kernel = new float[radius * 2 + 1];
            sigma = radius / amount;

            float twoSigmaSquare = 2.0f * sigma * sigma;
            float sigmaRoot = (float)Math.Sqrt(twoSigmaSquare * Math.PI);
            float total = 0.0f;
            float distance = 0.0f;
            int index = 0;

            for (int i = -radius; i <= radius; ++i)
            {
                distance = i * i;
                index = i + radius;
                kernel[index] = (float)Math.Exp(-distance / twoSigmaSquare) / sigmaRoot;
                total += kernel[index];
            }

            for (int i = 0; i < kernel.Length; ++i)
                kernel[i] /= total;
        }
        void ComputeOffsets(float textureWidth, float textureHeight)
        {
            offsetsHoriz = null;
            offsetsHoriz = new Vector2[radius * 2 + 1];

            offsetsVert = null;
            offsetsVert = new Vector2[radius * 2 + 1];

            int index = 0;
            float xOffset = 1.0f / textureWidth;
            float yOffset = 1.0f / textureHeight;

            for (int i = -radius; i <= radius; ++i)
            {
                index = i + radius;
                offsetsHoriz[index] = new Vector2(i * xOffset, 0.0f);
                offsetsVert[index] = new Vector2(0.0f, i * yOffset);
            }
        }       

We call both funtions in Intialization time passing the parameters: blurRadius = something ranging from 2 to 15 (the Kernel width), blurAmount = blur scale parameter, textureWidth = width of the texture that will be blured, textureHeight = same for height.

Here is the shader that Performs the Gaussian Blur (the RADIUS value must be defined in Compilation time, it must have the same value used in CPU side)

#define RADIUS  15
#define KERNEL_SIZE (RADIUS * 2 + 1)
float weights[KERNEL_SIZE];
float2 offsets[KERNEL_SIZE];

float2 GBufferPixelSize; ///half pixel size of the origin render target(0.5f /width , 0.5f/height)
float2 TempBufferRes; ///destiny buffer size
float blurDepthFalloff;

sampler2D depthSampler : register(s0);
sampler2D ssaoSampler : register(s1);

struct VertexShaderInput
{
    float4 Position : POSITION0;
	float2 TexCoord : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
	float4 TexCoord : TEXCOORD0;
};

VertexShaderOutput VertexShaderBlur(VertexShaderInput input)
{
    VertexShaderOutput output = (VertexShaderOutput)0;

	output.Position = input.Position;
	output.TexCoord.xy = input.TexCoord + GBufferPixelSize;
	output.TexCoord.zw = input.TexCoord + 0.5f / TempBufferRes;
	return output;
}

/////////////////////////////////// bilateral

float4 PS_GaussianBlurTriple(float4 texCoord : TEXCOORD0) : COLOR0
{
    float3 color = 0;

    float depth = tex2D(depthSampler, texCoord.xy).x;	

    float s=0;
    for (int i = 0; i < KERNEL_SIZE; ++i)
	{
		float3 im = tex2D(ssaoSampler, texCoord.zw + offsets[i] );
		float d = tex2D(depthSampler, texCoord.xy + offsets[i] ).x;
		float r2 = abs(depth - d) * blurDepthFalloff;
		float g = exp(-r2*r2);
		color +=  im* weights[i] * g;
		s+=g* weights[i];
	}
	color = color/s;
	return float4(color,1);
}

technique GAUSSTriple
{
    pass p0
    {
	VertexShader = compile vs_3_0 VertexShaderBlur();
        PixelShader = compile ps_3_0 PS_GaussianBlurTriple();
    }
}

//////////////////////////////////////

float4 PS_GaussianBlurSingle(float4 texCoord : TEXCOORD0) : COLOR0
{
    float color = 0;
    float depth = tex2D(depthSampler, texCoord.xy).x;	

	float s=0;
    for (int i = 0; i < KERNEL_SIZE; ++i)
	{
		float im = tex2D(ssaoSampler, texCoord.zw + offsets[i] ).x;
		float d = tex2D(depthSampler, texCoord.xy + offsets[i] ).x;
		float r2 = abs(depth - d) * blurDepthFalloff;
		float g = exp(-r2*r2);
		color +=  im* weights[i] * g;
		s+=g* weights[i];
	}
	color = color/s;
	return float4(color,0,0,1);
}

technique GAUSSSingle
{
    pass p0
    {
		VertexShader = compile vs_3_0 VertexShaderBlur();
        PixelShader = compile ps_3_0 PS_GaussianBlurSingle();
    }
}

I included two version of the pixel shader, one for Color Texture and another for float point textures (used in fluid rendering for example).
The blurDepthFalloff is a artistic/adjustment parameter
The DepthTexture is a texture containing the depth of the Scene (in z/w form). See this article for more details about how to generate it.

To render the Scene (Post Effect) we use Render a Quad using the previous shader and the avaluated parameters.

            rHelper.PushRenderTarget(RenderTarget2D);
            effect.Parameters["blurDepthFalloff"].SetValue(blurDepthFalloff);
            effect.Parameters["weights"].SetValue(kernel);
            effect.Parameters["offsets"].SetValue(offsetsHoriz);
            effect.Parameters["GBufferPixelSize"].SetValue(new Vector2(1f / ImageToProcess.Width, 1f / ImageToProcess.Height));
            effect.Parameters["TempBufferRes"].SetValue(destinySize.Value);
            rHelper.Textures[0] = rHelper[PrincipalConstants.DephRT];
            rHelper.Textures[1] = ImageToProcess;
            SamplerState s0 = rHelper.SetSamplerState(SamplerState.PointClamp, 0);
            SamplerState s1 = rHelper.SetSamplerState(ImageSamplerState, 1);
            rHelper.RenderFullScreenQuadVertexPixel(effect);

            rHelper.PopRenderTarget();

            effect.Parameters["offsets"].SetValue(offsetsVert);
            rHelper.Textures[1] = RenderTarget2D;
            rHelper.RenderFullScreenQuadVertexPixel(effect);

            rHelper.SetSamplerState(s0, 0);
            rHelper.SetSamplerState(s1, 1);

Quite Simple !
The Gaussian Blur with edge preservation is not Separable (we cant perform a Y and a X pass independentely) but for performance we normally dont care about this.

,

  1. #1 by car insurance quotes online compare on 16 de janeiro de 2017 - 7:36 pm

    Can I use a different WordPress theme to a WordPress hosted blog?

  2. #2 by home insurance RATINGs 2015 on 16 de janeiro de 2017 - 8:46 pm

    Hello. remarkable job. I did not expect this. This is a remarkable story. Thanks!

  3. #3 by am best rating insurance companies on 16 de janeiro de 2017 - 8:58 pm

    Have you ever thought about including a little bit more than just your articles? I mean, what you say is fundamental and everything. However imagine if you added some great photos or video clips to give your posts more, “pop”! Your content is excellent but with pics and clips, this site could definitely be one of the very best in its niche. Great blog!

  4. #4 by patagonia outlet sale on 16 de janeiro de 2017 - 9:35 pm

    I must say, as significantly as I enjoyed reading what you had to say, I couldnt help but lose interest after a while. Its as if you had a excellent grasp on the topic matter, but you forgot to include your readers. Perhaps you should think about this from additional than 1 angle. Or maybe you shouldnt generalise so substantially. Its better if you think about what others may have to say instead of just heading for a gut reaction to the topic. Think about adjusting your own thought process and giving others who may read this the benefit of the doubt.
    patagonia outlet sale http://www.unilorites.com/patagonia/

  5. #5 by car insurance quotes online compare on 16 de janeiro de 2017 - 10:22 pm

    Excellent blog made with Blogger and it has Blogger logos at the top.. I’ve noticed Blogger sites without them, and it makes them a lot cool..

  6. #6 by butt plug on 16 de janeiro de 2017 - 10:41 pm

    we prefer to honor numerous other net internet sites on the web, even if they arent linked to us, by linking to them. Beneath are some webpages worth checking out

  7. #7 by arcteryx veilance sale on 17 de janeiro de 2017 - 12:36 am

    When are you going to post again? You really entertain a lot of people!
    arcteryx veilance sale http://www.lticonstruction.com/arcteryx/

  8. #8 by android apps for pc on 17 de janeiro de 2017 - 12:53 am

    Together with everything which seems to be building throughout this particular subject matter, all your opinions are relatively radical. Having said that, I am sorry, because I can not give credence to your whole idea, all be it refreshing none the less. It looks to everybody that your commentary are generally not completely validated and in actuality you are your self not wholly confident of your assertion. In any event I did appreciate reading through it.

  9. #9 by pc version free download on 17 de janeiro de 2017 - 2:35 am

    Very nice layout and fantastic articles, nothing else we want : D.

  10. #10 by balmain jeans women on 17 de janeiro de 2017 - 3:37 am

    excellent info keep up your good work thankx
    balmain jeans women http://balmain.compucelunlock.net

1 142 143 144
(não será publicado)