Jump to content
  • Advertisement
Sign in to follow this  

Problems setting up SSAO

This topic is 2937 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

First off, I've already read the articles on gamedev and a few other places about SSAO.

After trying their shaders (which either gave me noise or strange results), I tried to write my own:

#extension GL_ARB_texture_multisample : enable

uniform sampler2DMS normalMap;
uniform sampler2DMS depthMap;

uniform vec2 screenResolution;

smooth in vec2 texCoord;

out vec4 vFragColor0;

vec4 getTexelI (sampler2DMS tex, int samples, ivec2 coord)
vec4 res;
for (int i = 0; i < samples; ++i)
res += texelFetch(
return res * (1.0 / float(samples));

const float rayLength = 0.0000001;

const int numSamples = 4;

const vec3 s_directions[numSamples] = vec3[] (
normalize(vec3(-1, 0, -1)),
normalize(vec3(1, 0, -1)),
normalize(vec3(0, -1, -1)),
normalize(vec3(0, 1, -1))

vec3 adjustNormal (vec3 inNormal, vec3 bumpNormal)
mat3 mat;
vec3 left = bumpNormal;
left.xy = left.yx;
left.x = -left.x;
vec3 up = cross(bumpNormal, left);
left = cross(bumpNormal, up);
mat[0] = left;
mat[1] = bumpNormal;
mat[2] = up;

return mat * inNormal;

void main ()
// Get the pixel coordinate as a texel coordinate
ivec2 texelCoord = ivec2(
int(texCoord.x * screenResolution.x),
int(texCoord.y * screenResolution.y)

// Get screen-normal and depth
vec3 centerNormal = getTexelI(normalMap, 4, texelCoord).rgb;
float centerDepth = getTexelI(depthMap, 4, texelCoord).g;

// Flip the distance from 1-0 to 0-1
float distanceAdjusted = -(centerDepth - 1.0);

// Decide how long the ray should be, given depth.
vec2 distanceResAdjusted = vec2(
distanceAdjusted * screenResolution.x,
distanceAdjusted * screenResolution.y

float occlusion = 0.0;
float samples = float(numSamples);

for (int i = 0; i < numSamples; ++i)

// Get the sample direction.
vec3 sampleDirection = s_directions;

// Rotate the sample direction to be in the same rotation space as the screen normal.
// I believe that this is where it is broken.
sampleDirection = adjustNormal(centerNormal, sampleDirection);

// Adjust the length of the Z coordinate, as the range is only 0 - 1.
sampleDirection.z *= distanceAdjusted * rayLength;

// Get the length of the offset in texel coordinates
vec2 iSampleDirection = vec2(
distanceResAdjusted.x * sampleDirection.x,
distanceResAdjusted.y * sampleDirection.y

// Get the new offset to look up.
vec2 texOffset = texelCoord + iSampleDirection;

// Clamp the offset to be within the screen.
// This causes some artifacts at the screen edges.
texOffset.x = clamp(texOffset.x, 0, screenResolution.x);
texOffset.y = clamp(texOffset.y, 0, screenResolution.y);

// Get the height of the offset texel
float sampleHeight = getTexelI(depthMap, 4, ivec2(texOffset)).g;

// Compare them. If sampleHeight is less than compareHeight, add 1.0 to the occlusion value.
float compareHeight = centerDepth - sampleDirection.z;

occlusion += ceil(clamp(-(sampleHeight - compareHeight), 0.0, 1.0));

vFragColor0.rgb = vec3(0.0);
vFragColor0.a = occlusion / samples;

There are some obvious problems with it, but I have not been able to find it.

The inputs are:
normalMap - a multisampled framebuffer, consisting of screen-space normals. X and Y are X and Y, Z is depth (with positive meaning towards the camera).
depthMap - a multisampled framebuffer, consisting of Z-depth.
screenResolution - the resolution of the framebuffers, as a float (IE, 1024x768)
texCoord - the texture coordinate based upon the drawn quad

The only output that is needed is the alpha channel of the fragment - it controls how dark to draw the shading. RGB is ignored.

The effect I am seeing is this:

This is obviously incorrect. Past that, the shading moves heavily with the camera. Under my understanding of the algorithm, the shading should be relatively static as it is relative to geometry depth (and hence positioning), which means that that should -not- happen -- it looks more like broken shadowing than anything. I am assuming that my call to 'adjustNormal' is written incorrectly, but my brain is simply not in a state to debug that.

Can anyone assist me or offer some suggestions as to what to do? Thank you!

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!