OpenGL: Окклюзия окружающего пространства на экране (SSAO) - PullRequest
0 голосов
/ 18 декабря 2018

Я следовал этому учебнику для Окружающей среды на экране (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 кадра в секунду.

Как повысить производительность?Спасибо!

...