c – HLSL法线映射矩阵乘法
我目前正在使用directx9,并为我的法线贴图提供以下代码:
(顶点着色器): 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); } 代码有效,但我不太明白为什么我需要这样做 TBN =转置(TBN);在像素着色器中. 我通过顶点着色器的TBN值是那些在世界空间中的值(因此为什么我乘以gWorldMatrix),但我被告知 float3x3 TBN = float3x3(normalize(Input.T), 转换world =>切线(曲面)空间. 为什么是这样? 解决方法
你需要这条线
TBN = transpose( TBN ); 因为你正在将你的切线空间法线从右边乘以矩阵.因此,它被视为列向量,而基本向量位于矩阵的行中.因此必须转置矩阵,可以应用基本变换.如果要将乘法切换为,则可以省略转置 float3 worldNormal = mul( tangentNormal,TBN ); 因为你将T,N和B向量与世界矩阵相乘,你的TBN矩阵从切线空间转换到世界空间(TBN转换为对象空间,之后世界转换为世界空间).其他实现将TBN与世界逆转置矩阵相乘.使用生成的TBN,您可以将光矢量从世界转换为切线空间,并将其与切线法线进行比较.所以我认为那个告诉你TBN将世界转换为切线空间的人使用这种方法(它节省了一些性能,因为重型矩阵操作是在顶点着色器中完成的). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |