延迟MSAA伪影问题

4
这是我用来渲染场景的过程:
  • 绑定 MSAA x4 GBuffer(4个颜色附件,位置、法线、颜色和非光照颜色(仅天空盒)。我还有一个深度组件/纹理)。
  • 绘制天空盒
  • 绘制几何体
  • 将所有颜色和深度组件合并到一个单样本 FBO 中
  • 应用光照(我使用深度纹理检查是否应该被照亮,通过检查深度纹理值是否小于1)。
  • 渲染四边形
以下是发生的情况:

Single-Sample Multi-Sample

可以看到,边缘周围出现了黑白条纹而不是平滑的边缘。值得注意的是,如果我删除光照并只渲染没有光照的纹理,我就不会遇到这个问题,而且它会正确地平滑。
以下是我的着色器(其中实现了 SSAO,但似乎与此无关)。
#version 410 core
in vec2 Texcoord;
out vec4 outColor;
uniform sampler2D texFramebuffer;
uniform sampler2D ssaoTex;

uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gAlbedo;
uniform sampler2D gAlbedoUnlit;
uniform sampler2D gDepth;

uniform mat4 View;
struct Light {
    vec3 Pos;
    vec3 Color;
    float Linear;
    float Quadratic;
    float Radius;
 };

 const int MAX_LIGHTS = 32;
 uniform Light lights[MAX_LIGHTS];
 uniform vec3 viewPos;

 uniform bool SSAO;

 void main()
 {
    vec3 color = texture(gAlbedo, Texcoord).rgb;
    vec3 colorUnlit = texture(gAlbedoUnlit, Texcoord).rgb;
    vec3 pos = texture(gPosition, Texcoord).rgb;
    vec3 norm = normalize(texture( gNormal, Texcoord)).rgb;
    vec3 depth = texture(gDepth, Texcoord).rgb;
    float ssaoValue = texture(ssaoTex, Texcoord).r;

    // then calculate lighting as usual
    vec3 lighting;
    if(SSAO)
    {
        lighting = vec3(0.3 * color.rgb * ssaoValue); // hard-coded ambient component
    }
    else
    {
        lighting = vec3(0.3 * color.rgb); // hard-coded ambient component
    }
    vec3 posWorld = pos.rgb;

    vec3 viewDir = normalize(viewPos - posWorld);

    for(int i = 0; i < MAX_LIGHTS; ++i)
    {

        vec4 lightPos = View * vec4(lights[i].Pos,1.0);
        vec3 normLight = normalize(lightPos.xyz);
        float distance = length(lightPos.xyz - posWorld);
        if(distance < lights[i].Radius)
        {
            // diffuse
            vec3 lightDir = normalize(lightPos.xyz - posWorld);
            vec3 diffuse = max(dot(norm.rgb, lightDir), 0.0) * color.rgb * 
lights[i].Color;

        float attenuation = 1.0 / (1.0 + lights[i].Linear * distance + lights[i].Quadratic * distance * distance);
        lighting += (diffuse*attenuation);
        }
    }

    if(depth.r >= 1)
    {
        outColor = vec4(colorUnlit, 1.0);
    }
    else
    {
        outColor = vec4(lighting, 1.0);
    }

}

所以,最后一个if语句检查它是否在深度纹理中,如果是,则应用光照,如果不是,则只绘制天空盒(这样就不会对天空盒应用光照)。

我已经花了几天时间尝试解决这个问题,改变了检查是否需要光照的方式,比较法线、位置和深度,将格式更改为更高的分辨率(例如使用RGB16F而不是RGB8等),但我无法弄清楚是什么原因导致这种情况发生,每个样本单独进行光照处理(使用texel fetch)会非常耗费性能。

有什么想法吗?


你正在使用纹理附件,对吗?这可能是你正在使用的包装选项。 - Daniel Marques
我认为你的问题在于深度混合在 blit msaa 解析上。在你的算法中,深度组件是否跨越大距离混合(部分在/外对象)是有意义的呢? - Andreas
1
MSAA和延迟渲染不太容易兼容。你只是在物体之间的边缘混合颜色/材质/深度/法线/任何属性,并使用混合在一起的属性进行照明,这与使用正确的属性进行照明并仅混合结果颜色完全不同。 - derhass
我已经通过每个 Texel 而不是每个片段来处理我的光照,使其正常工作,但是找到一种更好的方法来实现这一点而不会过度使用 GPU 会很好。 - Calum McManus
边缘上的片段几乎肯定需要进行每个像素的光照计算,但其余部分可能不需要。您可以尝试找到一种解决方案,仅对需要进行每个像素着色的片段执行此操作,否则切换到后处理多重采样并避免整个问题(这是一种流行的解决方案)。 - fintelia
1个回答

0

这个问题现在有点老了,但我想说一下我是如何解决它的。

我在我的着色器中运行基本的Sobel滤波器,用于进行屏幕空间轮廓,但除此之外,我还检查是否启用了MSAA,如果启用了,则计算边缘像素周围每个纹素的光照!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接