MSAA和顶点插值导致数值超出范围

5

我正在使用一个顶点着色器和片段着色器来编写GLSL程序。

在顶点着色器中,输出的highp float范围是[0,1]。

但当它到达片段着色器时,我看到三角形边缘处的值超过了1.1!

如果我要解决这个问题,我可以...

  • 要么禁用MSAA。
  • 要么使用GLSL插值限定符flat来禁用插值。

如果启用了MSAA,一个被夹紧在0到1之间且具有高精度的浮点数怎样会作为一个远大于1的值到达片段着色器中呢?

顶点着色器代码:

out highp float lightcontrib2;
...
lightcontrib2 = clamp( irrad, 0.0, 1.0 );

片元着色器代码:

in highp float lightcontrib2;
...
if (lightcontrib2>1.1) { fragColor = vec4(1,0,1,1); return; }

使用MSAA 4x,在OpenGL中生成的图像如下所示(观察窗口中心处品红色的像素)。

magenta pixels

我已排除非数字值。

GL_VERSION: 3.2.0 NVIDIA 450.51.06

1个回答

5
如果启用了MSAA,那么被夹住的0到1的高精度浮点数如何作为一个明显大于1的值出现在片段着色器中?多重采样本质上是超级采样的一种变体:从基本图元的像素大小区域中取多个样本。在该像素大小区域内的不同位置进行采样以产生结果值。然而,当你处于基本图元的边缘时,该像素大小区域中的某些位置在实际覆盖的基本图元区域之外。在超级采样中,这没有问题;你只需不使用这些样本。然而,多重采样不同。在多重采样中,深度样本与片段着色器生成的样本是不同的。也就是说,系统可能只执行FS一次,但会取4个深度样本并将其与深度缓冲区中的4个样本进行测试。通过深度测试的任何样本都会从执行的单个FS调用中获取其颜色值。如果那4个深度样本中有一些在基本图元区域之外,那就没关系,它们不计入。然而,通过将FS调用值与深度采样分离,我们现在遇到了一个问题:在像素区域内,单个FS调用的确切位置是哪里?
这就是我们遇到的问题。如果FS调用执行在原始区域之外,那么它通常会被丢弃。但是,如果任何深度采样在原始区域内,那么这些深度采样仍然需要获取颜色数据。而MSAA的整个目的就是不为每个样本执行FS,因此它们可以从在不同位置执行的FS调用中获取其颜色数据。
理想情况下,应该是在原始区域内执行FS调用。但硬件不能保证这一点。好吧,它默认情况下不能保证。如果FS位置恰好落在原始区域略微外面,则并非每个算法都存在问题。
但是有些算法确实存在问题。这就是为什么我们有片段着色器输入的 centroid限定符。它确保特定的插值值将在原始区域内生成。
正如你可能已经猜到的那样,这不是默认设置,因为它比非 centroid 插值要慢。因此只在需要时使用它。

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