Hey guys, it’s me - again …
I’ve some issues porting the SSAO implementation from XNA to mono. As you will see in the screenshot below, a weird banding does occur. Also there are some strange lines inside the image which will flicker as the camera moves.
The random normals for the SSAO effect are taken from a funk-tastic random normal texture - so there should be no banding?
Any suggestions about that? It might be the testing scene I am using, but I can not remember having such issues in the old implementation …
The FAR plane is set to 1000.0f.
My depth map is set to “Single”. SSAO params are::
bias = 0.5f;
intensity = 1.5f;
sampleRadius = 0.5f;
scale = 1.5f;
SSAO-HLSL::
float4x4 param_inverseViewProjectionMatrix;
float4x4 param_inverseViewMatrix;
float3 param_frustumCornersVS[4];
float param_randomSize;
float param_sampleRadius;
float param_intensity;
float param_scale;
float param_bias;
float2 param_screenSize;
texture param_normalMap;
texture param_depthMap;
texture param_randomMap;
sampler normalSampler = sampler_state
{
Texture = (param_normalMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = POINT;
MinFilter = POINT;
Mipfilter = NONE;
};
sampler depthSampler = sampler_state
{
Texture = (param_depthMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = POINT;
MinFilter = POINT;
MipFilter = NONE;
};
sampler randomSampler = sampler_state
{
Texture = (param_randomMap);
AddressU = WRAP;
AddressV = WRAP;
MagFilter = POINT;
MinFilter = POINT;
MipFilter = NONE;
};
// Define VS input
struct VSIn
{
float3 Position : POSITION0;
float3 TexCoord : TEXCOORD0;
};
// Define VS output and therefor PS input
struct VSOut
{
float4 Position : POSITION0;
float2 TexCoord: TEXCOORD0;
float3 FrustumCornerVS : TEXCOORD1;
};
// Define PS output
struct PSOut
{
float4 Color : COLOR0;
};
// Reconstruct view-space position from the depth buffer
float3 getPosition(in float2 vTexCoord, in float3 in_vFrustumCornerVS)
{
float fPixelDepth = tex2D(depthSampler, vTexCoord).r;
return float3(fPixelDepth * in_vFrustumCornerVS);
}
// Calculate the occlusion term
float doAmbientOcclusion(in float2 tcoord, in float3 p, in float3 cnorm, in float3 in_vFrustumCornerVS)
{
float3 diff = getPosition(tcoord, in_vFrustumCornerVS) - p;
float3 v = normalize(diff);
float d = length(diff) * param_scale;
return max(0.0, dot(cnorm, v) - param_bias) * (1.0 / (1.0 + d)) * param_intensity;
}
/**************************************************
Vertex shader.
**************************************************/
VSOut MainVS(VSIn input)
{
VSOut output;
output.Position = float4(input.Position, 1);
output.TexCoord = input.TexCoord.xy;
output.FrustumCornerVS = param_frustumCornersVS[input.TexCoord.z];
return output;
}
/**************************************************
Pixel shader.
**************************************************/
PSOut MainPS(VSOut input)
{
PSOut output;
const float2 vec[4] = {
float2(1,0),
float2(-1,0),
float2(0,1),
float2(0,-1)
};
float3 p = getPosition(input.TexCoord, input.FrustumCornerVS);
float3 n = normalize(tex2D(normalSampler, input.TexCoord).xyz * 2.0f - 1.0f);
float2 rand = normalize(tex2D(randomSampler, param_screenSize * input.TexCoord / param_randomSize).xy * 2.0f - 1.0f);
float ao = 0.0f;
float rad = param_sampleRadius / p.z;
int numIterations = 4;
for (int j = 0; j < numIterations; ++j) {
float2 coord1 = reflect(vec[j], rand) * rad;
float2 coord2 = float2(coord1.x - coord1.y, coord1.x + coord1.y) * 0.707f;
ao += doAmbientOcclusion(input.TexCoord + coord1 * 0.25, p, n, input.FrustumCornerVS);
ao += doAmbientOcclusion(input.TexCoord + coord2 * 0.50, p, n, input.FrustumCornerVS);
ao += doAmbientOcclusion(input.TexCoord + coord1 * 0.75, p, n, input.FrustumCornerVS);
ao += doAmbientOcclusion(input.TexCoord + coord2 * 1.00, p, n, input.FrustumCornerVS);
}
ao /= (float)numIterations * 4.0;
ao = saturate(ao * param_intensity);
output.Color = 1 - ao;
return output;
}
technique Default
{
pass SSAO
{
VertexShader = compile vs_4_0 MainVS();
PixelShader = compile ps_4_0 MainPS();
}
}
BTW. The ambient light is cranked up to a ridiculous value for this image