切线空间

发布时间 2023-07-07 14:21:02作者: Backsword

切线空间

切线空间是什么?

我们知道一个模型有许多面,每个面有法线,当我们从高模到低模的时候,就需要细节贴图和法线贴图来弥补。(细节贴图有好多种,对应的shader也有好多种,这里不详细讲解)

而物体的法线贴图存储的位置,而发现贴图是一个面的数据,并不是物体的数据,当前面用什么法线贴图,如果转存为物体,则必须根据物体的坐标系来建立贴图关系,这样法线贴图无法复用,所以需要一个相对于面的局部空间位置的法线。而切线空间更进一步,直接在点上建立坐标系。

切线空间是一个根据顶点的位置和当前点位置的UV方向法线生成的一个局部坐标系。而调整的法线贴图存储的就是关于这个坐标系的数据。

如何求TBN

定义:每两个顶点中,满足下面公式:

\[E_1 = \Delta U_1T + \Delta V_1B \]

\[E_2 = \Delta U_2T + \Delta V_2B \]

一个三角面 A B C 三点,A 对应位置是 PosA 对应UV坐标UVA(UA, VA), B 对应位置是 PosB 对应UV坐标(UB, VB), C 对应位置是 PosC, 对应UV坐标(UC, VC).

则上面公式展开为:

\[PosB-PosA = (UB-UA) T + (VB-VA)B \]

\[PosC-PosA = (UC-UA) T + (VC-VA)B \]

求出 T 和 B 的值。Normal 是当前顶点的法线。或者说是在建模软件中,编辑的顶点法线,这样可以通过顶点法线和当前的uv等信息,重建TBN矩阵,大多数的切线空间法线贴图是可以直接用的。

通过此方式,得到的TBN数值,把当前编辑的法线通过UV转换到切线空间,导出贴图。(在早期有许多建模软件实现方式不一样,渲染器对应的渲染方式不一样,导致阴影和接缝处问题很多)

一般建模软件有平滑法线的功能,但有的棱角的地方,不能平滑,这里需要额外的方案,比如说手动断UV 等等方式解决(建模有教程)。

详细计算方式和原理可查看 https://learnopengl-cn.github.io/05 Advanced Lighting/04 Normal Mapping/ 中的切线空间节点。

如何用

通过UV获取法线贴图,通过当前平滑过来的TBN矩阵,把切线空间的法线转为世界空间。(需要model矩阵,从局部空间转世界)

有的需要顶点输入的TBN,在经过光栅化到片元着色器的时候,TBN三个轴有可能不垂直了,有的着色器重新通过顶点法线来重新计算TBN的值。

但目前看UE和unity等引擎和一些建模软件使用 mikktspace 算法,不需要这么做了。官网提供了源码,很多软件导出也支持 mikkt 导出。

http://www.mikktspace.com/