在OpenGL着色器中检测NaN的最佳方法

Ste*_* Lu 17 opengl glsl nan

今天早上我遇到了一个似乎是一个神秘的小虫,我觉得非常幸运,很快就偶然发现了一个解决方案.

我正在用计数器除以产生片段着色器的平均值,当然当计数器为零时,得到的颜色值变为NaN.

在混合期间,NVidia优雅地将NaN视为0值,但英特尔不会并且似乎级联NaN,从而导致黑色碎片.

所以这个bug一直存在,直到我在Intel机器上测试代码.

我想知道我能做些什么来"捕获"无效的值.看起来,就像在常规编程中一样,唯一可靠的(即使那时它也感觉不到防范)处理这种情况的方法是在划分数字时仔细考虑所有可能的情况.

检测NaN的标准方法是查看数字是否与自身不相等.我是否可以构建一个调试着色器来检查每个片段以查看它是否与自身不相等,如果满足该条件,设置一个闪烁的,显眼的颜色?GLSL是否允许我以这种方式检测NaN,或者只要值无效,我是否会遇到未定义的行为?

Nic*_*las 21

我正在用计数器除以产生片段着色器的平均值,当然当计数器为零时,得到的颜色值变为NaN.

这不是浮动的工作方式.除以零,得到INF,而不是NaN.除非分子也为零,否则你会得到NaN.

无论如何,GLSL提供的功能isinfisnan功能完全符合他们的意思.

  • 啊。这很方便。原来它们是 NaN,因为如果分母是,分子将始终为零。 (2认同)

wan*_*len 7

对于WebGL和Opengl ES 2.0,缺少isnan是个问题。适用于所有GPU的Polyfill我有机会尝试过:

bool isnan( float val )
{
  return ( val < 0.0 || 0.0 < val || val == 0.0 ) ? false : true;
  // important: some nVidias failed to cope with version below.
  // Probably wrong optimization.
  /*return ( val <= 0.0 || 0.0 <= val ) ? false : true;*/
}
Run Code Online (Sandbox Code Playgroud)

  • FWIW Java将其定义为 boolean isNaN(float f) {return f != f;}, (3认同)
  • [OpenGL ES GLSL 3+具有`isnan`](https://www.khronos.org/opengles/sdk/docs/man31/)。 (2认同)