【问题标题】:Inexplicable behavior in WebGL shader on iOSiOS 上 WebGL 着色器中的莫名行为
【发布时间】:2018-05-01 22:36:51
【问题描述】:

我看到一些我无法在我编写的 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 错误,或者我在这里误解了什么?

【问题讨论】:

    标签: ios glsl webgl regl


    【解决方案1】:

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

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

    4.6.2 着色器内的不变性

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

    值可以在着色器中变化。为了防止这种情况,不变量限定符或不变量 必须使用 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 等...

    【讨论】:

    • 谢谢!了解着色器不变性非常有趣。添加编译指示使我达到了没有出现这种意外行为的地步。
    猜你喜欢
    • 2020-07-21
    • 2014-03-24
    • 1970-01-01
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多