人气 512

[WIKI] 为什么要有切线空间(Tangent Space),它的作用是什么? ... [复制链接]

武汉视灵插画56 2022-3-26 11:28:52

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
新手,有好多不明白的地方:
1.法线贴图(Normal map)技术中的切线空间是一个怎样的空间?
2.法线贴图上存储的值是什么值?这个值是如何计算得到的?
3.转换到Tangent space时,[n.x,n.y,n.z] [T, B ,N]    与   [n.x,n.y,n.z] [B, T ,N] 有什么区别?
回复

使用道具 举报

风云堂Simon54 2022-3-26 11:48:52
1 .什么是切线空间?
      Tangent Space,其实一个坐标系,也就是原点+三个坐标轴决定的一个相对空间,我们只要搞清楚原点和三个坐标轴是什么就可以了。在Tangent Space中,坐标原点就是顶点的位置,其中z轴是该顶点本身的法线方向(N)。另外两个坐标轴就是和该点相切的两条切线。这样的切线本来有无数条,但模型一般会给定该顶点的一个tangent,这个tangent方向一般是使用和纹理坐标方向相同的那条tangent(T)。而另一个坐标轴的方向(B)就可以通过normal和tangent的叉乘得到。
y9WGoH23OmKKi1j9.jpg


YYTBy18E4rt11tdq.jpg


JWHN8g51n6KK8nHs.jpg


ZMOozkKPpWKXpmwu.jpg

        通常我们所见的法线纹理还是基于原法线信息构建的坐标系来构建出来的。那种偏蓝色的法线纹理其实就是存储了在每个顶点各自的Tangent Space中,法线的扰动方向。也就是说,如果一个顶点的法线方向不变,那么在它的Tangent Space中,新的normal值就是z轴方向,也就是说值为(0, 0, 1)。但这并不是法线纹理中存储的最终值,因为一个向量每个维度的取值范围在(-1, 1),而纹理每个通道的值范围在(0, 1),因此我们需要做一个映射,即pixel = (normal + 1) / 2。这样,之前的法线值(0, 0, 1)实际上对应了法线纹理中RGB的值为(0.5, 0.5, 1),而这个颜色也就是法线纹理中那大片的蓝色。这些蓝色实际上说明顶点的大部分法线是和模型本身法线一样的,不需要改变。总结一下就是,法线纹理的RGB通道存储了在每个顶点各自的Tangent Space中的法线方向的映射值。

2.为什么要有切线空间
        实际上,法线本身存储在哪个坐标系中都是可以的,例如存储在World Space、或者Object Space、或者Tangent Space中。但问题是,我们并不是单纯的想要得到法线,后续的光照计算才是我们的目的。不管使用哪个坐标系,都面临着一个选择,就是最后光照计算使用的坐标系究竟是哪个。对于Tangent-Space Normal Map,我们一般就是在Tangent Space里计算的,也就是说,我们需要把viewDir、lightDir在Vertex Shader中转换到Tangent Space中,然后在Fragment Shader对法线纹理采样后,直接进行光照计算
        Tangent-Space还有如下一些优点:


    • 自由度很高。Tangent-Space Normal Map记录的是相对法线信息,这意味着,即便把该纹理应用到一个完全不同的网格上,也可以得到一个合理的结果。
    • 可进行UV动画。比如,我们可以移动一个纹理的UV坐标来实现一个凹凸移动的效果,这种UV动画在水或者火山熔岩这种类型的物体会会用到。
    • 可以重用Normal Map。比如,一个砖块,我们可以仅使用一张Normal Map就可以用到所有的六个面上。
    • 可压缩。由于Tangent-Space Normal Map中法线的Z方向总是正方向的,因此我们可以仅存储XY方向,而推导得到Z方向。

回复 支持 反对

使用道具 举报

纤纤 2022-3-26 12:08:52
Normal map的用途是为了在几何物体表面上加入细节。
Normal map通常有两种,一种是object-space normal map(看上去颜色分布很随机),一种是tangent-space normal map(看上去通常大多部分是浅蓝色的)。
WqfwdraTdpwTHFqf.jpg

图源:
Tangent Space Normal Mapping

现在先谈后一种。
我们考虑一个三角形,要为里面每个sample给定一个法线矢量。这三角形是一个平面,有一个平面法矢量,我们可以修改这个矢量去定义每个sample的法矢量,例如每个sample上向某个轴偏移一个值,向另一个轴偏移一个值。这两个轴最好都垂直于该平面法线。但问题是,我们应该用哪两个轴?
这是一个常见的三维问题,给定一个轴,要生成另外两个轴。或者换句话说,我们需要定义一个坐标系,其中一个是以平面法矢量定义的轴。
对于一些简单的几何形状,我们可以自定义一个坐标系统,例如球体以经纬度来定义另外两个轴(注意两个apex顶点不能定义)。
但对于普通的三角形网格,我们想用更简单的方法,就是利用纹理座标(或称为网格的parameterization)。
可以按照模型顶点的位置坐标随纹理坐标(u, v)的变化作为「切线空间」:
VRbb8MCw8cC94k89.jpg


但这样做T和B并不一定是互相垂直的,所以一般会用:
oEvWZ8B8HWMTswBW.jpg


然后,tangent-space normal map的值(颜色)是用这种坐标定义的。
我们把这些值储存至每个顶点,在vertex shader做插值。在pixel shader计算光照时,把normal map采样出来的法矢量用从这组坐标变换至模型/世界坐标。
tangent-space normal map的好处是可以贴到不同的平面上,例如一个立方体的六面都可以贴上同一张tangent-space normal map。但如果这并非必需的,我们可以使用object-space normal map,其值已经是模型空间的法矢量。
更详细的说明可参考
The Cg Tutorial

