Float 不大于、小于或等于 0.,但也不是 NaN 也不是 Infinity

Float is not greater than, lesser than, or equal to 0., but is also not NaN and is not Infinity

从标题来看,我有一个着色器,其中我的浮点数显然不是 NaN,显然不是 Ininity,并且显然不等于、大于或小于 0。什么?

生成这个浮点数的函数是这样的:

float ray1(vec3 rayO, vec3 rayD){
    
    float a = rayD.x;
    float b = rayD.y;
    float c = rayD.z;
    
    float x0 = rayO.x;
    float y0 = rayO.y;
    float z0 = rayO.z;
    
    
    float alpha = 0.1 * ((a * a * c) + (b * b * c));
    float beta = 0.1 * ((a * a * z0) + (2. * x0 * a * c) + (b * b * z0) + (2. * y0 * b * c));
    float gamma = 0.1 * ((2. * x0 * z0 * a) + (x0 * x0 * c) + (2. * y0 * z0 * b) + (y0 * y0 *c)) + (0.6  * c);
    float rho = 0.1 * ((z0 * x0 * x0) + (z0 * y0 * y0)) + (0.6 * z0) + 1.;
    
    float P = -beta / (3. * alpha);
    float Q = (P * P * P) + (((beta * gamma) - (3. * alpha * rho)) / (6. * (alpha * alpha)));
    float R = gamma / (3. * alpha);
    
    float M = (Q * Q) + pow(pow(R - (P * P), 3.), .5);
    
    float t = pow(Q + M, .333) + pow(Q - M, .333) + P;
    
    return t;
}

我把这个传递给它:

float t0 = ray1(vec3(0.), vec3(1.));

当我检查 t0 是什么时(一次一个):

if(isnan(t0)){
    col = vec4(.5);
}
if(t0 <= 0.){
    col = vec4(.5);
}
if(t0 >= 0.){
    col = vec4(.5);
}
if(isinf(t0)){
    col = vec4(.5);
}

他们都是return错误的。

什么是t0?为什么会这样?

更新:我相当确定问题出在 Q 的立方根上,因为当我 return pow(Q, .333); 相反时,它给出了相同的结果。

这似乎是编译器进行了一些积极优化的结果。通过一些代数,您可以确定从这一行开始:

float t = pow(Q + M, .333) + pow(Q - M, .333) + P;

Q的值为-2.5,M的值为7.25。因此,第二个 pow 将产生一个 NaN,整个表达式也是如此,就编译器而言,整个 ray1 函数调用可以被优化掉。

编译器随后似乎优化了 NaN-checking if 语句的事实也可能被视为一个错误,但需要注意的是 WebGL 的实现不是首先需要支持 NaN 。 (请参阅用户 ibesora 在 上的回答。)换句话说,让着色器的行为取决于在编译时保证为 NaN 的值会导致未定义的行为。

为了确认这是optimization-related,我修改了设置M的行如下:

float M = (Q * Q) + pow(pow(R - (P * P), 3.), .5) + (iDate.x - 2022.);

进行此更改后,图像会如您预期的那样变成灰色。