HLSL Shader:调用函数更改返回值

问题描述 投票:0回答:3

我一直在从事着色器程序,最奇怪的事情之一正在发生。我有一个称为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结构是否具有对着色器程序的影响?)

struct directx shader hlsl
3个回答
2
投票

我找到了问题的原因。我的计算机使用CUDA,并在不知情的情况下锁定使用集成的图形芯片。强制使用NVidia卡解决了该问题。

但是,我确实发现了这篇非常有用的博客文章,其中详细说明了本质上是我的问题。 当两个特定的编译器标志同时处于活动状态时,调用用户定义函数会使编译器内联删除所处理的像素。我不知道集成图形芯片是否再现了这个确切的错误,但症状似乎完美对应(即,调用返回值没有影响的函数会改变返回的内容)。

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


1
投票

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


0
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.