什么可能导致变量表现为无限,同时表现为非无限?

时间:2015-09-21 00:37:57

标签: opengl glsl

要学习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);
}

我的物品变成紫色/洋红色。如果attenuation无限,我希望我的物体看起来是红色的;他们不是无限的,我希望它们看起来是蓝色的;如果它们无论如何都是无限的而不是无限的我会期望它们显得绿色。如果我将result += ...设为result = ...,则对象显示为红色。在这种情况下,如果它是无限的而不是无限的,正如我的紫色物体所暗示的那样,result将首先设置为红色,然后设置为蓝色,从而产生蓝色物体(如果某种方式绿色检查失败)。 / p>

我希望这能描述我困惑的根源。我的测试显示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是一个合理的值。当我把每一个单独作为一种颜色时,对象确实会变成那种颜色。即:使用这个

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

lite.constantlite.linear

,我的物体变成了一些红色

搜索google和堆栈溢出,例如“glsl isinf true and false”或“glsl variable is and not infinite”,这绝对没有相关结果。

我感觉我对这里发生的事情或某些事情的运作方式明显无知。所以我转向你,我错过了一些明显的东西,做错了,或者这是一个真正的谜?

2 个答案:

答案 0 :(得分:0)

我不确定为什么你的衰减如此之大,但你的解释是/不是无限问题很简单 - attenuation的至少一个成分是无限的,而至少有一个其他组件不是。

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

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

答案 1 :(得分:0)

问题在于问题中未显示的代码。 关键信息是我的着色器支持多达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];
  ...

解决了这个问题,现在一切都表现得很完美。似乎不存在的数据既不是无限的,也不是有限的;这在某种程度上是有道理的。