Skip to main content
GameDev.net gamedev.net
🔒 Locked

Gaussian Blur HLSL problem

Started by ThijsMorlion Apr 7, 2011 at 10:08 AM 0 replies 2.9k views
Original Post
ThijsMorlion
ThijsMorlion
Hi,

I've been trying to implement a Gaussian Blur shader in HLSL to use in DirectX 10.
I don't seem to get correct results, or not completely correct.

Can anyone check if I'm doing things correctly?
I think that I miss something, but I don't know what ^^

This is what I do now:

// -------------------------------------------------------------
// Texture & Sampler
// -------------------------------------------------------------
texture texTexture : TEXTURE0;
sampler sampTexture = sampler_state {
Texture = (texTexture);
AddressU = Wrap;
AddressV = Wrap;
};

// -------------------------------------------------------------
// Parameters
// -------------------------------------------------------------
float centerTapWeight;
const float2 texelSize;
const float tapOffSets[4] = {1, 2, 3, 4};
const float PI = 3.14159265f;
const float e = 2.71828182f;
float4 tapWeights;
const float standardDeviation = 2.0f;

// -------------------------------------------------------------
// Input/Output channels
// -------------------------------------------------------------
struct VS_INPUT
{
float4 position : POSITION;
float2 texCoord : TEXCOORD0;
};

struct VS_OUTPUT
{
float4 position : POSITION;
float2 centerTap : TEXCOORD0;
float4 positiveTaps[2] : TEXCOORD1;
float4 negativeTaps[2] : TEXCOORD3;
};

#define PS_INPUT VS_OUTPUT

// -------------------------------------------------------------
// Vertex Shader
// -------------------------------------------------------------
VS_OUTPUT VS(const VS_INPUT IN, uniform float2 DIRECTION)
{
VS_OUTPUT OUT;
OUT.position = IN.position;
OUT.centerTap = IN.texCoord;

for(int i = 0; i < 2; ++i)
{
//OUT.taps = IN.texCoord + tapOffSets * DIRECTION * texelSize;
OUT.positiveTaps.xy = IN.texCoord + tapOffSets[i*2] * DIRECTION * texelSize;
OUT.negativeTaps.xy = IN.texCoord - tapOffSets[i*2] * DIRECTION * texelSize;
OUT.positiveTaps.zw = IN.texCoord + tapOffSets[i*2+1] * DIRECTION * texelSize;
OUT.negativeTaps.zw = IN.texCoord - tapOffSets[i*2+1] * DIRECTION * texelSize;
}

return OUT;
}

// -------------------------------------------------------------
// Pixel Shader function
// -------------------------------------------------------------
float4 PS(PS_INPUT IN) : COLOR
{
float firstPart = 1/sqrt(2*PI*standardDeviation);
float power = (-(pow(0, 2)))/(2*pow(standardDeviation, 2));
float secondPart = pow(e, power);

centerTapWeight = firstPart*secondPart;

//float4x4 samples;
float4x4 positiveSamples;
float4x4 negativeSamples;

float4 color = tex2D(sampTexture, IN.centerTap) * centerTapWeight;

for(int i = 0; i < 2; ++i)
{
//samples = tex2D(sampTexture, IN.taps);
positiveSamples[i*2] = tex2D(sampTexture, IN.positiveTaps.xy);
negativeSamples[i*2] = tex2D(sampTexture, IN.negativeTaps.xy);
positiveSamples[i*2+1] = tex2D(sampTexture, IN.positiveTaps.zw);
negativeSamples[i*2+1] = tex2D(sampTexture, IN.negativeTaps.zw);

float firstPart = 1/sqrt(2*PI*standardDeviation);
float power = (-(pow(IN.positiveTaps.xy, 2)))/(2*pow(standardDeviation, 2));
float secondPart = pow(e, power);
tapWeights[i*2] = firstPart*secondPart;

firstPart = 1/sqrt(2*PI*standardDeviation);
power = (-(pow(IN.positiveTaps.zw, 2)))/(2*pow(standardDeviation, 2));
secondPart = pow(e, power);
tapWeights[i*2+1] = firstPart*secondPart;
}

color += mul(tapWeights, positiveSamples) + mul(tapWeights, negativeSamples);

return color;
}

// -------------------------------------------------------------
// Techniques
// -------------------------------------------------------------
technique10 GaussianBlur
{
pass HBlur
{
VertexShader = compile vs_4_0 VS(float2(1, 0));
PixelShader = compile ps_4_0 PS();
}
pass VBlur
{
VertexShader = compile vs_4_0 VS(float2(0, 1));
PixelShader = compile ps_4_0 PS();
}
}

Hunter-Killer
Hunter-Killer
I do my calculations in code rather than the shader. RenderCapture is just a simple wrapper for setting up render targets and ResultCapture is there so I can piggy back off this effect for depth of field.

App:
public class GaussianBlur : PostProcessor
{
public RenderCapture ResultCapture = null;

RenderCapture renderCapture;

float blurAmount;
float[] weightsH, weightsV;
Vector2[] offsetsH, offsetsV;

public GaussianBlur(GraphicsDevice gd, ContentManager c, float amount)
: base(gd, c)
{
blurAmount = amount;

// Calculate weights/offsets for horizontal pass
calcSettings(1.0f / (float)device.Viewport.Width, 0, out weightsH, out offsetsH);

// Calculate weights/offsets for vertical pass
calcSettings(0, 1.0f / (float)device.Viewport.Height, out weightsV, out offsetsV);

renderCapture = new RenderCapture(device);
}

void calcSettings(float w, float h, out float[] weights, out Vector2[] offsets)
{
weights = new float[15];
offsets = new Vector2[15];

weights[0] = gaussianFn(0);
offsets[0] = new Vector2(0, 0);

float total = weights[0];

for (int i = 0; i < 7; i++)
{
float weight = gaussianFn(i + 1);
weights[i * 2 + 1] = weight;
weights[i * 2 + 2] = weight;
total += weight * 2;

float offset = i * 2 + 1.5f;
Vector2 offsetVec = new Vector2(w, h) * offset;
offsets[i * 2 + 1] = offsetVec;
offsets[i * 2 + 2] = -offsetVec;
}

for (int i = 0; i < weights.Length; i++)
{
weights /= total;
}
}

float gaussianFn(float x)
{
float blur2 = 2 * blurAmount * blurAmount;
float invSq = 1.0f / (float)Math.Sqrt(Math.PI * blur2);
float exp = (float)Math.Exp(-(x * x) / blur2);
return invSq * exp;
}

public override void Draw()
{
// Horizontal pass
Effect.Parameters["xOffsets"].SetValue(offsetsH);
Effect.Parameters["xWeights"].SetValue(weightsH);

renderCapture.Begin();
base.Draw(PostProcessorTechnique.GaussianBlur);
renderCapture.End();

Input = renderCapture.GetTexture();

if (ResultCapture != null)
ResultCapture.Begin();

// vertical pass
Effect.Parameters["xOffsets"].SetValue(offsetsV);
Effect.Parameters["xWeights"].SetValue(weightsV);

base.Draw(PostProcessorTechnique.GaussianBlur);

if (ResultCapture != null)
ResultCapture.End();
}
}


Shader:
float4 GaussianBlurPS(float4 Position : POSITION0, float2 UV : TEXCOORD0) : COLOR0
{
float4 output = float4(0, 0, 0, 1);

for (int i = 0; i < 15; i++)
output += tex2D(tex[0], UV + xOffsets) * xWeights;

return output;
}

technique GaussianBlur
{
pass Pass1
{
PixelShader = compile ps_2_0 GaussianBlurPS();
}
}

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.