So I implemented a 9-tap (5-tap linear sampled) seperable gaussian blur which you can see here:
float4 PS(VSO input) : SV_TARGET0
{
const float offset[3] = { 0.0, 1.3846153846, 3.2307692308 };
const float weight[3] = { 0.2270270270, 0.3162162162, 0.0702702703 };
const float pixelSize = float2(1.0f / _ScreenSize.x, 1.0f / _ScreenSize.y);
float3 texColor = TargetTexture.Sample(TargetTextureSampler, input.UV * pixelSize).xyz * weight[0];
for (int i = 1; i < 3; i++)
{
texColor += TargetTexture.Sample(TargetTextureSampler, input.UV + float2(0.0f, offset * pixelSize)).xyz * weight;
texColor += TargetTexture.Sample(TargetTextureSampler, input.UV - float2(0.0f, offset * pixelSize)).xyz * weight;
}
return float4(texColor.rgb, 1.0f);
}
I'm just not sure if the result is correct since its quite a lot darker than the original image:
original :
http://cl.ly/image/093q0Z2c0m1a
blurred:
http://cl.ly/image/3E0P2d3t0U1g
I'm trying to achieve a bloom effect so in this sense making the result darker is quite the opposite of what I want...
Am I doing something wrong ?
Cancel
Save
[s]I think you weights are off.
Shouldn't they add up to 1 ?[/s]
Nevermind, didn't really read through the algo first
Cancel
Save
float3 texColor = TargetTexture.Sample(TargetTextureSampler, input.UV * pixelSize).xyz * weight[0];
Doesn't that always sample the top left corner (i.e Black) ?
I think it should be:
float3 texColor = TargetTexture.Sample(TargetTextureSampler, input.UV).xyz * weight[0];
Not?
Cancel
Save
Your first weight seems to be about half the weight it should be.
Also [eqn]w_0 + 2\sum_{i=1}^{\infty}w_i=1[/eqn]
I recommend not using a hardcoded array like this. Use a function that evaluates the gaussian filter for you instead.
float gaussianKernel(float x, float standardDeviation)
{
return exp(-(x * x) / (2 * standardDeviation * standardDeviation)) / (sqrt(2 * 3.14159265) * standardDeviation);
}
The compiler will compile this into constant weights, but it's easier for you to manage your code or compile this shader for multiple standard deviations.
Also, shouldn't your pixel size be a float2?
const float pixelSize = float2(1.0f / _ScreenSize.x, 1.0f / _ScreenSize.y);
And yes, Madhed is right too.
Cancel
Save
Well I was implementing it based on this implementation here:
http://rastergrid.co...inear-sampling/
or this one seems to do the same:
http://www.geeks3d.c...filter-in-glsl/
update:
You were right the initial texcolor was wrong.
This code now seems to give me a correct image:
float4 PS(VSO input) : SV_TARGET0
{
const float offset[3] = { 0.0, 1.3846153846, 3.2307692308 };
const float weight[3] = { 0.2270270270, 0.3162162162, 0.0702702703 };;
float3 texColor = TargetTexture.Sample(TargetTextureSampler, input.UV).xyz * weight[0];
for (int i = 1; i < 3; i++)
{
texColor += TargetTexture.Sample(TargetTextureSampler, input.UV + float2(offset, 0.0f) / _ScreenSize.x).rgb * weight;
texColor += TargetTexture.Sample(TargetTextureSampler, input.UV - float2(offset, 0.0f) / _ScreenSize.x).rgb * weight;
}
//return TargetTexture.Sample(TargetTextureSampler, input.UV);
return float4(texColor.rgb, 1.0f);
}
@CryZe what are those inputs 'x' and 'standardDeviation' ?
x = i in my case ?
Cancel
Save
Yes, x is your i and standardDeviation correlates to the width of the filter (it should be about a third of the maximum i). Your weights still seem off though. I fixed them:
const float weight[3] = { 0.40261952, 0.2442015368, 0.0544886997 };
Cancel
Save
With that in mind would this case be correct ?
float gaussianKernel(float x, float standardDeviation)
{
return exp(-(x * x) / (2 * standardDeviation * standardDeviation)) / (sqrt(2 * 3.14159265) * standardDeviation);
}
float4 PS(VSO input) : SV_TARGET0
{
const float offset[3] = { 0.0, 1.3846153846, 3.2307692308 };
const float weight[3] = { 0.45405405404, 0.3162162162, 0.0702702703 };;
float3 texColor = TargetTexture.Sample(TargetTextureSampler, input.UV).xyz * weight[0];
for (int i = 1; i < 3; i++)
{
float weight = gaussianKernel(i, 3 / 3); // (2 / 3) also gives different results
texColor += TargetTexture.Sample(TargetTextureSampler, input.UV + float2(offset, 0.0f) / _ScreenSize.x).rgb * weight;
texColor += TargetTexture.Sample(TargetTextureSampler, input.UV - float2(offset, 0.0f) / _ScreenSize.x).rgb * weight;
}
return float4(texColor.rgb, 1.0f);
}
Solving the equation with those numbers gives me different ones than my predefined ones.
Cancel
Save
float gaussianKernel(float x, float standardDeviation)
{
return exp(-(x * x) / (2 * standardDeviation * standardDeviation)) / (sqrt(2 * 3.14159265) * standardDeviation);
}
float4 PS(VSO input) : SV_TARGET0
{
const int numSamples = 3;
const float standardDeviation = numSamples / 3.0;
const float offset[numSamples] = { 0.0, 1.3846153846, 3.2307692308 };
const float weight[numSamples] = { 0.40261952, 0.2442015368, 0.0544886997 }; //Either use these or the gaussianKernel function
float3 texColor = TargetTexture.Sample(TargetTextureSampler, input.UV).xyz * gaussianKernel(0, standardDeviation); //You forgot about this weight here
for (int i = 1; i < numSamples; i++)
{
float weight = gaussianKernel(i, standardDeviation);
texColor += TargetTexture.Sample(TargetTextureSampler, input.UV + float2(offset, 0.0f) / _ScreenSize.x).rgb * weight;
texColor += TargetTexture.Sample(TargetTextureSampler, input.UV - float2(offset, 0.0f) / _ScreenSize.x).rgb * weight;
}
return float4(texColor.rgb, 1.0f);
}
You might also want to check out the implementation I'm currently using in my engine (even though I'm currently switching to a more optimized compute shader implemention with a runtime of O(log n) per pixel):
#ifndef MIN_WEIGHT
#define MIN_WEIGHT 0.0001f
#endif
#ifndef FILTER
#error You have to define the filter. (FILTER = (GAUSSIAN|EXPONENTIAL))
#endif
#define GAUSSIAN 0
#define EXPONENTIAL 1
#if FILTER == GAUSSIAN
#ifndef STANDARD_DEVIATION
#error You have to define the standard deviation when using a gaussian kernel. (STANDARD_DEVIATION = float)
#endif
#elif FILTER == EXPONENTIAL
#ifndef MEAN_VALUE
#error You have to define the mean value when using an exponential kernel. (MEAN_VALUE = float)
#endif
#endif
#ifndef DIRECTION
#error You have to define the direction. (DIRECTION = (HORIZONTAL|VERTICAL|int2(x,y)))
#endif
#ifndef MIP
#define MIP 0
#endif
#define HORIZONTAL int2(1, 0)
#define VERTICAL int2(0, 1)
Texture2D SourceTexture : register(t0);
cbuffer InfoBuffer : register(b0)
{
float Width;
float Height;
};
struct PSIn
{
float4 Position : SV_POSITION;
float2 TexCoord : TEXCOORD0;
float2 ScreenPos : SCREEN_POSITION;
};
float gaussianKernel(int x, float standardDeviation)
{
return exp(-(x * x) / (2 * standardDeviation * standardDeviation)) / (sqrt(2 * 3.14159265) * standardDeviation);
}
float integratedExponentialKernel(float x, float m)
{
return 0.5 * (1 - exp(-x / m) / 2) * (sign(x) + 1) - 0.25 * exp(x / m) * (sign(x) - 1);
}
float exponentialKernel(int x, float m)
{
return integratedExponentialKernel(x + 0.5, m) - integratedExponentialKernel(x - 0.5, m);
}
float filter(int x)
{
#if FILTER == GAUSSIAN
return gaussianKernel(x, STANDARD_DEVIATION);
#elif FILTER == EXPONENTIAL
return exponentialKernel(x, MEAN_VALUE);
#endif
}
float3 sample(int2 position, int offset)
{
float3 textureColor = 0.0f;
float2 newOffset = offset * DIRECTION;
if (newOffset.x >= -8 && newOffset.x <= 7 && newOffset.y >= -8 && newOffset.y <= 7)
textureColor = SourceTexture.Load(
int3(position, MIP),
newOffset);
else
textureColor = SourceTexture.Load(int3(position + newOffset, MIP));
return textureColor;
}
float4 PSMain(PSIn Input) : SV_Target
{
float3 accumulatedColor = 0.0f;
float accumulatedWeight = 0, weight = 0;
[unroll]
for (int x = 0; (weight = filter(x)) > MIN_WEIGHT; ++x)
{
accumulatedWeight += (x != 0) ? (2 * weight) : weight;
}
[unroll]
for (int x = 0; (weight = filter(x)) > MIN_WEIGHT; ++x)
{
accumulatedColor += weight / accumulatedWeight * sample((int2)Input.ScreenPos, x);
if (x != 0)
accumulatedColor += weight / accumulatedWeight * sample((int2)Input.ScreenPos, -x);
}
return float4(accumulatedColor, 1);
}
Cancel
Save
@cryze
OP's initial weights were alright. I stumbled across this also the first time I had a look at the code. He is doing 2 samples per loop iteration, so the weights add up to 1 as they should be.
Cancel
Save
He was / is not doing it for the sample with the index 0. Both samples with index 1 had higher weights, which would not have resulted in a proper gaussian blur.
Cancel
Save