openglrenderingdeferred-renderingssao

SSAO incorrect at z = 0 and at distance


So I tried to implement SSAO, but it is not working as intended. It seems to split at Position z=0 (worldspace), there is a white Line at position z=0. Also the Occlusion there doesn't look right.

enter image description here

Plus at greater distance, so when moving the camera, the occlusion becomes even weirder enter image description here

My Shader to render the geometry (instanciated):

Vertex:

#version 330 core

 layout(location = 0) in vec3 vertexPosition;
 layout(location = 1) in vec2 vertexUV;
 layout(location = 2) in vec3 vertexColor;
 layout(location = 3) in vec3 vertexNormal;
 layout(location = 4) in mat4 offset;
 layout(location = 8) in vec4 instanceColor;

uniform mat4 Projection;
uniform mat4 View;

out vec2 UV;
out vec4 Color;
out vec3 Normal;

void main()
{

        mat4 Model = offset;
    mat4 MVP = Projection * View * Model;



vec4 Pos = MVP * vec4(endpos,1);

gl_Position = Pos;

UV = vertexUV;

Color = instanceColor;
    Normal = normalize((Model * vec4(vertexNormal,0)).xyz);

}

Fragment:

    #version 330 core

    in vec2 UV;
    in vec4 Color;
    in vec3 Normal;

    uniform sampler2D Diffuse;

void main()
{
    gl_FragData[0] = vec4(Color);
    gl_FragData[1] = (vec4(Normal,1)+1)/2;
}

After the Geometry pass, I apply the SSAO pass with the Normal and Depth Information.

This is my NoiseTexture: enter image description here

I use the hardware Depth Buffer. I calculate everything in world space.

Here is the Fragment Shader:

    #version 330 core

#define KERNEL_SIZE 16
uniform sampler2D NormalMap;
uniform sampler2D DepthMap;
uniform sampler2D NoiseTexture;
uniform vec2 NoiseScale;

uniform vec2 Resolution;

uniform mat4 InvertViewProjection;

uniform float g_sample_rad = 0.1;
uniform float g_intensity = 2.0;
uniform float g_scale = 0.1;
uniform float g_bias = 0.0;

vec2 CalcTexCoord()
{
    return gl_FragCoord.xy / Resolution;
}

vec3 getPosition(vec2 uv)
{
    vec4 worldpos;

    float depth = texture2D(DepthMap, uv).r;

    worldpos.x = uv.x * 2.0f - 1.0f;

    worldpos.y = uv.y * 2.0f - 1.0f;

    worldpos.z = depth * 2.0f - 1.0f;

    worldpos.w = 1.0;

    worldpos = InvertViewProjection * worldpos;

    worldpos /= worldpos.w;

    return worldpos.rgb;
}

vec3 getNormal(vec2 uv)
{
    return normalize(texture2D(NormalMap, uv).xyz * 2.0f - 1.0f);
}

vec2 getRandom(vec2 uv)
{
    return normalize(texture2D(NoiseTexture, Resolution*uv / NoiseScale).xy * 2.0f - 1.0f);
}

float doAmbientOcclusion(in vec2 tcoord, in vec2 uv, in vec3 p, in vec3 cnorm)
{
    vec3 diff = getPosition(tcoord + uv) - p;
    vec3 v = normalize(diff);
    float d = length(diff)*g_scale;

    return max(0.0, dot(cnorm, v) - g_bias)*(1.0 / (1.0 + d))*g_intensity;
}



void main()
{

    vec4 Kernels[KERNEL_SIZE] =
    vec4[](
        vec4(0.355512,  -0.709318,  -0.102371,  0.0 ),
        vec4(0.534186,  0.71511,    -0.115167,  0.0 ),
        vec4(-0.87866,  0.157139,   -0.115167,  0.0 ),
        vec4(0.140679,  -0.475516,  -0.0639818, 0.0 ),
        vec4(-0.0796121,    0.158842,   -0.677075,  0.0 ),
        vec4(-0.0759516,    -0.101676,  -0.483625,  0.0 ),
        vec4(0.12493,   -0.0223423, -0.483625,  0.0 ),
        vec4(-0.0720074,    0.243395,   -0.967251,  0.0 ),
        vec4(-0.207641,     0.414286,   0.187755,   0.0 ),
        vec4(-0.277332,     -0.371262,  0.187755,   0.0 ),
        vec4(0.63864,   -0.114214,  0.262857,   0.0 ),
        vec4(-0.184051,     0.622119,   0.262857,   0.0 ),
        vec4(0.110007,  -0.219486,  0.435574,   0.0 ),
        vec4(0.235085,  0.314707,   0.696918,   0.0 ),
        vec4(-0.290012,     0.0518654,  0.522688,   0.0 ),
        vec4(0.0975089,     -0.329594,  0.609803,   0.0 )

    );
    vec2 uv = CalcTexCoord(); //same as UV Coordinate from Vertex
    vec3 p = getPosition(uv);
    vec3 n = getNormal(uv);
    vec2 rand = getRandom(uv);

    float ao = 0.0f;
    float rad = g_sample_rad / p.z;

    for (int j = 0; j < KERNEL_SIZE; ++j)
    {
        vec2 coord = reflect(Kernels[j].xy, rand)*rad;
        ao += doAmbientOcclusion(uv, coord, p, n);
    }
    ao /= KERNEL_SIZE;

    ao = 1 - (ao);
    gl_FragColor = vec4(ao,ao,ao, 1);
}

Solution

  • I figured it out by debugging the code step by step.

    I calculate everything in world space. It's easier to handle everything there. I looked at a tutorial which uses view space and changed everything I needed to world space.

    The error is here:

     float rad = g_sample_rad / p.z;
    

    this calculates the sampling radius based on the distance. In view space, this calculates the sampling radius for the distance from the camera. But in world space, this calculates for the distance from the world coordinate, which resulted in it looking weird at z=0 and even weirder at farther away.

    so what I did to fix that is simple this:

    vec4 viewpos = CamView * vec4(p,1);
    float ao = 0.0f;
    float rad = g_sample_rad/viewpos.z;
    

    I changed the point to view space and calculated the sampling radius in view space, thus taking in account the distance from the camera.

    This fixes it.

    enter image description here

    I played a little bit with the g_values to fit them for my needs. See how it looks everywhere the same. That's what it should look like.