Jump to content
  • Advertisement
Sign in to follow this  

SSAO Problems

This topic is 2798 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Update: see reply

Hey guys, I've been trying to implement an SSAO technique using Random Normals and Depth Data but I don't seem to get anything close to what it's supposed to look like. Also I think something must be wrong with either the UV's or maybe the normals because the effect (or whatever comes out of the SSAO RenderTarget) alters with the camera angle. Please take a look at the attached images (which show the ssao RT output)

The shader looks like this:
VSO_SSAO VertexShader_SSAO(VSI_SSAO input)
VSO_SSAO output = (VSO_SSAO)0;
//Just Straight Pass Position
output.Position = float4(input.Position, 1);
//Set up UV's
output.UV = input.UV - float2(1.0f / GBufferTextureSize.xy);
//Set up ViewDirection vector
output.ViewDirection = float3(-cornerFrustum.x * input.Position.x, cornerFrustum.y * input.Position.y, cornerFrustum.z);
return output;

float4 PixelShader_SSAO(VSO_SSAO input) : COLOR0
//Sample Vectors
float4 samples[8] =
float4(0.355512, -0.709318, -0.102371, 0.0 ),
float4(0.534186, 0.71511, -0.115167, 0.0 ),
float4(-0.87866, 0.157139, -0.115167, 0.0 ),
float4(0.140679, -0.475516, -0.0639818, 0.0 ),
float4(-0.207641, 0.414286, 0.187755, 0.0 ),
float4(-0.277332, -0.371262, 0.187755, 0.0 ),
float4(0.63864, -0.114214, 0.262857, 0.0 ),
float4(-0.184051, 0.622119, 0.262857, 0.0 )
//Normalize the input ViewDirection
float3 ViewDirection = normalize(input.ViewDirection);
//Sample the depth
float depth = tex2D(DepthBuffer, input.UV);

//Calculate the depth at this pixel along the view direction
float3 se = depth * ViewDirection;
//Sample a random normal vector
float3 randNormal = tex2D(RandomNormalSampler, input.UV * 200.0f).xyz;
// Decode and Sample Normal
half4 NormalData = tex2D(NormalBuffer, input.UV);
half3 normal = mul(decode(NormalData), inverseView);

// Normalize Normals
normal = normalize(normal);

//No assymetry in HLSL, workaround
float finalColor = 0.0f;

//SSAO loop
for (int i = 0; i < NUMSAMPLES; i++)
//Calculate the Reflection Ray
float3 ray = reflect(samples.xyz, randNormal) * sampleRadius;

//Test the Reflection Ray against the surface normal
if(dot(ray, normal) < 0) ray += normal * sampleRadius;

//Calculate the Sample vector
float4 sample = float4(se + ray, 1.0f);

//Project the Sample vector into ScreenSpace
float4 ss = mul(sample, Projection);
//Convert SS into UV space
float2 sampleTexCoord = 0.5f * ss.xy / ss.w + float2(0.5f, 0.5f);

//Sample the Depth along the ray
float sampleDepth = tex2D(DepthBuffer, sampleTexCoord);

//Check the sampled depth value
if (sampleDepth == 1.0)
//Non-Occluded sample
//Calculate Occlusion
float occlusion = distanceScale * max(sampleDepth - depth, 0.0f);

//Accumulate to finalColor
finalColor += 1.0f / (1.0f + occlusion * occlusion * 0.1);
//Output the Average of finalColor
return float4(finalColor / NUMSAMPLES, finalColor / NUMSAMPLES, finalColor / NUMSAMPLES, 1.0f);

Share this post

Link to post
Share on other sites
Update: Ok so using the "right" 4x4 random normal texture made it a lot better. I also got that weird horizontal line fixed by changing this line:

output.UV = input.UV;

to the following:

output.UV = input.UV - (1.0h / GBufferTextureSize); // GBufferTextureSize being a Vector2(ResolutionHeight, ResolutionWidth)

Weirdly I had to switch the order to Vector2(Height, Width) instead of the normal way. But it made the squares finer.

Anyway have a look at the most recent one:

I still need to figure out how to make the picture 100% clear. It seems to work if I multiply the UV's by 2, but then I get some odd artifacts.
Also the SSAO Effect takes away at least 100 fps of my scene O_o
Any suggestions ?

Well I've completely redone everything and been trying to implement the original Technique by Vladimir Kajalin (Crytek), code taken from the Shader X7 Book, which is almost correct. But it seems luck doesn't follow me around : /
Any help would be appreciated.
You can see the output right here: [media]

And the Shader Code there:

// Depth Buffer Input
sampler2D DepthBuffer : register(s0);

// External Stuff
extern texture RandomSamples;
extern float farClip;
extern float2 ScreenSize;
extern float offset;
// Random Normal Sampler Sampler
sampler RandomSampler = sampler_state
texture = <RandomSamples>;

