Sully Chen
Sully Chen

Reputation: 339

Point Lighting Error Directx 11

I'm new to Directx 11, and I programmed a distance dependent point light shader that works pretty well for rotated and translated objects, but after I tried scaling my models, the lighting got dimmer if I scaled the model larger, and the lighting got brighter if I scaled the model smaller. I thought it might be the normals, but I made sure to multiply them by the inverse transpose of the world matrix, and I made sure to normalize them in the pixel shader after they are interpolated. Here is the shader code:

Texture2D txDiffuse : register( t0 );
SamplerState samAnisotropic
{
    Filter = ANISOTROPIC;
    MaxAnisotropy = 4;
};

cbuffer ConstantBuffer : register( b0 )
{
    matrix World;
    matrix View;
    matrix Projection;
    matrix WorldInvTrans;
    float3 LightPos;
    float pad1;
    float3 EyePos;
    float pad2;
    float3 At;
    float pad3;
    float showNorms;
}


struct VS_INPUT
{
    float4 Pos : POSITION;
    float3 Norm : NORMAL;
    float2 TexCoor : TEXCOORD0; 
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float3 Norm : NORMAL;
    float3 LightDir : POSITION0;
    float3 EyeVector : POSITION1;
    float2 TexCoor : TEXCOORD0;
    float distance : FLOAT0;
    float showNorms : FLOAT1;

};

PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = mul( input.Pos, World );
    output.LightDir = normalize( LightPos - output.Pos );
    output.EyeVector = normalize( EyePos - At );
    output.distance = distance( LightPos, output.Pos);
    output.Pos = mul( output.Pos, View );
    output.Pos = mul( output.Pos, Projection );
    output.Norm = mul( input.Norm, WorldInvTrans );
    output.TexCoor = input.TexCoor;
    output.showNorms = showNorms;

    return output;
}

float4 PS( PS_INPUT input) : SV_Target
{
    input.Norm = normalize( input.Norm );

    float specTerm = 0;

    float3 ReflVector = normalize( reflect( input.LightDir, input.Norm ) );

    [flatten]
    if ( dot( ReflVector, input.EyeVector ) >= 0 )
    {
        specTerm = pow(  dot( ReflVector, input.EyeVector ) , 50 );
    }
    float diffuseTerm = saturate( dot( input.LightDir, input.Norm ) );
    float4 ambient = float4( 0.25f, 0.25f, 0.25f, 1.0f );
    float4 lightColor = float4( 1.0f, 1.0f, 1.0f, 1.0f );
    return ( (ambient + (diffuseTerm + specTerm) / (pow( input.distance, 1 ) * 0.025f)) * lightColor * txDiffuse.Sample( samAnisotropic, input.TexCoor ) ) * ( 1 - input.showNorms ) + float4( input.Norm, 1.0f ) * input.showNorms;
}

I was still suspicious that the normals weren't correct, so I edited the last line in my pixel shader to shade the model based on the normal vectors if showNorms = 1.0f. The normals looked like they were transformed correctly. Still suspicious, I replaced my model with a plane on the XZ axis, and scaled it up 50 times. When I rendered it, the lighting was still dim, but the plane was green when I set showNorms to 1.0f, which must mean that the normals are all pointing in the upwards Y direction. If I'm transforming my normals correctly and normalizing them, what could be causing these lighting errors?

If this helps, here is my code when I set the constant buffers for the plane:

//Render Plane
    mWorld = XMMatrixIdentity();
    cb1.mWorld = XMMatrixTranspose( XMMatrixMultiply( XMMatrixMultiply( mWorld, XMMatrixScaling( 50.0f, 1.0f, 50.0f ) ), XMMatrixTranslation( 0.0f, -5.0f, 0.0f ) ) );
    XMMATRIX A = cb1.mWorld;
    A.r[3] = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f);

det = XMMatrixDeterminant(A);
cb1.mWorldInvTrans = XMMatrixInverse(&det, A);

g_pImmediateContext->UpdateSubresource( g_pcBufferShader1, 0, NULL, &cb1, 0, 0 );

Edit: I changed the code a little bit to fix the specTerm:

Texture2D txDiffuse : register( t0 );
SamplerState samAnisotropic
{
    Filter = ANISOTROPIC;
    MaxAnisotropy = 4;
};

cbuffer ConstantBuffer : register( b0 )
{
    matrix World;
    matrix View;
    matrix Projection;
    matrix WorldInvTrans;
    float3 LightPos;
    float pad1;
    float3 EyePos;
    float pad2;
    float3 At;
    float pad3;
    float showNorms;
}


struct VS_INPUT
{
    float4 Pos : POSITION;
    float3 Norm : NORMAL;
    float2 TexCoor : TEXCOORD0; 
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float3 Norm : NORMAL;
    float3 LightDir : POSITION0;
    float3 EyeVector : POSITION1;
    float2 TexCoor : TEXCOORD0;
    float distance : FLOAT0;
    float showNorms : FLOAT1;

};

PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = mul( input.Pos, World );
    output.LightDir = LightPos - output.Pos;
    output.EyeVector = EyePos - At;
    output.distance = distance( LightPos, output.Pos );
    output.Pos = mul( output.Pos, View );
    output.Pos = mul( output.Pos, Projection );
    output.Norm = mul( input.Norm, WorldInvTrans );
    output.TexCoor = input.TexCoor;
    output.showNorms = showNorms;

    return output;
}

float4 PS( PS_INPUT input) : SV_Target
{
    input.Norm = normalize( input.Norm );
    input.LightDir = normalize( input.LightDir );
    input.EyeVector = normalize( input.EyeVector );

    float specTerm = 0;

    float3 ReflVector = normalize( reflect( -input.LightDir, input.Norm ) );

    [flatten]
    if ( dot( ReflVector, input.EyeVector ) >= 0 )
    {
        specTerm = pow(  dot( ReflVector, input.EyeVector ) , 50 );
    }
    float diffuseTerm = saturate( dot( input.LightDir, input.Norm ) );
    float4 ambient = float4( 0.25f, 0.25f, 0.25f, 1.0f );
    float4 lightColor = float4( 1.0f, 1.0f, 1.0f, 1.0f );
    return ( (ambient + (diffuseTerm + specTerm) / (pow( input.distance, 1 ) * 0.025f)) * lightColor * txDiffuse.Sample( samAnisotropic, input.TexCoor ) ) * ( 1 - input.showNorms ) + float4( input.Norm, 1.0f ) * input.showNorms;
}

Upvotes: 3

Views: 608

Answers (1)

Elvithari
Elvithari

Reputation: 834

I think you should try to normalize the LightDir vector in the pixel shader as well. If the plane is really large it may happen, that after the interpolation of these two vectors, the vector you get in the pixel shader is not normalized. This error is likely to increase as the scale goes up. Give it a try. The picture below shows this problem.

Light vector interpolation problem

Upvotes: 1

Related Questions