Standard HLSL matrix scaling

I am currently working in directx9 and have the following code for my normal display:

(Vertex Shader):

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; } 

(pixel shader)

 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); } 

The code works, but I don’t quite understand why I need to do

TBN = transpose( TBN ); in the pixel shader.

The TBN values ​​passed through the Vertex Shader are those that are in world space (so I multiplied gWorldMatrix), but they tell me that

float3x3 TBN = float3x3( normalize(Input.T), normalize(Input.B), normalize(Input.N) );

transforms world => tangent (surface) space.

Why is this?

+4
source share
1 answer

You need a string

 TBN = transpose( TBN ); 

because you are multiplying the normal tangent space on the right by the matrix. Therefore, it is considered as a column vector, and the basic vectors are in the rows of the matrix. Thus, the matrix must be transposed so that the basic transformation can be applied. You can omit the transpose if you switch the multiplication to

 float3 worldNormal = mul( tangentNormal, TBN ); 

Since yours has multiplied the vector T, N, and B with the worldmatrix, your TBN matrix is ​​transformed from tangent space to world space (TBN is transformed into space of objects after this world is transformed into world space). Other implementations multiply TBN by the world inverse transpose matrix. With the resulting TBN, you can convert the light vector from the world to the tangent space and compare it with the tangent normal. Therefore, I think that the one who told you that TBN transforms the world into tangent space uses this approach (it retains some performance because heavy operations with matrices are performed in vertexshader).

+3
source

Source: https://habr.com/ru/post/1480828/


All Articles