另外,除了用三个单元矢量(9个)表示一个坐标系,我们还可以用四元数,详见:
Spherical Skinning with Dual-Quaternions and QTangents。
回复 支持 反对

使用道具 举报

你丧心病狂吧 2022-3-26 12:28:52
为什么要有切线空间?这得先从法线贴图说起

一、什么是法线贴图?
    顾名思义,法线贴图就是保存了3D模型表面法线的贴图,主要用途是为了让3D模型在接收光照时显得更加真实。例如下图演示的是同一个3D模型在Unity中有法线贴图和无法线贴图所接收到的光照渲染对比,左右两边分别对应的是无法线贴图和有法线贴图的效果,很明显有法线贴图的黑叔叔脸部细节更丰富、刀疤更清晰,脖子上的肌肉细条相对于左图也要更清晰和立体一些。
ZL45ZCfcL8N8T04N.jpg

二.什么是切线空间?
我们知道,一个法线向量有三个坐标值
aUMM5abhun03FRuA.jpg

,这个值是相对于哪个坐标系下的呢?我们可以选择3D模型的顶点所在的坐标系,即对象空间(Object-Space),也可以选择3D模型纹理所在的坐标系,即切线空间(Tangent-Space),也称为纹理空间(Texture-Space)。例如下图是两张不同坐标系下的法线贴图对比,你能分辨出哪一张是切线空间中法线贴图吗?[1]
JXA1EISzg1R5Ry2i.jpg

其实,切线空间中的法线贴图特征比较明显,颜色比较单调,整体偏蓝色。为什么呢?因为法线贴图中任意一点的颜色通道的b值都大于0.5。为什么?在回答这个问题之前,我们先来了解一下什么是切线空间,切线空间可以理解为对于在3D模型表面上的任意一个点,在该点切平面上选取两条相互垂直的坐标轴以及切平面的法线所组成的坐标系。我们来举个简单的例子,假设地球是一个巨大的3D球模型,对于地球的任意一点P我们选择该点的由南向北方向为x坐标轴(T),由西向东方向为y坐标轴(B),地心与该点的连线方向为z坐标轴(N),这样的坐标系称为该点的切线空间。
R4UXBi1f11iz20XB.jpg

可以看到,切线空间中任意一点的法线与N坐标轴的夹角小于90度,也就是说法线的z值大于0。在归一化之后,法线的x和y取值范围为[-1,1],而z的取值范围为[0,1]。通常情况下我们存储在贴图中的值为正,一般通过一个简单的变换
SmywNw0z2wZkwaNI.jpg

来完成,经过该变换后,z的取值范围变为[0.5,1],所以切线空间下的法线贴图整体偏蓝。

三、切线空间有什么优缺点?
上一节中提过,对象空间中的法线和3D模型的顶点在一个空间,因此我们把这样的法线贴图应用到3D模型的另外一个部分或者另外一个3D模型上,解析出来的法线值可能就不对了,而切线空间中的法线与纹理坐标在同一空间,也就说只要我们同时将漫反射等纹理贴图和法线贴图同时应用到另一个模型上,法线贴图中的值经过变换后依然是正确的。如下图[2]
LggW8g3p70lqhI67.jpg

左图是切线空间中的法线贴图计算出来的光照,地板和墙的光照都是正确的。而右图的法线贴图在墙的对象空间中,地板在复用了墙的法线贴图后,计算出来的光照是错误的。
那么切线空间中的法线贴图有什么缺点呢?
由于在计算光照时需要统一法线和光照方向所在的空间,我们需要将切线空间的法线变换到灯光的空间(世界空间或者对象空间)或者将灯光从其所在的空间变换到切线空间,而空间变换需要计算额外的旋转矩阵TBN,一般情况下我们在vertex shader中计算TBN,再将灯光变换到切线空间,之后再将相关信息传递到fragment shader中,这样相对于对象空间中的法线贴图来说,在vertex shader中增加了额外矩阵运算,另外经过变换后每个象素的光照信息也变得不同,需要将这部分信息传递到fragment shader中。
四、法线贴图如何生成?
方法一,通过高度图生成,原理比较简单,对纹理中的任意一点求出u、v方向上的高度向量,叉乘后即可得到法线向量,例如下图[3],左边是高度图,右边是根据高度生成的法线贴图。
JWpgzNYneyFHY1wo.jpg

方法二,在maya等3D建模软件建立高精度模型,添加更丰富的细节然后再将法线贴图烘焙导出。
最后一个问题:
3.转换到Tangent space时,[n.x,n.y,n.z] [T, B ,N] 与 [n.x,n.y,n.z] [B, T ,N] 有什么区别?
TBN其实只是一个约定,一般在生成切线空间的中法线贴图时以u方向为T,v方向为B。我们在渲染时,会根据生成法线的算法建立TBN矩阵。如果在生成时[n.x,n.y,n.z]对应的是 [T, B ,N],那么我们在建的就是TBN矩阵,反之如果 [n.x,n.y,n.z] 对应的是[B, T ,N] 那么建立的就是BTN矩阵。
参考


  • ^https://github.com/ssloy/tinyrenderer/wiki/Lesson-6bis:-tangent-space-normal-mapping
  • ^如下图 https://developer.download.nvidia.cn/CgTutorial/cg_tutorial_chapter08.html
  • ^https://cpetry.github.io/NormalMap-Online/
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

QQ|手机版|小黑屋|九艺游戏动画论坛 ( 津ICP备2022000452号-1 )

GMT+8, 2022-8-12 23:54 , Processed in 1.086108 second(s), 25 queries .

Powered by Discuz! X3.4  © 2001-2017 Comsenz Inc.