Tangent Space Normal Mapping
为什么要法线贴图
法线贴图(Normal Map)正如其名所述,是一张包含了法线相关信息的贴图(我在说什么废话)。要介绍为什么使用法线贴图的话,我们首先得了解这样一个事实,在光照和着色算法不变的情况下,我们的图形质量高低基本上取决于我们模型的信息密度,更进一步说的话就是模型的三角形数量。
而这一概念也被应用到一种叫做LOD(level of detail)的技术之中,可以看到最右面的模型只有750个三角形,导致它头部的光圈基本上坍缩成了一个矩形,渲染质量显然没有最左面的好。
在有了上面的认知之后,大概率我们会有一个错误的认知,好,无脑堆素材质量就行了,看我一个模型整他个上亿个三角形,就不信出不了好画面。这种力大砖飞的情况虽然确实能显著提高渲染质量,但是游戏的包体大小也会成倍增加,并且这么高模的模型导入游戏,游戏渲染的压力会急速上升,如果没有UE5的Nanite这种技术来做简化,我们基本上没有希望达到实时渲染的速度要求。
不过聪明的人们想到了一种办法来进行近似,其原理大概是这样,虽然我们无法直接导入高模的模型,但是要是我们利用其表面的法线信息以及一个相对低模的模型,也能达到一个相对较好的渲染质量,同时也有一个不错的性能保证。
而这也就是所谓的法线贴图灵感的一个重要来源,高模模型烘焙出一张法线贴图配合上简化模型进行渲染,这是实时渲染中的一个常用trick。
上面这张看起来有点阴间的图便是一张常见的法线贴图示例。但是很快你就会发现问题,等下,为什么整张图都是蓝色的,法线如果转换为颜色向量的话,不应该是什么颜色都有的么?
是的我的朋友,你发现了一个盲点,我们只说了我们会利用法线贴图存储法线相关信息,但是我们并没有说明在什么坐标系下进行存储,也没有说明具体存的是什么东西,而这也就引出了我们下一个话题,也就是本文的标题切线空间法线贴图(Tangent Space Normal Mapping)。
切线空间法线贴图
其实法线贴图确实有你想的那种彩色形式,如果我们把法线信息定义在世界空间(world space)下的话。
上述左边便是直接存储在世界空间中的结果,可以看到基本上是什么颜色都有,比较符合一开始的假设。所以问题就是,为什么我们看到的大部分法线贴图是右边这种蓝色为主的情况呢?
首先考虑下如果将法线存储在世界坐标系下的话会有什么问题,如果我们有一个帧动画的话,模型每时每刻都会发生形变,那么自然而然其每帧的法线贴图也要变化,这就很恐怖了,每帧一个法线贴图,什么家庭敢这么做。所以我们自然是无法将其定义在世界坐标系下,而是转而进入到切线空间(Tangent Space)之中进行定义。
上图便是切线空间,在这个空间内,通过uv坐标我们便可以采样出一个Texel,这个Texel会是一个rgb的向量,记录的是在切线空间的法线向量,这里也就可以明白为什么这图是蓝色的,因为模型上大部分的点都不会在x,y轴上(对应r分量和g分量)偏移法线太多,基本上只有在z轴上稍微做个改动。
在得到了切线空间坐标系下的法线方向,之后我们通过构造一个TBN矩阵,即将TBN这三个向量作为基向量的矩阵,我们就可以将切线空间下的法线变换到相应坐标系中,最后再计算光照即可。
1 | void main() |
不过值得一提的是如果模型没给切线向量的话,我们自己就需要手算了。LearnOpenGL中有进行详细的解释,要是感兴趣的话可以看一看。