Jump to content
  • Advertisement
mister345

DX11 Why won't my falloff work for this dot product based spotlight?

Recommended Posts

I made a spotlight that

1. Projects 3d models onto a render target from each light POV to simulate shadows

2. Cuts a circle out of the square of light that has been projected onto the render target

as a result of the light frustum, then only lights up the pixels inside that circle 

(except the shadowed parts of course), so you dont see the square edges of the projected frustum.

 

After doing an if check to see if the dot product of light direction and light to vertex vector is greater than .95

to get my initial cutoff, I then multiply the light intensity value inside the resulting circle by the same dot product value,

which should range between .95 and 1.0.

 

This should give the light inside that circle a falloff from 100% lit to 0% lit toward the edge of the circle. However,

there is no falloff. It's just all equally lit inside the circle. Why on earth, I have no idea. If someone could take a gander

and let me know, please help, thank you so much.

float CalculateSpotLightIntensity(
    float3 LightPos_VertexSpace, 
    float3 LightDirection_WS, 
    float3 SurfaceNormal_WS)
{
    //float3 lightToVertex = normalize(SurfacePosition - LightPos_VertexSpace);
    float3 lightToVertex_WS = -LightPos_VertexSpace;
    
    float dotProduct = saturate(dot(normalize(lightToVertex_WS), normalize(LightDirection_WS)));

    // METALLIC EFFECT (deactivate for now)
    float metalEffect = saturate(dot(SurfaceNormal_WS, normalize(LightPos_VertexSpace)));
    if(dotProduct > .95 /*&& metalEffect > .55*/)
    {
        return saturate(dot(SurfaceNormal_WS, normalize(LightPos_VertexSpace)));
        //return saturate(dot(SurfaceNormal_WS, normalize(LightPos_VertexSpace))) * dotProduct;
        //return dotProduct;
    }
    else
    {
        return 0;
    }
}

float4 LightPixelShader(PixelInputType input) : SV_TARGET
{
    float2 projectTexCoord;
    float depthValue;
    float lightDepthValue;
    float4 textureColor;

    // Set the bias value for fixing the floating point precision issues.
    float bias = 0.001f;

    // Set the default output color to the ambient light value for all pixels.
    float4 lightColor = cb_ambientColor;

    /////////////////// NORMAL MAPPING //////////////////
    float4 bumpMap = shaderTextures[4].Sample(SampleType, input.tex);

    // Expand the range of the normal value from (0, +1) to (-1, +1).
    bumpMap = (bumpMap * 2.0f) - 1.0f;

    // Change the COORDINATE BASIS of the normal into the space represented by basis vectors tangent, binormal, and normal!
    float3 bumpNormal = normalize((bumpMap.x * input.tangent) + (bumpMap.y * input.binormal) + (bumpMap.z * input.normal));


    //////////////// LIGHT LOOP ////////////////
    for(int i = 0; i < NUM_LIGHTS; ++i)
    {
    // Calculate the projected texture coordinates.
    projectTexCoord.x =  input.vertex_ProjLightSpace[i].x / input.vertex_ProjLightSpace[i].w / 2.0f + 0.5f;
    projectTexCoord.y = -input.vertex_ProjLightSpace[i].y / input.vertex_ProjLightSpace[i].w / 2.0f + 0.5f;

    if((saturate(projectTexCoord.x) == projectTexCoord.x) && (saturate(projectTexCoord.y) == projectTexCoord.y))
    {
        // Sample the shadow map depth value from the depth texture using the sampler at the projected texture coordinate location.
        depthValue = shaderTextures[6 + i].Sample(SampleTypeClamp, projectTexCoord).r;

        // Calculate the depth of the light.
        lightDepthValue = input.vertex_ProjLightSpace[i].z / input.vertex_ProjLightSpace[i].w;

        // Subtract the bias from the lightDepthValue.
        lightDepthValue = lightDepthValue - bias;

        float lightVisibility = shaderTextures[6 + i].SampleCmp(SampleTypeComp, projectTexCoord, lightDepthValue );

        // Compare the depth of the shadow map value and the depth of the light to determine whether to shadow or to light this pixel.
        // If the light is in front of the object then light the pixel, if not then shadow this pixel since an object (occluder) is casting a shadow on it.
            if(lightDepthValue < depthValue)
            {
                // Calculate the amount of light on this pixel.
                float lightIntensity = saturate(dot(bumpNormal, normalize(input.lightPos_LS[i])));

                if(lightIntensity > 0.0f)
                {
                    // Determine the final diffuse color based on the diffuse color and the amount of light intensity.
                    float spotLightIntensity = CalculateSpotLightIntensity(
                        input.lightPos_LS[i], // NOTE - this is NOT NORMALIZED!!!
                        cb_lights[i].lightDirection, 
                        bumpNormal/*input.normal*/);

                    lightColor += cb_lights[i].diffuseColor*spotLightIntensity* .18f; // spotlight
                    //lightColor += cb_lights.diffuseColor*lightIntensity* .2f; // square light
                }
            }
        }
    }

    // Saturate the final light color.
    lightColor = saturate(lightColor);
   // lightColor = saturate( CalculateNormalMapIntensity(input, lightColor, cb_lights[0].lightDirection));

    // TEXTURE ANIMATION -  Sample pixel color from texture at this texture coordinate location.
    input.tex.x += textureTranslation;

    // BLENDING
    float4 color1 = shaderTextures[0].Sample(SampleTypeWrap, input.tex);
    float4 color2 = shaderTextures[1].Sample(SampleTypeWrap, input.tex);
    float4 alphaValue = shaderTextures[3].Sample(SampleTypeWrap, input.tex);
    textureColor = saturate((alphaValue * color1) + ((1.0f - alphaValue) * color2));

    // Combine the light and texture color.
    float4 finalColor = lightColor * textureColor;

    /////// TRANSPARENCY /////////
    //finalColor.a = 0.2f;

    return finalColor;
}

 

