理解Unity法线贴图的切线空间存储方式

最近再学习一些unity shader的一些东西,看到法线贴图那里突然不是很理解,经过查找资料,现在也是恍然大悟,也是深深敬佩发明切线空间法线贴图那个大神!


话不多说,直接说一下,关于法线贴图,主要有两种,一种是基于模型空间的法线信息存储,一种就是基于切线空间的信息存储。我们这里着重来说一下第二种。


什么是切线空间?

切线空间就是,基于模型上的一个顶点建立的坐标空间,它的X轴是这个顶点在模型中的切线分量,Z轴是改点在模型上的法线,Y轴就是这个顶点的副切线,因为坐标空间XYZ三个面都是互相垂直的嘛,所以这个副切线我们是可以求出来的(以为同样是与一个平面垂直的单位向量是有两方向的,在Unity中模型会提供一个副切线的方向的数据)。

来上一个图,让我们更好的理解这个所谓的切线空间。

理解Unity法线贴图的切线空间存储方式_第1张图片

这是网上找的一个图,大家明白这个切线空间的意思就好啦~

所以,法线贴图就是记录这个顶点在它的切线下的法线的向量(x,y,z)。

这里我们还要说一下就是,法线的分量范围是[-1,1]而像素(颜色)的分量范围是[0,1],所以,利用法线贴图来表示法线的话是需要一个转化的,即pixel = (normal +1)/2。

因为我们的坐标空间都是切线空间下的,所以,法向量基本都是指向正方向的,就算是没有指向正方向也只是偏了一个角度而已,总之不太会出现和正方向的太大的偏差(所以,这也是为什么我们也把这种贴图叫做法线扰动贴图,就是记录它和正方向的一个偏差)。所以呢,我们的法线分量基本都是1附近的,转化成像素也就是(1+1)/2还是1附近,而法线对应的像素通道是RGB中的B,这也就解释了为什么法线贴图基本都是呈现蓝色。

使用切线空间的法线贴图还有一个重要的一点就是,它可以节省空间,相比于,模型空间下的法线贴图,它可以只存储切线分量和副切线分量,然后法线的分量就可以计算出来了。


理解Unity法线贴图的切线空间存储方式_第2张图片

(原谅我的画技。。。)所以,我们根据一致的X,Y就可以算出来Z啦。

Z  = sqrt(1 - (x^2 + y^2));

或许我们在看一些Unity Shader 的CG代码的时候,会发现它是这么计算法线Z分量的:

float3 tangentNormal = tex2D(_BumpTex,uv_BumpTex);

tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy,tangentNormal.xy)));

这个计算和我们上面是一样的,因为dot点积操作就是(x,y)(x,y) = x^2 + y^2;(这里只要不要去想点积的几何意义就好,我们只是单纯的拿它来做个计算)

所以,改顶点的法向量就可以完全求出来啦~

当然这个是在切线空间下的该顶点的法向量,比如在Unity中需要计算光照什么的,我们还是会需要把这个法向量变换到对一个的坐标空间~



你可能感兴趣的:(Unity3D,Shader)