MSAA 的奇怪结果

Weird result with MSAA

使用 OpenGL 的 MSAA。

我刚刚使用 'glutSolidSphere' 绘制了一个白色球体,并在轮廓 'dot(Normal, CameraVec) < threshold' 处填充了黑色。
我在内部白色圆圈的轮廓处发现了一个奇怪的结果。 MSAA 好像没用。
顺便说一句,它在黑色圆圈的轮廓(最外层)处效果很好。

如果我增加样本数量,即使在内部白色圆圈的轮廓上也能很好地工作。
我认为它应该独立于样本数量工作,因为解析样本发生在片段着色器之后。

这是正确的结果吗?如果是,为什么?

下面是4个样本(左)和32个样本(右)的结果。

MSAA 仅有助于平滑多边形边缘和交叉点。它不会平滑由您的着色器代码创建的急剧过渡。

MSAA 背后的主要思想是片段着色器仍然每个片段只执行一次。每个片段有多个样本,覆盖率由样本决定。这意味着片段的一些样本可以在渲染的多边形内部,而一些在外部。然后片段着色器输出只写入覆盖的样本。但是片段中所有被覆盖的样本都得到相同的值。

深度缓冲区也有每个样本的分辨率,这意味着多边形之间的交点也受益于 MSAA 产生的平滑。

一旦您了解了 MSAA 的工作原理,就会明白它对多边形内部的急剧过渡没有任何作用,这可能是着色器中应用逻辑的结果。要在这种情况下实现平滑,您必须评估每个样本的片段着色器,而 MSAA 不会发生这种情况。

MSAA 很有吸引力,因为它确实为许多用例执行了足够的抗锯齿,而且开销相对较小。但正如您所注意到的,这显然不足以应对所有情况。

你能做些什么超出了这里的答案范围。主要有两个方向:

  • 您可以避免在着色器代码中生成急剧的过渡。如果您使用标准纹理,则使用 mipmap 会有所帮助。对于程序转换,您可以在代码中平滑它们,可能基于梯度值。
  • 您可以使用不同的抗锯齿方法。太多了,这里就不一一列举了。通过超级采样很容易获得完美的抗锯齿效果,但代价非常高。大多数方法都试图在不增加太多开销的情况下取得比普通 MSAA 更好的结果。

我对使用 32x MSAA 在内边缘得到一些平滑这一事实感到有些困惑。我不认为这是预期的。我想知道在下采样过程中是否发生了某种产生某种形式的平滑的事情。