首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么SSAO只从特定的角度/距离工作?

为什么SSAO只从特定的角度/距离工作?
EN

Stack Overflow用户
提问于 2019-04-05 07:17:28
回答 1查看 471关注 0票数 5

我试图复制Sascha Willems SSAO示例,同时使用LearnOpenGL SSAO教程作为资源。但是我的SSAO代码只是在一定的角度/距离上部分覆盖模型,并且当接近一个物体时也有很强的自遮挡效应。

左边是我的渲染器,右边是Sascha Willems SSAO示例

编辑:在来自RenderDoc的正确图像上有一些奇怪的工件。真对不起。

关于我的渲染器变量的一些注释:

  • Position+Depth图像使用VK_FORMAT_R32G32B32A32_SFLOAT格式,在RenderDoc中看起来是正确的。[1] [2]
  • 普通图像使用VK_FORMAT_R8G8B8A8_UNORM格式,在RenderDoc中看起来是正确的。[1]
  • Position+Depth和普通图像正在使用带有VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE的VkSampler。
  • SSAO图像是VK_FORMAT_R8_UNORM,并且正在被着色器正确地写入。[1]
  • SSAO噪声图像采用VK_FORMAT_R32G32B32A32_SFLOAT格式,在RenderDoc中显示正确。[1]
  • SSAO噪声图像使用的是VkSampler和VK_SAMPLER_ADDRESS_MODE_REPEAT。

SSAO噪声

代码语言:javascript
复制
// 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核

代码语言:javascript
复制
// 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之间:

代码语言:javascript
复制
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

代码语言:javascript
复制
mat3 normalMatrix = transpose(inverse(mat3(ubo.view * ubo.model)));
outNormalViewSpace = normalMatrix * inNormal;
outPositionViewSpace = vec3(ubo.view * ubo.model * vec4(inPosition, 1.0));

model.frag

代码语言:javascript
复制
// 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

代码语言:javascript
复制
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f);

ssao.frag

代码语言:javascript
复制
#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;
}

一定有一个错误的设置或不正确的计算某处,但我不能完全用我的手指。如果缺少相关内容,请随时请求额外的代码片段。

任何帮助都是非常感谢的,谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-04-05 10:24:06

这归功于mlkn在注释中指出LinearizeDepth函数看起来不正确。他是正确的,有一个额外的不必要的"* 2.01.0“步骤不属于。谢谢你!:)

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

代码语言:javascript
复制
float LinearizeDepth(float depth) 
{
    float z = depth * 2.0 - 1.0;
    return (2.0 * near * far) / (far + near - z * (far - near));    
}

删除第一行,并将其更改为:

代码语言:javascript
复制
float LinearizeDepth(float depth) 
{
    return (2.0 * near * far) / (far + near - depth * (far - near));    
}

我的输出立即更改为此,这似乎是正确的:

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55530121

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档