2

I followed this tutorial for Screen-Space Ambient Occlusion (SSAO), but it seems like something is not working as it should.

enter image description here

As you can see from the screenshot, there is some pattern in the darker areas where ambient occlusion is most evident.

I suspect there's something wrong with the sample kernel, but I followed the tutorial rigidly. The only difference is that I also consider resizing the window and the movement of the camera.

These are the relevant code snippets.

SSAO vertex shader

#version 450 core

out VertData
{
    smooth vec2 texcoord;
} vert;

void main()
{
    switch (gl_VertexID)
    {
    case 0:
        vert.texcoord = vec2(0.0f, 0.0f);
        break;
    case 1:
        vert.texcoord = vec2(0.0f, 1.0f);
        break;
    case 2:
        vert.texcoord = vec2(1.0f, 0.0f);
        break;
    case 3:
        vert.texcoord = vec2(1.0f, 1.0f);
        break;
    }

    vec2 position = vert.texcoord * 2.0f - 1.0f;
    gl_Position = vec4(position, 0.0f, 1.0f);
}

SSAO fragment shader

#version 450 core

struct FragData {
    vec3 position;
    vec3 normal;
    vec3 noise;
};

uniform sampler2D position;
uniform sampler2D normal;
uniform sampler2D KernelTexture;
uniform sampler2D noise;

in VertData
{
    smooth vec2 texcoord;
} vert;

out float occlusion;

uniform int KernelSize;
uniform vec2 NoiseScale;
uniform float radius;
uniform float bias;

uniform mat4 projection;

void main()
{
    FragData frag;
    frag.position = texture(position, vert.texcoord).xyz;
    frag.normal = normalize(texture(normal, vert.texcoord).xyz);
    frag.noise = normalize(texture(noise, vert.texcoord * NoiseScale).xyz);

    // TBN matrix
    vec3 tangent = normalize(frag.noise - frag.normal * dot(frag.noise, frag.normal));
    vec3 bitangent = cross(frag.normal, tangent);
    mat3 TBN = mat3(tangent, bitangent, frag.normal);

    occlusion = 0.0f;
    for(int i = 0; i < KernelSize; i++)
    {
        float x = float(i) / float(KernelSize);
        for(int j = 0; j < KernelSize; j++)
        {
            float y = float(j) / float(KernelSize);

            vec3 MySample = TBN * texture(KernelTexture, vec2(x, y)).xyz;
            MySample = frag.position + MySample * radius;

            vec4 offset = vec4(MySample, 1.0f);
            offset = projection * offset;
            offset.xyz /= offset.w;
            offset.xyz = offset.xyz * 0.5f + 0.5f;

            float depth = texture(position, offset.xy).z;

            float range = smoothstep(0.0f, 1.0f, radius / abs(frag.position.z - depth));
            occlusion += ((depth >= MySample.z + bias) ? 1.0f : 0.0f) * range;
        }
    }

    occlusion = 1.0f - (occlusion / float(KernelSize * KernelSize));
}

kernel configuration

void setKernel()
{
    auto lerp = [] (float a, float b, float f)
    {
        return a + f * (b - a);
    };

    kernel.clear();

    for (int i = 0; i < KernelSize * KernelSize; i++)
    {
        float x = RandomZeroOne();
        float y = RandomZeroOne();
        float z = RandomZeroOne();

        QVector3D sample = { x * 2.0f - 1.0f, y * 2.0f - 1.0f, z };
        sample.normalize();
        sample *= RandomZeroOne();

        float scale = static_cast<float>(i) / static_cast<float>(KernelSize);
        scale = lerp(0.1f, 1.0f, scale * scale);
        sample *= scale;

        kernel.append(sample);
    }
}

void setKernelTexture()
{
    glBindTexture(GL_TEXTURE_2D, textures[TextureIndex::KERNEL]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, KernelSize, KernelSize, 0, GL_RGB, GL_FLOAT, &(kernel[0]));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

==================== UPDATE ====================

I think I found the problem. I didn't update NoiseScale when the window is resized.

void resizeGL(int w, int h)
{
    /* ... */

    // now updating NoiseScale
    NoiseScale.setX(static_cast<float>(geometry().width()));
    NoiseScale.setY(static_cast<float>(geometry().height()));
    NoiseScale /= static_cast<float>(NoiseSize);

    /* ... */
}

And this is the result:

enter image description here

But now performance is very bad. With a 64-sample kernel and a 4x4 noise matrix, I get a frame rate of 3-4 fps.

How can I improve performance? Thanks!

Arctic Pi
  • 669
  • 5
  • 19
  • 1
    Looks like you are drawing many spheres are you using instancing? That could be one way to go also use some profiling tool . – Paritosh Kulkarni Dec 17 '18 at 22:52
  • @ParitoshKulkarni Yes, there are more than 4 thousand spheres in the scene, and this is only a "small" model. I'm working on molecular visualization. I'm not using instancing, but I'm using impostors to draw the spheres. I need to check if I can also use instancing combined with impostors, and if there could be some improvement. Thanks for the suggestion! ;) – Arctic Pi Dec 18 '18 at 15:15

0 Answers0