切線空間,即使用頂點的切線作為x軸,法線作為z軸,法線與切線的叉積作為y軸。
使用切線空間存儲法線,使得法線紋理可以復用,很好。
在切線空間中計算光照,比在世界空間中計算光照少了很多計算量。在切線空間中計算,需要在頂點中將光線和視角方向轉換到切線空間中,而在世界空間中計算時需要在每個片段中將法線從切線空間轉換到界面空間。
shader如下:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Custom/Normal map tangent space" { Properties { _MainTex("Main texture", 2D) = "white" _NormalMap("Normal map", 2D) = "bump" _Gloss("Gloss", float) = 8 } SubShader { Pass { Tags { "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc" struct v2f { float4 pos : SV_POSITION; float4 uv : TEXCOORD0; float3 tangentLightDir : TEXCOORD1; float3 tangentViewDir : TEXCOORD2; }; v2f vert(appdata_tan v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord; TANGENT_SPACE_ROTATION; float3 objLightDir = ObjSpaceLightDir(v.vertex); o.tangentLightDir = normalize(mul(rotation, objLightDir)); float3 objViewDir = ObjSpaceViewDir(v.vertex); o.tangentViewDir = normalize(mul(rotation, objViewDir)); return o; } sampler2D _MainTex; sampler2D _NormalMap; float _Gloss; float4 frag(v2f i) : SV_TARGET { float4 tex = tex2D(_MainTex, i.uv); float4 normalTex = tex2D(_NormalMap, i.uv); float3 tangentNormal = UnpackNormal(normalTex); // 切線空間 float3 diff = tex.rgb * _LightColor0.rgb * (dot(tangentNormal, i.tangentLightDir) * 0.5 + 0.5); float3 halfDir = i.tangentViewDir + i.tangentLightDir; halfDir = normalize(halfDir); float3 spec = tex.rgb * _LightColor0.rgb * pow(saturate(dot(halfDir, tangentNormal)), _Gloss); float3 col = spec + diff + UNITY_LIGHTMODEL_AMBIENT.rgb; return float4(col, 1); } ENDCG } } }
轉載請注明出處:http://www.cnblogs.com/jietian331/p/7132277.html
效果如下:
資源如下:
http://files.cnblogs.com/files/jietian331/TangentSpaceNormalMap.rar