Opengl GLSL(330)模返回意外值

Opengl GLSL(330)模返回意外值,opengl,glsl,modulo,opengl-3,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 = mo

我目前正在使用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
我更新了我的驱动程序并再次测试,结果相同。在桌面上再次无法复制。
根据GLSL文档,可能的参数组合有(GenType,float)和(GenType,GenType)(没有双精度,因为我们小于4.0)。此外,返回类型被强制为浮点型,但这对于这个问题来说并不重要。

我不知道如果您有意这么做,但是-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除法之间的差异并非不可能


因此,原因可能是您正在混合使用int和float

我想我已经找到了答案

我有一个错误是,GoType的关键字并不意味着泛型类型,比如C++模板。

GenType是float、vec2、vec3和vec4的缩写(请参见-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,所以它的工作原理如下:

float x = mod(-126, 63);
因此,调用
float mod(float,float)

因此,我们回到了最初的问题:

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

    #扩展黑魔法:启用


可能某些驱动程序设置强制默认浮点精度为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个键入数字的函数调用返回正确的值

这是一个很好的观点,如果我没有记错的话,我认为我已经测试了(int,int)作为参数,结果相同。不过我可能弄错了。明天我将再次测试它,并将结果作为更新发布。您能测试int x=-126/63是否返回-3吗?这听起来很奇怪,但整数除法并不是那么简单,也许ATI的实现将其降级为浮点除法,并将结果转换回整数。正如我们在modtest1(int)(-126.0/63.0)中看到的那样,-3I刚刚测试了-126/63,通过将其分配给变量和在if子句中测试返回值。两次结果都是-2。我还测试了int(-126.0/63.0)),它也像预期的那样返回-2。我慢慢地想不出主意了,你的浮点精度错误是最合乎逻辑的,我想不出还有什么其他原因可能会导致它。似乎除了精度问题之外,还有其他问题正在发生,因为对于所有可能的精度和所有可能的x和y值,不变量
!(abs(mod(x,y))>=abs(y))
应始终为真。打破,打破了什么模是图形程序。(奇怪的是!…>=对于NaN值也是如此)。非常好的信息,我回家后会研究gpu的浮点精度。如果有相关信息,甚至可以联系AMD的支持服务。但即使精度是答案,这仍然不能解释为什么得到63 für mod(变量,63.0)和0表示mod(-126,63.0)。