WebGL Float 模数行为

WebGL Float modulus behaviour

我遇到以下片段着色器的奇怪行为:

varying vec3 worldSpaceCoords;

uniform float rows;

void main() {

    float testNumber = 7.0;
    vec4 outputColor =  vec4(0.0,0.0,0.0,1.0);

    if(rows == testNumber) {
        if(worldSpaceCoords.x < 0.5) {

            outputColor.x = mod(floor(testNumber * worldSpaceCoords.y), rows ) / rows;

        } else {

            outputColor.x = mod(floor(testNumber * worldSpaceCoords.y), testNumber ) / testNumber;

        }

   } else {

        outputColor  = vec4(1.0,1.0,1.0,1.0);

   }

   gl_FragColor  = outputColor;

}

"testNumber" 变量只是我的控制变量,用于检查传入的制服 "rows" 实际上是它应该是什么。

制服的一些号码 "rows",给出了一个奇怪的行为。下面是一个设置为 9.0 的示例(相应地设置了 testNumber)。

这个结果是意料之中的。但是,将行设置为 7.0(并相应地设置 testNumber),它看起来像这样:

显然有些东西没有正常工作。任何想法为什么?我试过将精度设置为 lowp、mediump 和 highp 没有任何区别。

谢谢

这可能是不精确的浮点数学的结果,它遵循 GLSL ES Specification 中记录的规则。 highp 限定符保证 mod 运算符的输入和输出是 32 位 IEEE 754 浮点数,但是计算本身不能保证产生相同的高精度。特别是,modulus 运算符在第 8.3 章中定义为

genType mod (genType x, genType y)

Modulus. Returns x – y * floor (x/y).

这个表达式中的除法运算符a/b保证精度不低于2.5 ULP for b (参见第 4.5.1 章)并且通常计算为 a*(1/b),因为倒数和乘法比除法便宜。在您的情况下,1/testNumber 是一个编译时常量,可能计算为与 1/rows 不同(更高)的精度,后者需要在 运行 时计算。

您可以尝试使用整数数学而不是浮点数,因为整数 modulus 运算符 a%b 不会遇到此类精度问题。