我目前在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