首页 > 解决方案 > OpenGL:屏幕空间环境光遮蔽 (SSAO)

问题描述

我按照屏幕空间环境光遮蔽 (SSAO) 的教程进行操作,但似乎有些东西没有按应有的方式工作。

在此处输入图像描述

正如您从屏幕截图中看到的,在环境光遮蔽最明显的较暗区域中有一些图案。

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

这些是相关的代码片段。

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

    /* ... */
}

这是结果:

在此处输入图像描述

但是现在性能很差。使用 64 个样本内核和 4x4 噪声矩阵,我得到 3-4 fps 的帧速率。

我怎样才能提高性能?谢谢!

标签: c++openglgraphicslightingssao

解决方案


推荐阅读