CSAA / MSAA和镜面灯

时间:2014-02-04 10:01:44

标签: opengl glsl msaa

我已经在某些变体中实现了对MSAA的支持:

它可以使用任何基于上下文(通过在设置上下文时调用wglChoosePixelFormatARB并向其传递相应的参数列表)或通过启用MSAA渲染到FBO(创建具有颜色和深度渲染缓冲附件的多重采样FBO,以及另一个FBO)带有用于解析的颜色附件,并且抗锯齿似乎总体上起作用。

然而,当我启用消除锯齿时,我发现了一些似乎与镜面反射相关的伪像。对于基于上下文的CSAA来说这是最糟糕的,对于基于上下文的MSAA来说非常糟糕,但是当我在渲染到我的FBO时使用MSAA时要好得多。

对于我用于测试的飞机型号之一,它非常值得注意,特别是在发动机气缸和一些“导线”周围(它们实际上不是直线,而是薄气缸):

result comparison

正如你在图像上看到的那样,当我关闭镜面反射光时问题几乎消失了,但我不确定是什么导致它。

以上图片使用此着色器代码计算镜面反射(在所有灯光的循环内):

if( matShininess > 0.0 )
{
    vec3 reflectionCamSpace = reflect(-lightDirectionCamSpace, faceNormal);
    vec3 surfToViewerCamSpace = normalize (-vertPositionCamSpace);
    float dotSpecular = max( 0.0, dot (reflectionCamSpace, surfToViewerCamSpace) );
    float specularFactor = pow( dotSpecular, matShininess );
    specularTerm += vec3(lgt.specular * specularFactor); 
}

不同的灯光模型之间似乎也存在很大差异:

lighting models

左侧使用上面提到的代码用于镜面高光,而右边是使用它(再次在主光环内部,它遍历所有灯光)

if( matShininess > 0.0 )
{
    vec3 surfToViewerCamSpace = normalize (-vertPositionCamSpace);
    vec3 halfAngle = normalize(lightDirectionCamSpace + surfToViewerCamSpace);
    float specularFactor = dot(faceNormal, halfAngle);
    specularFactor = clamp(specularFactor, 0, 1);
    specularFactor = lightDot != 0.0 ? specularFactor : 0.0;
    specularFactor = pow(specularFactor, matShininess);
    specularTerm += vec3(lgt.specular * specularFactor);
}

所以我想知道为什么在使用基于FBO的MSAA和基于上下文的MSAA时会有这么大的差异。还有什么我的错误与我的镜面高光一起创造问题?

编辑:根据以下帖子的要求,我还添加了一个测试,用于比较16xQ CSAA到上下文和FBO的结果(对于FBO我只使用RenderbufferStorageMultisampleCoverageNV而不是glRenderbufferStorageMultisample)。 FBO的结果似乎更好(但仍然没有令人信服):

16xQ CSAA Ctx vs FBO

1 个答案:

答案 0 :(得分:1)

这不是答案;更像是一个冗长的评论请求。

Sample shading可能会有所帮助,您可以告诉GL多次评估着色器,而不是每个片段进行一次计算,如果覆盖率允许此优化,则将结果传递给所有样本。对于MSAA,着色器仅针对其基元完全覆盖像素的片段进行一次评估。深度/模板样本在每个样本中是唯一的,这有助于边缘混叠,但是着色器本身内出现的任何混叠(例如纹理混叠,镜面反射高光等)都不能使用纯MSAA进行纠正。

样本着色有效地将MSAA转换为MSAA(多个样本可以阴影一次)到SSAA(1:1样本:阴影比率)之间的某些内容。为什么你的问题只显示使用默认帧缓冲区执行的MSAA解析,我不能说。但样本着色应该有所帮助。

对于CSAA来说,这完全超出了GL无法控制的事物范围。在香草GL管道的任何地方都没有CSAA的概念。虽然如果使用NV的NV_framebuffer_multisample_coverage扩展名,可以使用FBO实现它。

老实说,如今我几乎总是优先考虑基于FBO的抗锯齿。如果执行此操作,则无需为最终用户重新创建渲染上下文以更改AA设置,这意味着如果用户开始尝试性能/图像质量的配置设置,则可以减少更少的资源重新加载。它是一种更加灵活的设计,您甚至可以使用现代硬件上的FBO进行MSAA延迟着色,这要归功于多重采样纹理提取(您可以在着色器级别实现解析)。

我很想知道您是否在基于上下文和基于FBO的CSAA之间遇到任何差异,或者如果明确设置着色样本的最小数量有任何影响。