是什么导致一个变量表现得像无限的同时又像非无限的?

What could cause a variable to behave as infinite and simultaneously as non-infinite?

为了学习 opengl,我正在使用 openGL 3.3 创建一个简单的 3D 图形引擎。我最近添加了随距离的光衰减;这已将所有对象完全变黑。这是通过将以下代码添加到我在片段着色器中的光照计算中完成的:

float distance = length(lite.position - FragPos);
float attenuation = 1.0f/(lite.constant + (lite.linear * distance) + (lite.quadratic * (distance * distance)));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;

result += (ambient + diffuse + specular);

似乎可以安全地假设 attenuation 非常小,实际上或实际上为 0,或负数(黑色)。为了测试这一点,我使用 result += vec3(attenuation);,结果是白色物体;这表明 attenuation 不接近 0,而是 1.0 或更大;尝试 result += vec3(attenuation/500000); 的额外测试仍然产生白色,这表明衰减非常大,可能是无限的。我对它做了一些无穷大和 NaN 检查。 NaN 检查告诉我这是一个数字,无穷大检查告诉我它有时是无限的,有时不是。事实上,它告诉我它既是无限的又不是无限的。我通过使用以下代码段确定了这一点:

if(isinf(attenuation)){
  result += vec3(1.0, 0.0, 0.0);
}
if(isinf(attenuation) && !isinf(attenuation)){
  result += vec3(0.0, 1.0, 0.0);
}
if(!isinf(attenuation)){
  result += vec3(0.0, 0.0, 1.0);
}

我的对象变成了 purple/magenta。如果 attenuation 是无限的,我希望我的对象显示为红色;如果它们不是无限的,我希望它们呈现蓝色;如果它们不知何故既无限又不是无限,我希望它们看起来是绿色的。如果我将 result += ... 设为 result = ...,则对象显示为红色。在这种情况下,如果它既是无限又不是无限,正如我的紫色对象所暗示的那样,result 将首先设置为红色,然后设置为蓝色,从而导致蓝色对象(如果绿色检查以某种方式失败)。

我希望这描述了我困惑的根源。我的测试表明 attenuation 是无限的,它不是无限的,而且两者都不是。

在我使用时把所有东西都顶起来:

float attenuation = 1.0f/(1.0 + (0.0014 * distance) + (0.000007* (distance * distance)));

为了确定衰减系数,一切都按预期工作;然而,此处显示为常量的值正是从我的 openGL 调用 (c++) 传入的值:

glUniform1f(lightConstantLoc,  1.0f);
glUniform1f(lightLinearLoc,    0.0014f);
glUniform1f(lightQuadraticLoc, 0.000007f);

从那里我应该得出结论,我的数据没有正确地传递到我的着色器,但是我相信我的 lite.constant 等值已正确设置,并且 distance 是一个合理的价值。当我将每一个单独作为一种颜色时,对象确实会变成 color.i.e.: 使用 this

result = vec3(lite.constant, 0.0, 0.0);

我的对象变成了一些红色阴影,lite.constantlite.linear

搜索 google 和堆栈溢出 "glsl isinf true and false" 或 "glsl variable is and isn't infinite" 之类的东西绝对没有给我相关的结果。

我觉得我对这里发生的事情或事情的运作方式一无所知。所以我求助于你,我是不是漏掉了一些明显的东西,做错了,还是这是一个真正的谜?

我不确定为什么你的衰减这么大,但你的 is/isn 不是无限问题的解释很简单—— attenuation 的至少一个分量是无限的,而在至少有一个其他组件不是。

当您执行 if (bvec) 时——测试一个布尔向量而不是单个布尔值的条件——它就像您执行 if (any(bvec)) 一样。因此,如果任何组件为真,它将执行关联的真分支。当你有 isinf(attenuation) 时,你会得到一个布尔向量。例如,如果红色是无限的而其他的不是,你会得到 (true, false, false)。所以!isinf(attenuation)会是(false,true,true),中间&&的结果if就是(false,false,false).

所以它执行第一个和第三个 if(而不是第二个),给你洋红色。

问题在于问题中没有显示的代码。 关键信息是我的着色器最多支持 5 个光源,并遍历所有 5 个光源;即使提供的光源少于 5 个。考虑到这一点,改变

vec3 result = vec3(0.0);
for(int i = 0; i < 5; ++i){
  Light lite = light[i];
  ...

vec3 result = vec3(0.0);
for(int i = 0; i < 1; ++i){
  Light lite = light[i];
  ...

问题已解决,现在一切正常。似乎不存在的数据既不是无限的也不是有限的;这在某种程度上是有道理的。