GLSL(330)模数返回意外值

时间:2013-05-22 20:49:28

标签: opengl glsl modulo opengl-3

我目前正在使用GLSL 330并遇到了mod()函数的一些奇怪行为。 我在Windows 8下使用Radeon HD 6470M工作。我无法在使用Windows 7和GeForce GTX 260的台式PC上重现这种行为。

这是我的测试代码:

float testvalf = -126;
vec2 testval = vec2(-126, -126);

float modtest1 = mod(testvalf, 63.0);   //returns 63
float modtest2 = mod(testval.x, 63.0);  //returns 63
float modtest3 = mod(-126, 63.0);   //returns 0

编辑:

以下是在IceCools建议之后完成的一些测试结果。

int y = 63;
int inttestval = -126;
ivec2 intvectest(-126, -126);
float floattestval = -125.9;


float modtest4 = mod(inttestval, 63); //returns 63
float modtest5 = mod(intvectest, 63); //returns vec2(63.0, 63.0)
float modtest6 = mod(intvectest.x, 63); //returns 63
float modtest7 = mod(floor(floattestval), 63); //returns 63
float modtest8 = mod(inttestval, y); //returns 63
float modtest9 = mod(-126, y); //returns 63

我更新了我的驱动程序并再次测试,结果相同。再次无法在桌面上重现。 根据{{​​3}}上的GLSL文档,可能的参数组合是(GenType,float)和(GenType,GenType)(没有double,因为我们<4.0)。返回类型也被强制浮动,但这对于这个问题无关紧要。

3 个答案:

答案 0 :(得分:2)

我不知道如果你是按照意图做的,但-126是一个int而不是一个浮点数,而且代码可能没有达到预期的效果。

关于模数的方式: 请注意,调用了两个不同的函数:

前两行:

float mod(float, float);

最后一行:

int mod(int, float);

如果我是对的mod计算如下:

genType mod(genType x, float y){
return x - y*floor(x/y);
}

现在请注意,如果x / y计算-2.0,它将返回0,但如果它的计算结果为-2.00000001,则返回63.0。 int / float和float / float除法之间的差异并非不可能。

所以原因可能只是你正在使用整数和浮点数。

答案 1 :(得分:2)

我想我找到了答案。

我错误的一点是{em> genType 的mangsl关键字并不代表通用类型,就像在c ++模板中一样。

GenType float vec2 vec3 vec4 的简写(参见link - ctrl + f genType )。

Btw genType 命名就像:

genType - floats
genDType - doubles
genIType - ints
genBType - bools 

这意味着genType mod(genType, float)意味着没有像int mod(int, float)这样的功能。

上面的所有代码都在调用float mod(float, float)(幸好有函数参数的隐式类型转换,所以mod(int, int)也可以工作,但实际上调用了mod(float, float)

正如证据:

int x = mod(-126, 63);
Doesn't compile: error C7011: implicit cast from "float" to "int"

它只能起作用,因为它返回float,所以它的工作原理如下:

float x = mod(-126, 63);

因此调用float mod(float, float)

所以我们回到原来的问题:

  • 浮动分割不准确
  • int to float cast不准确
  • 在大多数GPU上应该不是问题,因为如果它们之间的差异小于10 ^ -5(它可能随硬件而异,但我的GPU就是这种情况),则认为浮点数相等。楼(-2.0000001)是-2。 Highp浮标远比这更准确。
  • 因此,要么你没有使用highp浮点数(precision highp float;应该修复它),或者你的GPU对浮点相等性有更严格的限制,或者某些函数返回的准确值不太准确。
  • 如果其他所有方法都失败了,请尝试:

    #extension BlackMagic : enable

答案 2 :(得分:0)

也许某些驱动程序设置强制默认浮点精度为 mediump

如果发生这种情况,您所定义的所有变量都将是 mediump ,但是,代码中输入的数字仍将保持 highp 。 请考虑以下代码:

precision mediump float;
float x = 0.4121551, y = 0.4121552;
x == y; // true
0.4121551 == 0.4121552; // false, as highp they still differ.

因此mod(-126,63.0)仍然可以精确到足以返回正确的值,因为它使用高精度浮点数,但是如果你给出一个变量(就像所有其他情况一样),它只会是 mediump ,该函数没有足够的精度来计算正确的值,当您查看测试时,就会发生这种情况:

  • 至少有一个变量的所有函数都不够精确
  • 唯一需要2个输入数字的函数调用将返回正确的值。