struct VSI_SSAOTarget
float3 Position : POSITION0;
float2 UV : TEXCOORD0;
struct PSI_SSAOTarget
float4 Position : SV_POSITION;
float2 UV : TEXCOORD0;

// Vertex Shader
PSI_SSAOTarget SSAOTarget_VS(VSI_SSAOTarget input)
PSI_SSAOTarget output = (PSI_SSAOTarget)0;
output.Position = float4(input.Position, 1);
output.UV = input.UV;

return output;

float ComputeSSAO(sampler2D sRotSampler4x4, sampler2D sSceneDepthSampler,
float2 screenTC, float2 screenSize, float farClipDist)
float2 rotationTC = screenTC * screenSize / 4;
float3 vRotation = 2 * tex2D(sRotSampler4x4, rotationTC).rgb-1;
float3x3 rotMat;
float h = 1 / (1 + vRotation.z);
rotMat._m00 = h * vRotation.y * vRotation.y + vRotation.z;
rotMat._m01 = -h * vRotation.y * vRotation.x;
rotMat._m02 = -vRotation.x;
rotMat._m10 = -h * vRotation.y * vRotation.x;
rotMat._m11 = h * vRotation.x * vRotation.x + vRotation.z;
rotMat._m12 = -vRotation.y; rotMat._m20 = vRotation.x;
rotMat._m21 = vRotation.y; rotMat._m22 = vRotation.z;
float fSceneDepthP = tex2D( sSceneDepthSampler, screenTC ) * farClipDist;
const int nSamplesNum = 24;
float offsetScale = offset;
const float offsetScaleStep = 1 + 2.4 / nSamplesNum;
float Accessibility = 0;

for(int i = 0; i < (nSamplesNum / 8); i++)
for(int x = -1; x <= 1; x += 2)
for(int y = -1; y <= 1; y += 2)
for(int z = -1; z <= 1; z += 2)
float3 vOffset = normalize(float3( x, y, z )) * ( offsetScale *= offsetScaleStep );
float3 vRotatedOffset = mul( vOffset, rotMat );
float3 vSamplePos = float3( screenTC, fSceneDepthP );
vSamplePos += float3( vRotatedOffset.xy,
vRotatedOffset.z * fSceneDepthP * 2);
float fSceneDepthS = tex2D( sSceneDepthSampler, vSamplePos.xy ) * farClipDist;
float fRangeIsInvalid = saturate( ( ( fSceneDepthP - fSceneDepthS ) / fSceneDepthS ) );
Accessibility += lerp( fSceneDepthS > vSamplePos.z, 0.5, fRangeIsInvalid );
Accessibility = Accessibility / nSamplesNum;
return saturate( Accessibility * Accessibility + Accessibility );
// Pixel Shader
float4 SSAOTarget_PS(PSI_SSAOTarget input) : COLOR0
float4 output = ComputeSSAO(RandomSampler, DepthBuffer, input.UV, ScreenSize, farClip);
return output;

technique Default
pass Target
VertexShader = compile vs_3_0 SSAOTarget_VS();
PixelShader = compile ps_3_0 SSAOTarget_PS();

Share this post

Link to post
Share on other sites
When i did my SSAO (not the best one, or the most complex one).

i did get the random pixel around the main pixel, compared the depth, if the depth was around the same, it dident get so much "grey",
but if the depth differd a big deal, then it was more "greyd", and i had a range check so i dident get a "grey" aoura around the object.

for randomizing, i had and 16x16 noise texture. and a kernelvalue, this actualy dont make a "REAL" random value, but it´s probably better that you could do with
HLSL code.

unfortunately i dont have the code around. but im sure you will figure it out!


the last one looks kinda good.

Share this post

Link to post
Share on other sites
When I multiply the UV's for the random texture sampler the raster seems to be perfect (meaning I can completely remove the raster by using the 4x4 Blur) but instead I'm getting weird ghosting artifacts. Not sure how to fix this...

half2 rotationTC = screenTC * screenSize.xy / 4; // If I multiply this by 2 the raster is perfect but artifacts appear.
half3 vRotation = 2 * tex2D(sRotSampler4x4, rotationTC).rgb - 1;

Share this post

Link to post
Share on other sites
You probaly need to clamp the texture. (if your not allredy did that.

what is screenTC?
and remeber that 1 in hlsl is equal to the end of the texutre. so you have to do.
(pixelOffset / screensize.x) / 4. orterwise you will get a value bigger than 1 and thats bad.

uv space ranges from 0->1 in both U and V.

Share this post

Link to post
Share on other sites
You mean clamping the random normal texture ? If I do that the raster disappears but I get ghost images of every sample taken.
screenTC is the TextureCoord coming from the VertexShader:

output.UV = input.UV - (1.0h / GBufferTextureSize);

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!