OpenGL SSAO 白色发光边缘/出血神器

问题描述 投票:0回答:0

我正在尝试在我的游戏引擎中实现高质量的 SSAO,为此我使用 OpenGL 作为主要渲染 API 和 GLSL 着色器。到目前为止,结果还不错,说实话,我实际上实现了 https://learnopengl.com/Advanced-Lighting/SSAO 这篇文章中的 SSAO。所以我上手并没有遇到太多困难,而且代码与文章非常相似。我唯一的问题是我在各个场景对象周围出现的白色发光边缘伪影。

就像边缘在流血。我尝试过 SSAO 的其他实现,但这个工件总是出现。其他的好像都还好。

此外,我没有对 SSAO 结果进行任何后模糊操作来平滑结果。我听说做模糊实际上会导致这种类型的伪像更多......

这是片段/像素着色器代码:

#version 460 core

in vec2 textureCoordinate;

layout(binding = 0) uniform sampler2D gPosition;
layout(binding = 1) uniform sampler2D gNormal;
layout(binding = 2) uniform sampler2D gNoise;

layout(std140, binding = 0) uniform CBPerFrame {
    mat4 proj;
    mat4 view;
    mat4 world;
    mat4 lightviewproj;
    vec4 lightPosition;
    vec4 cameraPosition;
    float hasNormalMap;
    float enableSSAO;
    vec2 pad;
    vec4 pad2;
} cbPerFrame;

const int samples = 64;
const vec2 noiseScale = vec2(1200.0/4.0, 800.0/4.0);

layout(std140, binding = 1) uniform CBSSAO {
    vec3 sample_sphere[samples];
} cbSSAO;

void main() {
    vec3 fragPos   = texture(gPosition, textureCoordinate).xyz;
    vec3 normal    = normalize(texture(gNormal, textureCoordinate).rgb*2.0 - 1.0);
    vec3 randomVec = texture(gNoise, textureCoordinate * noiseScale).xyz;

    vec3 tangent   = normalize(randomVec - normal * dot(randomVec, normal));
    vec3 bitangent = cross(normal, tangent);
    mat3 TBN       = mat3(tangent, bitangent, normal);

    float radius = 0.9f;
    float bias = 0.05f;

    float occlusion = 0.0;
    for(int i = 0; i < samples; ++i) {
        // get sample position
        vec3 samplePos = TBN * cbSSAO.sample_sphere[i]; // from tangent to view-space
        samplePos = fragPos + samplePos * radius;

        vec4 offset = vec4(samplePos, 1.0);
        offset      = cbPerFrame.proj * offset;    // from view to clip-space
        offset.xyz /= offset.w;               // perspective divide
        offset.xyz  = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0

        float sampleDepth = texture(gPosition, offset.xy).z; 
        float rangeCheck = smoothstep(0.0, 1.0, radius / abs(fragPos.z - sampleDepth));
        occlusion += (sampleDepth >= samplePos.z + bias ? 1.0 : 0.0) * rangeCheck; 
    }

    occlusion = 1.0 - (occlusion / float(samples));
    gl_FragColor = vec4(1, 1, 1, 1) * occlusion;  
}

这是我生成样本的方法:

IGPUConstantBuffer* cbSSAO = rnd->createGPUConstantBuffer(sizeof(SSAOData));

    std::uniform_real_distribution<float> randomFloats(0.0, 1.0); // random floats between [0.0, 1.0]
    std::default_random_engine generator;
    for (unsigned int i = 0; i < numSamples; ++i)
    {
        glm::vec3 sample(
            randomFloats(generator) * 2.0 - 1.0,
            randomFloats(generator) * 2.0 - 1.0,
            randomFloats(generator)
        );
        sample  = glm::normalize(sample);
        sample *= randomFloats(generator);

        float scale = (float)i / float(numSamples);
        scale   = lerp(0.1f, 1.0f, scale * scale);
        sample *= scale;
        SSAOData.samples[i] = sample;
    }

    cbSSAO->updateData(&SSAOData);

我还应该提到,所有 g 缓冲区纹理(gPosition、gNormal、gNoise)均采用 GL_RGBA32F 格式,并将过滤器设置为 GL_NEAREST。位置和法线都在视图空间中。

注意:我的引擎还支持 DirectX 11 渲染 API,并且我还使用 HLSL 实现了相同的 SSAO 技术,不幸的是,这是同样的问题。除了物体周围有白色边缘外,一切都很好。

opengl glsl shader game-engine ssao
© www.soinside.com 2019 - 2024. All rights reserved.