Question

I've added a specular component to my basic light shader and I'm having some problem with specular power. If I set it's value to 0, instead of an expected matte object without specular highlights, I'm getting a weird effect where only directly lit surface is visible, while ambient and diffuse components are ignored.

The image below illustrates this problem:

Globe screenshots

I can still get rid of the specular element by setting specularIntensity to 0, but I assumed setting specularPower to 0 would have the same effect. Below is my pixel shader code and I can't figure out what's wrong with it:

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;
 }
Was it helpful?

Solution

The culprit is this innocent-looking line here:

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

When specularPower is zero, specular always winds up as one because any variable raised to the zero power is 1. So that last globe you're seeing is a view of the specular reflection of all pixels with specular reflection.

But your question asked for help finding a problem in the code. I didn't offer one because, strictly speaking, there isn't one - because there is no problem. It's just a quirk of specularity.

OTHER TIPS

The shader below can trigger undefined behavior. when you end to a computation of pow(0,0) it could result to 0 or NAN according to the documentation : http://msdn.microsoft.com/en-us/library/windows/desktop/bb509636%28v=vs.85%29.aspx

This is because pow(x,y) is implement as exp( y * ln( x ) ).

Once you have a NAN everything is possible on screen, but it often ends as black and this is why a large part of the sphere disappear.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top