Light_vs.hlsl

Light_ps.hlsl

Share this post


Link to post
Share on other sites
Advertisement

Hi,

Those calculations seem correct at first glance. But something is missing. With only a dot(normal, lightDirection) you won't get a smooth spotlight attenuation for the cutoff. You also want to calculate a spotlight attenuation factor. My code:

float3 L = light.worldPosition - surfaceWorldPosition; // light-vector
float dist = length(L); // distance from surface to light

float SpotFactor = dot(L, light.directionWorldSpace); // spotlight lookAt vector
float spotCutOff = light.coneAngleCos; // cos(spotLightFieldOfView)

// ...

// pointlight-like attenuation factor
float att = (light.energy * (light.range / (light.range + 1 + dist)));
float attenuation = (att * (light.range - dist) / light.range);

// spotlight-specific attenuation factor:
// this is resposible for smooth gradient of spotlight cutoff circle
attenuation *= saturate((1.0 - (1.0 - SpotFactor) * 1.0 / (1.0 - spotCutOff)));

diffuse *= attenuation;
specular *= attenuation;

In the above code, spotCutoff would be your hardcoded 0.95 value, SpotFactor is your "dotProduct" valriable. Good luck!

Share this post


Link to post
Share on other sites
18 hours ago, turanszkij said:

Hi,

Those calculations seem correct at first glance. But something is missing. With only a dot(normal, lightDirection) you won't get a smooth spotlight attenuation for the cutoff. You also want to calculate a spotlight attenuation factor. My code:


float3 L = light.worldPosition - surfaceWorldPosition; // light-vector
float dist = length(L); // distance from surface to light

float SpotFactor = dot(L, light.directionWorldSpace); // spotlight lookAt vector
float spotCutOff = light.coneAngleCos; // cos(spotLightFieldOfView)

// ...

// pointlight-like attenuation factor
float att = (light.energy * (light.range / (light.range + 1 + dist)));
float attenuation = (att * (light.range - dist) / light.range);

// spotlight-specific attenuation factor:
// this is resposible for smooth gradient of spotlight cutoff circle
attenuation *= saturate((1.0 - (1.0 - SpotFactor) * 1.0 / (1.0 - spotCutOff)));

diffuse *= attenuation;
specular *= attenuation;

In the above code, spotCutoff would be your hardcoded 0.95 value, SpotFactor is your "dotProduct" valriable. Good luck!

Thanks, will try it out!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!