我正在尝试将Sascha Willems SSAO example用作资源时复制LearnOpenGL SSAO tutorial。但是我的SSAO代码仅部分覆盖了特定角度/距离的模型,并且在靠近对象时也具有非常强的自我遮挡效果。
左边是我的渲染器,右边是Sascha Willems SSAO Example:

  • 中心:Wrong | Correct
  • 窗口:Wrong | Correct
  • 楼梯:Wrong | Correct

  • 编辑:从RenderDoc的正确图像上有一些奇怪的伪像。对于那个很抱歉。
    有关渲染器变量的一些注意事项:
  • 位置+深度图像使用VK_FORMAT_R32G32B32A32_SFLOAT格式,在RenderDoc中看起来正确。 [1] [2]
  • 正常图像使用VK_FORMAT_R8G8B8A8_UNORM格式,在RenderDoc中看起来正确。 [1]
  • 位置+深度和正常图像使用带有VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE的VkSampler。
  • SSAO图像是VK_FORMAT_R8_UNORM,并且正在由着色器正确写入。 [1]
  • SSAO噪声图像使用VK_FORMAT_R32G32B32A32_SFLOAT格式,在RenderDoc中看起来正确。 [1]
  • SSAO噪声图像使用带有VK_SAMPLER_ADDRESS_MODE_REPEAT的VkSampler。

  • SSAO噪声
    // Random Generator
    std::default_random_engine rndEngine(static_cast<unsigned>(glfwGetTime()));
    std::uniform_real_distribution<float> rndDist(0.0f, 1.0f);
    
    // SSAO random noise
    std::vector<glm::vec4> ssaoNoise(SSAO_NOISE_DIM * SSAO_NOISE_DIM);
    for (uint32_t i = 0; i < static_cast<uint32_t>(ssaoNoise.size()); i++)
    {
        ssaoNoise[i] = glm::vec4(rndDist(rndEngine) * 2.0f - 1.0f, rndDist(rndEngine) * 2.0f - 1.0f, 0.0f, 0.0f);
    }
    
    SSAO内核
    // Function for SSAOKernel generation
    float lerp(float a, float b, float f)
    {
        return a + f * (b - a);
    }
    
    // SSAO sample kernel
    std::vector<glm::vec4> ssaoKernel(SSAO_KERNEL_SIZE);
    for (uint32_t i = 0; i < SSAO_KERNEL_SIZE; i++)
    {
        glm::vec3 sample(rndDist(rndEngine) * 2.0 - 1.0, rndDist(rndEngine) * 2.0 - 1.0, rndDist(rndEngine));
        sample = glm::normalize(sample);
        sample *= rndDist(rndEngine);
        float scale = float(i) / float(SSAO_KERNEL_SIZE);
        scale = lerp(0.1f, 1.0f, scale * scale);
        ssaoKernel[i] = glm::vec4(sample * scale, 0.0f);
    }
    
    SSAO内核XY值在-1.0至1.0之间,Z值在0.0至1.0之间:
    ssaoKernel XYZ[0]: X: -0.0428458 Y: 0.0578492 Z: 0.0569087
    ssaoKernel XYZ[1]: X: 0.0191572 Y: 0.0442375 Z: 0.00108795
    ssaoKernel XYZ[2]: X: 0.00155709 Y: 0.0287552 Z: 0.024916
    ssaoKernel XYZ[3]: X: -0.0169349 Y: -0.0298343 Z: 0.0272303
    ssaoKernel XYZ[4]: X: 0.0469432 Y: 0.0348599 Z: 0.0573885
    (...)
    ssaoKernel XYZ[31]: X: -0.104106 Y: -0.434528 Z: 0.321963
    
    GLSL着色器
    model.vert
    mat3 normalMatrix = transpose(inverse(mat3(ubo.view * ubo.model)));
    outNormalViewSpace = normalMatrix * inNormal;
    outPositionViewSpace = vec3(ubo.view * ubo.model * vec4(inPosition, 1.0));
    
    model.frag
    // These are identical to the camera
    float near = 0.1;
    float far  = 100.0;
    
    float LinearizeDepth(float depth)
    {
        float z = depth * 2.0 - 1.0;
        return (2.0 * near * far) / (far + near - z * (far - near));
    }
    
    (...)
    
    outNormalViewSpace = vec4(normalize(inNormalViewSpace) * 0.5 + 0.5, 1.0);
    outPositionDepth = vec4(inPositionViewSpace, LinearizeDepth(gl_FragCoord.z));
    
    fullscreen.vert
    outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
    gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f);
    
    ssao.frag
    #version 450
    
    layout (location = 0) in vec2 inUV;
    
    layout (constant_id = 1) const int SSAO_KERNEL_SIZE = 32;
    layout (constant_id = 2) const float SSAO_RADIUS = 0.5;
    
    layout (binding = 0) uniform sampler2D samplerPositionDepth;
    layout (binding = 1) uniform sampler2D samplerNormal;
    layout (binding = 2) uniform sampler2D samplerSSAONoise;
    
    layout (binding = 3) uniform SSAOKernel
    {
        vec4 samples[SSAO_KERNEL_SIZE];
    } ssaoKernel;
    
    layout( push_constant ) uniform UniformBufferObject {
        mat4 projection;
    } ubo;
    
    layout (location = 0) out float outSSAO;
    
    void main()
    {
        //
        // SSAO Post Processing (Pre-Blur)
        //
    
        // Get a random vector using a noise lookup
        ivec2 texDim = textureSize(samplerPositionDepth, 0);
        ivec2 noiseDim = textureSize(samplerSSAONoise, 0);
        const vec2 noiseUV = vec2(float(texDim.x) / float(noiseDim.x), float(texDim.y) / (noiseDim.y)) * inUV;
        vec3 randomVec = texture(samplerSSAONoise, noiseUV).xyz * 2.0 - 1.0;
    
        // Get G-Buffer values
        vec3 fragPos = texture(samplerPositionDepth, inUV).rgb;
        vec3 normal = normalize(texture(samplerNormal, inUV).rgb * 2.0 - 1.0);
    
        // Create TBN matrix
        vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
        vec3 bitangent = cross(tangent, normal);
        mat3 TBN = mat3(tangent, bitangent, normal);
    
        // Calculate occlusion value
        float occlusion = 0.0f;
        for(int i = 0; i < SSAO_KERNEL_SIZE; i++)
        {
            vec3 samplePos = TBN * ssaoKernel.samples[i].xyz;
            samplePos = fragPos + samplePos * SSAO_RADIUS;
    
            // project
            vec4 offset = vec4(samplePos, 1.0f);
            offset = ubo.projection * offset;
            offset.xyz /= offset.w;
            offset.xyz = offset.xyz * 0.5f + 0.5f;
    
            float sampleDepth = -texture(samplerPositionDepth, offset.xy).w;
    
            // Range check
            float rangeCheck = smoothstep(0.0f, 1.0f, SSAO_RADIUS / abs(fragPos.z - sampleDepth));
            occlusion += (sampleDepth >= samplePos.z ? 1.0f : 0.0f) * rangeCheck;
        }
        occlusion = 1.0 - (occlusion / float(SSAO_KERNEL_SIZE));
    
        outSSAO = occlusion;
    }
    
    某处必须有错误的设置或不正确的计算,但是我不能完全依靠它。如果缺少相关内容,请随时请求其他代码段。
    任何帮助,不胜感激,谢谢!

    最佳答案

    感谢mlkn在注释中指出LinearizeDepth函数看起来不正确。他是正确的,还有一个额外的不必要的“* 2.0-1.0”步骤不属于该步骤。谢谢mlkn! :)

    这是原始的,不正确的LinearizeDepth函数:

    float LinearizeDepth(float depth)
    {
        float z = depth * 2.0 - 1.0;
        return (2.0 * near * far) / (far + near - z * (far - near));
    }
    

    通过删除第一行,并将其更改为:
    float LinearizeDepth(float depth)
    {
        return (2.0 * near * far) / (far + near - depth * (far - near));
    }
    

    我的输出立即更改为此,这似乎是正确的:
    c&#43;&#43; - 为什么SSAO仅在某些角度/距离下工作?-LMLPHP

    09-18 00:01