OpenGL:屏幕空间环境光遮蔽(SSAO)

时间:2018-12-17 21:31:04

标签: c++ opengl graphics lighting ssao

我遵循了tutorial进行屏幕空间环境光遮蔽(SSAO)的操作,但似乎有些事情没有按预期进行。

enter image description here

从屏幕截图中可以看到,在较暗的区域中有一些图案,其中环境光遮挡最为明显。

我怀疑示例内核有问题,但是我严格按照本教程进行操作。唯一的区别是,我还考虑调整窗口的大小和相机的移动。

这些是相关的代码段。

SSAO顶点着色器

#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片段着色器

#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));
}

内核配置

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);
}

====================更新==================

我认为我找到了问题。调整窗口大小时,我没有更新NoiseScale。

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);

    /* ... */
}

这是结果:

enter image description here

但是现在性能非常糟糕。使用64个样本的内核和4x4的噪声矩阵,我的帧速率为3-4 fps。

如何提高性能?谢谢!

0 个答案:

没有答案