0

我看到一些我无法在我编写的 WebGL 着色器中解释的奇怪行为。这对我来说不是一个专业领域,所以我完全有可能误解了一些非常简单的东西,但我不确定是什么。

我有一个代码笔来说明这里的奇怪行为https://codepen.io/bjvanminnen/pen/XqMpvL

void main () {
    vec3 color = vec3(0.);

    vec2 loc1 = vec2(0.5, 0.) / u_res;
    vec2 loc2 = vec2(1.5, 0.) / u_res;
    float val1 = texture2D(u_tex, loc1).r * 255.;
    float val2 = texture2D(u_tex, loc1).r * 255.;
    color.r = val1 == val2 ? 1. : 0.;
    // commenting/uncommenting this line somehow affects the b value
    // on iOS, when uncommented we end up with (53, 0, 255, 255)
    // when commented we end up with (255, 0, 0, 255)
    // I can think of no reason why the below line should affect color.b
    color.r = floor(val1) / 255.;

    color.b = val1 == 53. ? 1. : 0.;      
    gl_FragColor = vec4(color, 1.);
}

正在发生的事情的摘要

  • 在 JS 中,我创建了一个每个像素为 #350000 的纹理

  • 在我的片段着色器中,读取前两个像素

  • 如果两个像素相同(它们应该相同),则最初将输出的 r 值设置为 1

  • 取消注释时,根据 val1 的下限更改 color.r 的值(我不希望影响 color.b 的步骤)

  • 如果像素值为 53(即 0x35),则将输出的 b 值设置为 1。

  • 然后我在 JS 中检查生成的像素值。

我的期望:当第二color.r行被注释掉时,我期望结果为 (53, 0, 255, 255)。这是我在桌面上看到的,但在我的 iOS 设备上看到的是 (53, 0, 0, 255)。似乎 val1 在 iOS 上最终略大于 53。我假设这只是浮点怪异。

超级奇怪,我无法理解的是,当我注释掉第二color.r行时,我的桌面上会出现 (255, 0, 255, 255) - 这是有道理的 - 但我的桌面上会出现 (255, 0, 0, 255) iOS 设备。

换句话说,这条线的存在/不存在color.r = floor(val1) / 255.;以某种方式改变了color.b.

我是否遇到了一些奇怪的 iOS 错误,或者我在这里误解了什么?

4

1 回答 1

2

查看GLSL ES 1.0 规范,从第 4.6 节开始有很多关于不变性的部分

您的案例的重要部分可能是 4.6.2

4.6.2 着色器内的不变性

当一个值存储在一个变量中时,通常假定它将保持不变,除非明确更改。但是,在优化过程中,编译器可能会选择重新计算一个值而不是将其存储在寄存器中。由于运算的精度没有完全指定(例如,低精度运算可以在中等或高精度下进行),重新计算的值可能与原始值不同。

值可以在着色器中变化。为了防止这种情况,必须使用 invariant 限定符或 invariant pragma。

在着色器中,由不同的非常量表达式生成的值没有不变性,即使这些表达式相同。

示例 1:

precision mediump;
vec4 col;
vec2 a = ...
...
col = texture2D(tex, a); // a has a value a1
...
col = texture2D(tex, a); // a has a value a2 where possibly a1 ≠ a2

要在此示例中强制执行不变性,请使用:

#pragma STDGL invariant(all)

示例 2:

vec2 m = ...;
vec2 n = ...;
vec2 a = m + n;
vec2 b = m + n; // a and b are not guaranteed to be exactly equal

没有机制来强制 a 和 b 之间的不变性。

您正在将浮点数与几乎任何语言中似乎很危险的精确值进行比较。如果我改变这条线

color.b = val1 == 53. ? 1. : 0.; 

color.b = val1 > 52.9 && val1 < 53.1 ? 1. : 0.; 

然后它按我的预期工作。另外,如果我写val1出来

color.g = val1 / 153.;

我没有看到它改变。即使您的测试失败,该行是否被注释掉也是 88。这表明在一种情况下它不是 53.0。它是 53.000000000001 或 52.9999999999999 等...

于 2018-05-01T06:36:12.757 回答