我刚学习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;
}