c++ - 点光照错误 Directx 11

标签 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 时基于法线 vector 对模型进行着色。法线看起来像是被正确地转换了。仍然怀疑,我用 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;
}

最佳答案

我认为您也应该尝试在像素着色器中标准化 LightDir vector 。如果平面真的很大,可能会发生这两个 vector 插值后,您在像素着色器中获得的 vector 未归一化。随着规模的增加,这个错误可能会增加。试一试。下图显示了这个问题。

Light vector interpolation problem

关于c++ - 点光照错误 Directx 11,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24028112/

相关文章:

c++ - 多个对象,不同的行为

java - java 远处的 Sprite 变暗

c++ - 我应该使用 GetDisplayModeList 中的哪种刷新率?

java - OpenGL 延迟着色照明无法正常工作

Three.js ShaderMaterial 照明不起作用

c++ - 确定 Qt 库链接

c++ - 接口(interface)(抽象类)设计的最佳方法?

c++ - 运算符重载错误不匹配运算符<<

c++ - 在可变数量的标记碱基上进行模板化

c++ - 如何使用 CheckMultisampleQualityLevels 并启用多重采样