我一直在研究着色器程序,其中一个最奇怪的事情正在发生。 我有一个名为PositionLightPS的方法,它基本上为位置灯(全向和聚光灯)执行计算,并返回一个包含灯光强度和漫反射颜色的结构。
它曾用于该程序的先前版本,但由于某种原因它停止工作......
让我解释一下原因。但首先,这是PositionPS方法的代码。我毫不怀疑这种方法的计算是正确的,但稍后会更多。
struct LightFragment {
float4 diffuse;
float intensity;
};
LightFragment PositionLightPS(PositionLightVOut pin, float3 lightToPixelVec)
{
LightFragment result;
pin.normal = normalize(pin.normal);
float4 diffuse = shaderTexture.Sample( textureSampler, pin.tex0 );
float3 finalDiffuse = float3(0.0f, 0.0f, 0.0f);
float d = length(lightToPixelVec);
if( d > plRange )
{
result.diffuse = float4(finalDiffuse, 0);
result.intensity = 0;
return result;
}
lightToPixelVec /= d;
result.intensity = dot(lightToPixelVec, pin.normal);
if( result.intensity > 0.0f )
{
finalDiffuse = result.intensity * diffuse.xyz;
finalDiffuse.xyz *= clColour.xyz;
finalDiffuse.xyz *= clColour.w;
finalDiffuse /= plAttenuation[0] + (plAttenuation[1] * d) + (plAttenuation[2] * (d*d));
}
result.diffuse = float4(finalDiffuse, diffuse.a) * diffuseColour;
return result;
}
这是全向光像素着色器。
float4 OmniLightDiffusePS(PositionLightVOut pin) : SV_TARGET0
{
float3 lightToPixelVec = plPosition.xyz - pin.worldPos.xyz;
return = PositionLightPS(pin, lightToPixelVec).diffuse;
}
出于某种原因,虽然已经很长时间了,但这不起作用。但这不是我的问题的焦点。奇怪的是,这两种方法会产生不同的结果。
float4 OmniLightDiffusePS(PositionLightVOut pin) : SV_TARGET0
{
//return float4(1,1,1,1);
float3 lightToPixelVec = plPosition.xyz - pin.worldPos.xyz;
LightFragment fragment = PositionLightPS(pin, lightToPixelVec);
return float4(1,1,1,1);
}
这个会返回一个黑色像素
float4 OmniLightDiffusePS(PositionLightVOut pin) : SV_TARGET0
{
return float4(1,1,1,1);
float3 lightToPixelVec = plPosition.xyz - pin.worldPos.xyz;
LightFragment fragment = PositionLightPS(pin, lightToPixelVec);
//return float4(1,1,1,1);
}
这个会返回一个白色像素
所以这意味着调用PositionLightPS方法会对返回的值产生影响......但为什么呢? 为什么会这样?怎么了?这是内存错误吗?
(注意:直接在OmniLightDiffuse方法中复制PositionLightPS方法代码可以解决问题,并且灯光会正常显示。这意味着在PositionLightPS中执行的计算是正确的。问题是, 确实在使用LightFragment结构会以某种方式对着色器程序产生影响 ?)
答案 0 :(得分:2)
我找到了问题的原因。我的计算机使用CUDA并在我不知情的情况下锁定自己使用集成图形芯片。强制NVidia卡解决了这个问题。
但是,我确实找到了这个非常有用的博客文章,详细说明了本质上我的问题。 当两个特定的编译器标志同时处于活动状态 时,调用用户定义函数会导致编译器内联删除它所处理的像素。 我不知道集成图形芯片是否再现了这个确切的错误,但症状似乎完全对应(即调用一个没有发生返回值的函数会改变返回的内容)。
有关详细信息,请参阅Nico Shertler撰写的博客文章链接:http://nicoschertler.wordpress.com/2012/01/02/hlsl-4-calls-to-user-defined-functions-will-crash/
答案 1 :(得分:1)
通常,这是由于零除错误。 ATI和NVIDIA在处理这种NaN方面可能有所不同。检查输入向量的长度,或添加一些epsilon。
答案 2 :(得分:0)
Bjorkes帖子为我提供了解决问题的线索。 我的代码输入了一个自定义函数,该函数返回白色像素(错误),并且调试器不允许我单步执行代码。 罪魁祸首是以下几行。 float4 p = texture.Sample(...) return(float4)(1 / p.x,1 / p.y,1 / p.z,1);
为0个已解决的问题添加检查。