我目前在DirectX9的工作,有我的法线贴图如下代码:HLSL法线贴图矩阵乘法
(顶点着色器):
float4x4 gWorldMatrix;
float4x4 gWorldViewProjectionMatrix;
float4 gWorldLightPosition;
float4 gWorldCameraPosition;
struct VS_INPUT
{
float4 mPosition : POSITION;
float3 mNormal: NORMAL;
float3 mTangent: TANGENT;
float3 mBinormal: BINORMAL;
float2 mUV: TEXCOORD0;
};
struct VS_OUTPUT
{
float4 mPosition : POSITION;
float2 mUV: TEXCOORD0;
float3 mLightDir: TEXCOORD1;
float3 mViewDir: TEXCOORD2;
float3 T: TEXCOORD3;
float3 B: TEXCOORD4;
float3 N: TEXCOORD5;
};
VS_OUTPUT vs_main(VS_INPUT Input)
{
VS_OUTPUT Output;
Output.mPosition = mul(Input.mPosition, gWorldViewProjectionMatrix);
Output.mUV = Input.mUV;
float4 worldPosition = mul(Input.mPosition, gWorldMatrix);
float3 lightDir = worldPosition.xyz - gWorldLightPosition.xyz;
Output.mLightDir = normalize(lightDir);
float3 viewDir = normalize(worldPosition.xyz - gWorldCameraPosition.xyz);
Output.mViewDir = viewDir;
//object space=>world space
float3 worldNormal = mul(Input.mNormal, (float3x3)gWorldMatrix);
Output.N = normalize(worldNormal);
float3 worldTangent = mul(Input.mTangent, (float3x3)gWorldMatrix);
Output.T = normalize(worldTangent);
float3 worldBinormal = mul(Input.mBinormal, (float3x3)gWorldMatrix);
Output.B = normalize(worldBinormal);
return Output;
}
(像素着色器)
struct PS_INPUT
{
float2 mUV : TEXCOORD0;
float3 mLightDir: TEXCOORD1;
float3 mViewDir: TEXCOORD2;
float3 T: TEXCOORD3;
float3 B: TEXCOORD4;
float3 N: TEXCOORD5;
};
sampler2D DiffuseSampler;
sampler2D SpecularSampler;
sampler2D NormalSampler;
float3 gLightColor;
float4 ps_main(PS_INPUT Input) : COLOR
{
//read normal from tex
float3 tangentNormal = tex2D(NormalSampler, Input.mUV).xyz;
tangentNormal = normalize(tangentNormal * 2 - 1); //convert 0~1 to -1~+1.
//read from vertex shader
float3x3 TBN = float3x3(normalize(Input.T), normalize(Input.B),
normalize(Input.N)); //transforms world=>tangent space
TBN = transpose(TBN); //transform tangent space=>world
float3 worldNormal = mul(TBN, tangentNormal); //note: mat * scalar
//(since TBN is row matrix)
float3 lightDir = normalize(Input.mLightDir);
float3 diffuse = saturate(dot(worldNormal, -lightDir));
float4 albedo = tex2D(DiffuseSampler, Input.mUV);
diffuse = gLightColor * albedo.rgb * diffuse;
float3 specular = 0;
if (diffuse.x > 0)
{
float3 reflection = reflect(lightDir, worldNormal);
float3 viewDir = normalize(Input.mViewDir);
specular = saturate(dot(reflection, -viewDir));
specular = pow(specular, 20.0f);
//further adjustments to specular (since texture is 2D)
float specularIntensity = tex2D(SpecularSampler, Input.mUV);
specular *= specularIntensity * gLightColor;
}
float3 ambient = float3(0.1f, 0.1f, 0.1f) * albedo;
return float4(ambient + diffuse + specular, 1);
}
该代码有效,但我不太明白为什么我需要做
TBN = transpose(TBN);
在像素着色器中。
的TBN值我从顶点着色器传递是那些在世界空间(所以为什么我乘gWorldMatrix),但有人告诉我
float3x3 TBN = float3x3(normalize(Input.T), normalize(Input.B), normalize(Input.N));
改造世界=>切线(面)空间。
这是为什么?
+1所以基本上,如果我没有做转置,并且只是做了'worldNormal = mul(TBN,tangentNormal)',TBN就像一个矩阵,转换world => tangent,因为我将它用作一行主矩阵而不是列主矩阵,对吗? (因此计算不会返回世界空间中的法线,而是一些奇怪的随机值) – dk123
只有反转才会切换转换,转置仅适用于正确的乘法顺序。如果没有转换,你可以将你的向量映射到一个不需要是正交基的基(例如(1,0,0)将被映射到(TX,BX,NX)),这会导致奇怪的伸展或者可能是无稽之谈的结果。但我不是数学家,也许它变成了非常棒的东西;) – Gnietschow
+1谢谢。接下来,我的顶点着色器使用'Output.mPosition = mul(Input.mPosition,gWorldViewProjectionMatrix);'因为ID3DXBaseEffect :: SetMatrix()传入的'gWorldProjectionMatrix'的值是一个行主矩阵,对吗? – dk123