2013-05-15 60 views
4

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

改造世界=>切線(面)空間。

這是爲什麼?

回答

3

您需要的線

TBN = transpose(TBN); 

,因爲你從復接到矩陣正確的切空間正常。因此它被認爲是列向量,而基向量在矩陣的行中。所以矩陣必須轉置,可以應用基本轉換。可以省略換位,如果youre切換乘法

float3 worldNormal = mul(tangentNormal, TBN); 

因爲你的相乘的T,N和B向量與您的TBN矩陣從切空間到世界空間變換worldmatrix(TBN變換成對象之後,世界轉變爲世界空間)。其他實現將TBN與世界逆轉置矩陣相乘。通過生成的TBN,您可以將來自世界的光矢量轉換爲切線空間,並將其與正切法線進行比較。所以我認爲那個告訴你TBN將世界切換到切線空間的人使用這種方法(它節省了一些性能,因爲重型矩陣操作是在頂點着色器中完成的)。

+0

+1所以基本上,如果我沒有做轉置,並且只是做了'worldNormal = mul(TBN,tangentNormal)',TBN就像一個矩陣,轉換world => tangent,因爲我將它用作一行主矩陣而不是列主矩陣,對嗎? (因此計算不會返回世界空間中的法線,而是一些奇怪的隨機值) – dk123

+1

只有反轉纔會切換轉換,轉置僅適用於正確的乘法順序。如果沒有轉換,你可以將你的向量映射到一個不需要是正交基的基(例如(1,0,0)將被映射到(TX,BX,NX)),這會導致奇怪的伸展或者可能是無稽之談的結果。但我不是數學家,也許它變成了非常棒的東西;) – Gnietschow

+0

+1謝謝。接下來,我的頂點着色器使用'Output.mPosition = mul(Input.mPosition,gWorldViewProjectionMatrix);'因爲ID3DXBaseEffect :: SetMatrix()傳入的'gWorldProjectionMatrix'的值是一個行主矩陣,對嗎? – dk123