0

我一直在研究一个着色器程序,而最奇怪的事情之一正在发生。我有一个名为 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结构体对shader程序有影响吗不知何故?)

4

3 回答 3

2

我找到了问题的原因。我的电脑使用 CUDA 并在我不知情的情况下将自己锁定为使用集成图形芯片。强制 NVidia 卡解决了这个问题。

但是,我确实发现这篇非常有用的博客文章详细说明了我的问题所在。当两个特定的编译器标志同时激活时,调用用户定义函数会导致编译器的内联删除它处理的像素。我不知道集成图形芯片是否重现了这个确切的错误,但症状似乎完全对应(即调用返回值没有发生的函数将改变返回的内容)。

有关更多详细信息,请参阅 Nico Shertler 的博客文章链接:http: //nicoschertler.wordpress.com/2012/01/02/hlsl-4-calls-to-user-defined-functions-will-crash /

于 2012-12-07T20:40:33.213 回答
1

通常,这是由于被零除错误造成的。ATI 和 NVIDIA 在处理这个 NaN 方面可能有所不同。检查输入向量的长度,或添加一些 epsilon。

于 2012-12-07T02:06:46.983 回答
0

Bjorkes 的帖子给了我解决问题的线索。我的代码输入了一个自定义函数,该函数返回了一个白色像素(错误),并且调试器不允许我单步执行代码。罪魁祸首是下面一行。float4 p = texture.Sample(...) return (float4)(1 / px, 1 / py, 1 / pz, 1);

添加检查 0 已解决的问题。

于 2020-02-11T20:32:49.330 回答