After having implemented deferred rendering, I tried my luck with a SSAO implementation using this Tutorial. Unfortunately, I'm not getting anything that looks like SSAO, you can see my result below.

failed ssao atempt

You can see there is some weird pattern forming and there is no occlusion shading where there needs to be (i.e. in between the objects and on the ground). The shaders I implemented follow:

#version 330 core

uniform mat4 invProjMatrix;

layout(location = 0) in vec3 in_Position;
layout(location = 2) in vec2 in_TexCoord;

noperspective out vec2 pass_TexCoord;
smooth out vec3 viewRay;

void main(void){
    pass_TexCoord = in_TexCoord;
    viewRay = (invProjMatrix * vec4(in_Position, 1.0)).xyz;
    gl_Position = vec4(in_Position, 1.0);

#version 330 core

uniform sampler2D DepthMap;
uniform sampler2D NormalMap;
uniform sampler2D noise;

uniform vec2 projAB;
uniform ivec3 noiseScale_kernelSize;
uniform vec3 kernel[16];
uniform float RADIUS;
uniform mat4 projectionMatrix;

noperspective in vec2 pass_TexCoord;
smooth in vec3 viewRay;

layout(location = 0) out float out_AO;

vec3 CalcPosition(void){
    float depth = texture(DepthMap, pass_TexCoord).r;
    float linearDepth = projAB.y / (depth - projAB.x);
    vec3 ray = normalize(viewRay);
    ray = ray / ray.z;
    return linearDepth * ray;

mat3 CalcRMatrix(vec3 normal, vec2 texcoord){
    ivec2 noiseScale = noiseScale_kernelSize.xy;
    vec3 rvec = texture(noise, texcoord * noiseScale).xyz;
    vec3 tangent = normalize(rvec - normal * dot(rvec, normal));
    vec3 bitangent = cross(normal, tangent);

    return mat3(tangent, bitangent, normal);

void main(void){

    vec2 TexCoord = pass_TexCoord;
    vec3 Position = CalcPosition();
    vec3 Normal = normalize(texture(NormalMap, TexCoord).xyz);

    mat3 RotationMatrix = CalcRMatrix(Normal, TexCoord);

    int kernelSize = noiseScale_kernelSize.z;

    float occlusion = 0.0;

    for(int i = 0; i < kernelSize; i++){
        // Get sample position
        vec3 sample = RotationMatrix * kernel[i];
        sample = sample * RADIUS + Position;
        // Project and bias sample position to get its texture coordinates
        vec4 offset = projectionMatrix * vec4(sample, 1.0);
        offset.xy /= offset.w;
        offset.xy = offset.xy * 0.5 + 0.5;
        // Get sample depth
        float sample_depth = texture(DepthMap, offset.xy).r;
        float linearDepth = projAB.y / (sample_depth - projAB.x);
        if(abs(Position.z - linearDepth ) < RADIUS){
            occlusion += (linearDepth <= sample.z) ? 1.0 : 0.0;
    out_AO = 1.0 - (occlusion / kernelSize);

I draw a full screen quad and pass Depth and Normal textures. Normals are in RGBA16F with the alpha channel reserved for the AO factor in the blur pass. I store depth in a non linear Depth buffer (32F) and recover the linear depth using:

float linearDepth = projAB.y / (depth - projAB.x);

where projAB.y is calculated as:

enter image description here

and projAB.x as:

enter image description here

These are derived from the glm::perspective(gluperspective) matrix. z_n and z_f are the near and far clip distance.

As described in the link I posted on the top, the method creates samples in a hemisphere with higher distribution close to the center. It then uses random vectors from a texture to rotate the hemisphere randomly around the Z direction and finally orients it along the normal at the given pixel. Since the result is noisy, a blur pass follows the SSAO pass.

Anyway, my position reconstruction doesn't seem to be wrong since I also tried doing the same but with the position passed from a texture instead of being reconstructed.

I also tried playing with the Radius, noise texture size and number of samples and with different kinds of texture formats, with no luck. For some reason when changing the Radius, nothing changes.

Does anyone have any suggestions? What could be going wrong?

  • \$\begingroup\$ I think the blur needs to be a separate pass. Can you post a screenshot of your shader without the blur? \$\endgroup\$
    – knight666
    Jun 19, 2012 at 12:15
  • \$\begingroup\$ The blur pass is separate, you can check the pre-blur screenshot. \$\endgroup\$ Jun 19, 2012 at 12:32

1 Answer 1


I found the problem. It was a really stupid mistake, I didn't know you had to specify glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); to get the correct depth values and thus, I wasn't sampling the Depth values. Now I get a nice SSAO effect:

enter image description here

  • \$\begingroup\$ Feel free to flag this as the correct answer so that people know you've found your solution :P \$\endgroup\$
    – SomeGuy
    Jun 20, 2012 at 4:16
  • \$\begingroup\$ Yes, unfortunately I have to wait one day to be able to flag my answer as correct :S . \$\endgroup\$ Jun 20, 2012 at 5:06
  • \$\begingroup\$ My mistake, didn't check the timestamps. \$\endgroup\$
    – SomeGuy
    Jun 20, 2012 at 21:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .