点光源错误Directx 11

时间:2014-06-04 02:41:50

标签: c++ directx-11 lighting

我是Directx 11的新手,我编写了一个距离相关的点光着色器,它对于旋转和翻译的对象非常有效,但是在我尝试缩放模型之后,如果我将模型缩放得更大,则光线变暗如果我缩小模型,照明会变得更亮。我认为它可能是法线,但我确保将它们乘以世界矩阵的逆转置,并确保在插值后在像素着色器中对它们进行归一化。这是着色器代码:

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;
}

我仍然怀疑法线是不正确的,所以我编辑了像素着色器中的最后一行,如果showNorms = 1.0f,则根据法线向量对模型进行着色。法线似乎正确转换。仍然可疑,我用XZ轴上的平面替换了我的模型,并将其缩放了50次。当我渲染它时,光线仍然暗淡,但是当我将showNorms设置为1.0f时,飞机是绿色的,这必然意味着法线都指向向上的Y方向。如果我正确地转换法线并将它们标准化,可能会导致这些灯光错误?

如果这有帮助,那么当我为平面设置常量缓冲区时,这是我的代码:

//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 );

编辑:我稍微更改了代码以修复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;
}

1 个答案:

答案 0 :(得分:1)

我认为你应该尝试在像素着色器中规范化LightDir矢量。如果平面非常大,可能会发生这种情况,即在插入这两个矢量之后,您在像素着色器中得到的矢量不会被标准化。随着规模的增加,这个错误可能会增加。试试看。下图显示了这个问题。

Light vector interpolation problem