MSAA 和顶点插值导致值超出范围
MSAA and vertex interpolation cause out-of-range values
我正在使用 GLSL 顶点着色器和片段着色器。
顶点着色器在[0,1]
范围内输出一个highp float
当它到达片段着色器时,我看到值(在三角形边缘处)不少于 1.1!
如果我...
,这个问题就会消失
- 要么禁用 MSAA
- 或者使用 GLSL 禁用插值 interpolation qualifier
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 生成的图像。 (观察 window 中心的磁铁色像素。)
我已经排除了非数字值。
GL_VERSION: 3.2.0 NVIDIA 450.51.06
How can a clamped 0-to-1 high precision float arrive in fragment shader as a value that is substantially larger than 1, if MSAA is enabled?
多重采样的核心是超级采样的变体:从图元的 pixel-sized 区域获取多个样本。对 pixel-sized 区域的 space 内的不同位置进行采样以生成结果值。
然而,当您处于图元的边缘时,pixel-sized 区域中的某些位置在图元实际覆盖的区域外部。在超级采样中很好;你只是不使用那些样本。
但是,多重采样是不同的。在多重采样中,深度样本不同于片段着色器生成的样本。也就是说,系统可能只执行一次 FS,但会获取 4 个深度样本并针对深度缓冲区中的 4 个样本进行测试。任何通过深度测试的样本都从执行的单个 FS 调用中获取它们的颜色值。如果这 4 个深度样本中的一些在图元区域之外,那很好;他们不算数。
但是,通过将 FS 调用值与深度采样分开,我们现在遇到了一个问题:在像素区域内 那个单个 FS 调用究竟是在哪里执行的?
这就是我们遇到问题的地方。如果 FS 调用在原语区域之外的位置执行,通常会被丢弃。但是如果任何深度样本在图元的区域内,那么这些深度样本仍然需要获取颜色数据。 MSAA 的全部意义在于不为每个样本执行 FS,因此他们可能会从在不同位置执行的 FS 调用中获取颜色数据。
理想情况下,它将来自在原语区域内的某个位置执行的 FS 调用。但是硬件不能保证这一点。好吧,无论如何,默认情况下它不能保证。如果 FS 位置恰好略微落在基元区域之外,并非每个算法都会出现问题。
但是有些算法确实有问题。这就是为什么我们有 the centroid
qualifier for fragment shader inputs。它确保将在图元区域内生成特定的插值。
您可能已经猜到了,这不是默认值,因为它比非 centroid
插值要慢。所以只在你需要的时候使用它。
我正在使用 GLSL 顶点着色器和片段着色器。
顶点着色器在[0,1]
范围内输出一个highp float
当它到达片段着色器时,我看到值(在三角形边缘处)不少于 1.1!
如果我...
,这个问题就会消失- 要么禁用 MSAA
- 或者使用 GLSL 禁用插值 interpolation qualifier
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 生成的图像。 (观察 window 中心的磁铁色像素。)
我已经排除了非数字值。
GL_VERSION: 3.2.0 NVIDIA 450.51.06
How can a clamped 0-to-1 high precision float arrive in fragment shader as a value that is substantially larger than 1, if MSAA is enabled?
多重采样的核心是超级采样的变体:从图元的 pixel-sized 区域获取多个样本。对 pixel-sized 区域的 space 内的不同位置进行采样以生成结果值。
然而,当您处于图元的边缘时,pixel-sized 区域中的某些位置在图元实际覆盖的区域外部。在超级采样中很好;你只是不使用那些样本。
但是,多重采样是不同的。在多重采样中,深度样本不同于片段着色器生成的样本。也就是说,系统可能只执行一次 FS,但会获取 4 个深度样本并针对深度缓冲区中的 4 个样本进行测试。任何通过深度测试的样本都从执行的单个 FS 调用中获取它们的颜色值。如果这 4 个深度样本中的一些在图元区域之外,那很好;他们不算数。
但是,通过将 FS 调用值与深度采样分开,我们现在遇到了一个问题:在像素区域内 那个单个 FS 调用究竟是在哪里执行的?
这就是我们遇到问题的地方。如果 FS 调用在原语区域之外的位置执行,通常会被丢弃。但是如果任何深度样本在图元的区域内,那么这些深度样本仍然需要获取颜色数据。 MSAA 的全部意义在于不为每个样本执行 FS,因此他们可能会从在不同位置执行的 FS 调用中获取颜色数据。
理想情况下,它将来自在原语区域内的某个位置执行的 FS 调用。但是硬件不能保证这一点。好吧,无论如何,默认情况下它不能保证。如果 FS 位置恰好略微落在基元区域之外,并非每个算法都会出现问题。
但是有些算法确实有问题。这就是为什么我们有 the centroid
qualifier for fragment shader inputs。它确保将在图元区域内生成特定的插值。
您可能已经猜到了,这不是默认值,因为它比非 centroid
插值要慢。所以只在你需要的时候使用它。