珍蜗蜗

不断向前

导航

[Unity Shader] 切线空间的法线贴图

Posted on 2017-08-10 16:15  珍蜗蜗  阅读(3347)  评论(3编辑  收藏  举报

  切线空间的法线贴图,可以这样理解:

  #纹理坐标是从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页,求得了世界空间下的切线、副切线、法线后,归一化得到这三个正交分量。按列摆放可得到从切线空间到世界空间的变换矩阵。没有完全理解为什么按列摆放就是从切线空间到世界空间的变换矩阵。不知道下面的推导过程是否正确,先做个记录。