在webgl中,如果输入来自int统一,则mod函数在片段着色器中给出不正确的结果

问题描述

我遇到了奇怪的事情。如果我将一个int统一设置为传递给片段着色器,然后在着色器中对其进行一些数学运算,则得到的结果与将着色器内部的int变量设置为相同值时会得到不同的结果。

我做了一个测试用例来演示,转到 https://shaderfrog.com/app/view/4630 它将渲染带有蓝色条的绿色矩形。 向下滚动到制服,并将tileXSize设置为28。 该栏应变为红色。这意味着当我执行56 mod 28时,答案会返回为28,我希望该数值为0。 如果取消注释第44行,则将着色器内部的int设置为28,则数学运算似乎正确,并且显示白色条。

(蓝色条表示输入不是28,因此确认当我们获得红色或白色条时实际上已将其设置为28)。

我在做什么错/我误解了什么?我干了什么事,还是发现了一些极端情况?

解决方法

这似乎是由于浮点舍入误差引起的。
如果添加另一个测试。例如。
这是真的。

if(test <= 28.0) {
  gl_FragColor = vec4(0.0,0.0,1.0);       // black
}

但是..
这将是错误的。

if(test <= 27.9) {
  gl_FragColor = vec4(0.0,1.0);       // black
}

所以这个数字在27.9和28.0之间

,

如果通过统一的testint设置了tileXSize,则数学运算将由GPU完成,可能使用单精度浮点精度。 mod可能以某种巧妙的方式实现,可以提高性能但降低准确性。

在片段着色器中对testint进行硬编码时,着色器编译器将意识到该表达式可以在编译时评估一次,而不是每个像素评估一次。编译时的评估将在CPU上完成,并且结果略有不同。很难知道为什么会精确地进行数学运算(例如,双精度浮点运算),或者可能会发现mod的两个参数都是整数,并使用整数数学运算而不是浮点数进行计算,也许只是因为它是不同的数学库或不同的处理器。

This是一篇很棒的文章,介绍了用浮点数测试相等性的风险和替代方法。浮点运算的一般规则是,您将对大多数计算获得极为准确的答案,但通常不应期望精确答案。