该如何正确理解切线空间
网上搜了一圈,说得好很少,讲得细的也不多
我花了大概快接近一周,从物理意义理解透了tbn变换矩阵。
如果你能耐心看完,你的线性代数水平、高数水平、和空间变换能力,会更上一层楼的
网上的文章分为两类:
(1)推导类
大部分文章明确告诉你,T就是u的切线,B是另一条在法平面内的切线方向。没告诉你怎么求u的切线,也没告诉你v的切线怎么求。在实际看引擎代码,是看不出所以然的
(2)计算类
这类文章着重数值计算,告诉你在uv取两个点,也没告诉你uv这两个点是在哪个空间下测量的数值。当你通过uv求出来TB后,告诉你TB不一定垂直,然后又要重新正交化,而且这类文章很喜欢说,假设uv法向量为(0,0,1),是这样没错,但是对解决问题毫无帮助。
预备知识
求解切线控件的关键点在于:寻找一个矩阵,这个矩阵能将uv平面空间中的两个点映射到世界坐标三维空间中
关键点(1)uv的这两个点是在uv平面空间中测量的,一般uv都是在[0,1]的范围内。举个实际例子,(0.1,0.2),(0.3,0.4)
关键点(2)世界坐标下的两个点一般是类似(1,2,3) 或者(12,3,1)
关键点(3)如何求出一个矩阵能将uv的两个点映射到世界坐标下的两个点呢?这正是本文的围绕的点。【先说结论 其实(T,B)就是这样的矩阵】
(1)扎实的线性代数理解
对的,你没看错,是“理解”,只会加减乘除这些统统都不算。正确理解切线空间。请把3B1B的视频老老实实看完,起码知道二维空间到三维空间的映射,以及三维空间到二维空间的映射。【只需要看里面某一两个视频,基向量和变换】
3B1B的线性代数链接
如果在刷3B1B的时候,发现有点吃力,挑着内容宋浩老师的视频,起码知道矩阵的加减乘除吧【只需看到矩阵的加减乘除即可】
宋浩的线性代数视频
(2)TBN的定义
在满足了预备知识之后,接下来开始,理解什么是tbn。其实milo大佬在之后上讲得很好了
为什么要有切线空间(Tangent Space),它的作用是什么?
(3)TBN的计算
只有用起来了,这些知识才是属于你的。
OPENGL教程
(4)正确理解
最后一步才是正确理解TB的含义,【N可以不考虑,N在一开始没啥意义,全网的公式和推导都是从N从(0,0,1)的基础上推导,其实都是不好理解,容易混乱了uv平面、切线空间以及世界坐标的关系,甚至会复杂化问题,本文基于uv平面到世界坐标的映射(二维到三维的映射),不浪费过多的时间和精力去纠结其他的关系】
(1)T和B是uv空间的两个基向量
请看下图,这个是OpenGL的教程的推导公式,其实不容易看出公式的意义的。一旦知道了物理意义,就不用教程那么啰嗦的推导流程了
首先,不妨将两边转置,会发现,其实(T,B)矩阵是基向量【红色框圈起来了】,既然是基向量,那左乘任何一个矩阵,都会将(T,B)uv空间里面的任何点、或者向量转换到世界空间。【uv空间不是切线空间,只是一个普通的二维平面空间】
why???
为什么是转换到世界空间。
因为(T,B)是在世界空间测量的
【如果看不懂这段解释的话,得看3B1B视频,知道基向量空间的物理意义】
最有力证明我以上结论的是,OpenGL官方教程的数值计算
// positions
glm::vec3 pos1(-1.0, 1.0, 0.0);
glm::vec3 pos2(-1.0, -1.0, 0.0);
glm::vec3 pos3(1.0, -1.0, 0.0);
glm::vec3 pos4(1.0, 1.0, 0.0);
// texture coordinates
glm::vec2 uv1(0.0, 1.0);
glm::vec2 uv2(0.0, 0.0);
glm::vec2 uv3(1.0, 0.0);
glm::vec2 uv4(1.0, 1.0);
// normal vector
glm::vec3 nm(0.0, 0.0, 1.0);
glm::vec3 edge1 = pos2 - pos1; //边E的数值是在世界空间下测量的
glm::vec3 edge2 = pos3 - pos1; //这里的E也是一样的,在世界空间下测量的
glm::vec2 deltaUV1 = uv2 - uv1; //这里的数值居然是在uv空间下测量的
glm::vec2 deltaUV2 = uv3 - uv1; //这里的数值居然也是在uv空间下测量的
说明TB是想将uv空间下测量的点(向量)变换到三维空间的点(向量)。
(2)TB空间只能是uv平面的一个二维空间
既然是二维空间,又是怎么映射到三维呢??
我们发现(T,B)矩阵是个32的矩阵,其实左乘任何一个二维矩阵,就会得到一个32的矩阵(E1, E2),这个结果矩阵就表示,在TB空间映射到世界坐标下的两个三维向量
(3)TB二维空间如何映射到三维空间呢
N = TXB
利用叉乘就可以得到第三个垂直分量
其实N法向量从头至尾都是作为uv空间的一个垂直法向量,直接将TBN三者写一起,就变成了(T,B,N)这样的变换矩阵。
最后一个问题:
肯定有同学还在想 2维的数据表达成3维,那么会不会需要补充某些些数据,三维到2维,又会丢掉某些数据。补充和丢掉的数据会不会不一样。
答案:
如果这个三维数据的rank是2.。。。。其实本来就只能表达和二维数据一样的范围【如果想不通,就去看3B1B的关于rank的视频】
附上一张rank为2的图片,其中有两个零,并感受一下是不是这两个0导致的rank为2