切線空間的法線貼圖,可以這樣理解:
#紋理坐標是從0到1,它的坐標是x向右,y向下
#頂點坐標是從-1到-1,坐標是x向右,y向上
1 由表面上某點的切線Tangent、副切線Bitangent、法線Normal形成一個新的坐標系,即切線空間。
2 其中與法線垂直的切線有很多,在Unity中或者是Cg中,規定紋理坐標的方向u和v作為切線和副切線的方向。
3 修改法線的方向,會讓表面看起來有凹凸感。這時在切線空間中,調整后的法線看起來是對原法線的擾動。
4 其擾動后的在切線空間中的坐標(x, y, z),其中x是u方向上的偏移,y是v方向上的偏移,z則是法線方向上的偏移。
5 將其作為顏色存儲在法線貼圖中。由於歸一化之后的法線坐標,各分量范圍在[-1, 1]之間,而顏色范圍在[0, 1]之間。對其做(x+1)/2的映射計算,使其值滿足顏色范圍。
6 由於是偏移量,因此當表面凹凸沒有變化時,法線為原法線方向(x y z) = (0, 0, 1)。映射到顏色之后為(0.5, 0.5, 1.0)。這也是為什么法線貼圖大部分是偏淺藍色的原因。
7 由於偏移后的法線是歸一化的,因此滿足x2 + y2 + z2 = 1。知道x和y就可以求出z。因此如果texture的類型被設置為Normal Map,Unity使用DXT5nm壓縮算法,對法線貼圖進行了壓縮。只存儲x和y的值,存儲在貼圖中的a和g通道(即w和y),這樣另外兩個通道可對其他數據進行存儲。見UnityCG.cginc的UnpackNormal函數
1 inline fixed3 UnpackNormalDXT5nm (fixed4 packednormal) 2 { 3 fixed3 normal; 4 normal.xy = packednormal.wy * 2 - 1; 5 normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy))); 6 return normal; 7 } 8 9 inline fixed3 UnpackNormal(fixed4 packednormal) 10 { 11 #if defined(UNITY_NO_DXT5nm) 12 return packednormal.xyz * 2 - 1; 13 #else 14 return UnpackNormalDXT5nm(packednormal); 15 #endif 16 }
書中(《Unity Shader 入門精要》)P153頁,求得了世界空間下的切線、副切線、法線后,歸一化得到這三個正交分量。按列擺放可得到從切線空間到世界空間的變換矩陣。沒有完全理解為什么按列擺放就是從切線空間到世界空間的變換矩陣。不知道下面的推導過程是否正確,先做個記錄。