像素着色器中的镜面反射功率为零会消除环境和漫反射

时间:2014-01-29 18:04:44

标签: directx direct3d hlsl lighting

我在我的基本灯光着色器中添加了一个镜面反射分量,我在镜面反射方面遇到了一些问题。如果我将它的值设置为0,而不是没有镜面高光的预期遮罩对象,我会得到一个奇怪的效果,只有直接照亮的表面可见,而环境和漫反射组件被忽略。

下图说明了这个问题:

Globe screenshots

我仍然可以通过将specularIntensity设置为0来摆脱镜面反射元素,但我假设将specularPower设置为0会产生相同的效果。下面是我的像素着色器代码,我无法弄清楚它有什么问题:

float4 LightPixelShader(PixelInputType input) : SV_Target
{   
    float4 specular;

    // Sample the pixel color from the texture using the sampler at this texture coordinate location.
    float4 textureColor = shaderTexture.Sample(SampleType, input.tex);

    // Set default output color to ambient light value for all pixels
    float4 color = ambientColor;

    // Invert the light direction for calculations.
    float3 lightDir = -lightDirection;

    // Calculate the amount of light on this pixel.
    float lightIntensity = saturate(dot(input.normal, lightDir));

    if (lightIntensity > 0.0f)
    {
        // Determine final diffuse color
        color += (diffuseColor * lightIntensity);

        // Saturate ambient and diffuse color
        color = saturate(color);

        // Calculate the reflection vector based on the light intensity, normal vector and light direction
        float3 reflection = normalize(2 * dot(lightDir, input.normal) * input.normal     - lightDir);

        // Determine the amount of specular light based on the reflection vector, viewing direction and specular power
        specular = specularIntensity * specularColor * pow(saturate(dot(reflection, normalize(input.viewDirection))), specularPower);
    }

    // Saturate the final color in case it's greater then 1
    color = saturate(color);

    // Multiply the texture pixel and the final diffuse color to get the final pixel color result.
    color = color * textureColor;

    // Add the specular component
    color = saturate(color + specular);

    return color;
 }

2 个答案:

答案 0 :(得分:3)

罪魁祸首就是这条天真无邪的路线:

specular = specularIntensity * specularColor * pow(saturate(dot(reflection, normalize(input.viewDirection))), specularPower);

specularPower为零时,specular总是最终为一,因为任何提升到零功率的变量都是1.所以你看到的最后一个地球是所有镜面反射的视图具有镜面反射的像素。

但是你的问题要求帮助在代码中找到问题。我没有提供一个,因为严格来说,没有一个 - 因为没有问题。这只是镜面反射的一个怪癖。

答案 1 :(得分:1)

下面的着色器可以触发未定义的行为。当你结束pow(0,0)的计算时,根据文档可能会得到0或NAN:http://msdn.microsoft.com/en-us/library/windows/desktop/bb509636%28v=vs.85%29.aspx

这是因为pow(x,y)实现为exp(y * ln(x))。

一旦你有了NAN,屏幕上就可以看到一切,但它通常以黑色结束,这就是为什么球体的大部分消失了。