这是我渲染场景的过程:

  • 绑定(bind) MSAA x4 GBuffer(4 种颜色附件、位置、法线、颜色和无光照颜色(仅限天空盒。我还有一个深度组件/纹理)。
  • 绘制天空盒
  • 绘制地理
  • 将所有颜色和深度分量 Blit 到单个样本 FBO
  • 应用光照(我使用深度纹理通过检查深度纹理值是否小于 1 来检查它是否应该被点亮)。
  • 渲染四边形

  • 这就是正在发生的事情:

    c++ - 延迟的 MSAA 伪像-LMLPHP c++ - 延迟的 MSAA 伪像-LMLPHP

    正如你所看到的,我在边缘得到了这些白色和黑色的人工制品,而不是平滑的边缘。 (很高兴注意到,如果我移除照明并在没有照明的情况下渲染纹理,我不会得到它并且它会正确平滑)。

    这是我的着色器(它实现了 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)将是密集的方式。

    有任何想法吗?

    最佳答案

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

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

    关于c++ - 延迟的 MSAA 伪像,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49063871/

    10-10 23:22