3

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

这是我的测试代码:

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

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

4

3 回答 3

3

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

顺便说一下模数:请注意,调用了 2 个不同的函数:

前两行:

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 除法之间的差异并非不可能。

因此,原因可能只是您混合使用了整数和浮点数。

于 2013-05-22T21:16:46.863 回答
2

我想我已经找到了答案。

我一直错的一件事是mangsl的genType关键字并不意味着泛型类型,就像在 c++ 模板中一样。

GenTypefloatvec2vec3vec4的简写(参见链接- ctrl+f genType)。

顺便说一句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 x = mod(-126, 63);

因此float mod(float, float)被称为。

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

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

    #extension BlackMagic : enable

于 2013-05-24T10:40:19.097 回答
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 个类型数字的函数调用返回正确的值。
于 2013-05-24T20:12:02.777 回答