似乎无法在片段着色器中乘以某些东西...精度问题?

Can't seem to multiply something in fragment shader...precision issue?

我试图通过 PixiJS 库揭开 webgl 的一些黑暗未知。在这一点上,可能应该注意到我也有一段时间没有使用 PixiJS,但它似乎是比操纵底层 webgl 状态更可取的方法。

我目前的逻辑是这样的: 我使用相同的片段着色器创建两个缓冲区(“当前”和“上一个”)以及一个渲染缓冲区和一个“渲染”片段着色器。两个缓冲区都以相同的内容开始:每个像素的填充都是 rgb(255, 10, 0)。

现在,片段着色器是这样做的:

void main(){
    vec2 pixel = texture2D(buffer, vTextureCoord).xy;
    pixel.x = pixel.x * 0.95; // decrease red a bit
    pixel.y = pixel.y * 1.05; // increase green a bit
    gl_FragColor = vec4(pixel, 0.0, 1.0);
}

在动画循环中,这是应该发生的事情:

  1. 将先前的缓冲区渲染到当前缓冲区
  2. 将当前缓冲区渲染到渲染缓冲区(用于屏幕显示)
  3. 当前和以前的缓冲区被交换:当前缓冲区现在变成以前的缓冲区

因此应该发生的是红色逐渐淡出和绿色逐渐淡入。现在,发生的是红色逐渐淡出为黑色而绿色永远不会淡入。它落在 rgb(9, 10, 0) 上。

通过玩(大量的随机猜测),我发现如果我从更高的绿色开始,比如说 11 或更高它会起作用。或者如果我在着色器中将 'green rate' 增加到 1.06。然后就可以了。但出于某种原因,它不是绿色 10 和 1.05 比率。

我唯一的猜测可能是 GLSL 方面的一些 precision/rounding 问题,但由于我无法追踪着色器中的任何值,所以我真的不知道。我也不知道如何修复它。虽然,相当 possible/probable 我只是在做其他完全错误的事情。

我目前在 jsfiddle 中的内容:https://jsfiddle.net/nfrLjhgk/1/

问题与纹理格式有关。颜色通道使用标准化浮点格式存储在单个字节中。 [0.0, 1.0] 范围内的浮点值映射到 [0, 255] 范围内的整数值。

绿色通道的起始值为10。10 * 1.05为10.5。由于存储在纹理中时该值被截断,因此结果为 10.

最简单的解决方案是更改因数:

pixel.y = pixel.y * 1.05; // increase green a bit

pixel.y = pixel.y * 1.1; // increase green a bit

或者计算一个乘法和加法的最大值:

pixel.y = max(pixel.y * 1.05, pixel.y + 0.005); // increase green a bit

或者,您可以创建一个 WebGL 2.0 上下文并使用不同的纹理格式。