在之前的一篇文章中,我介绍了平移、旋转和缩放矩阵的证明,简单的讲解了如何证明绕任意轴旋转的旋转矩阵的证明思路。没有看过的朋友可以在这里看到。
这篇文章主要讲解下我理解的矩阵和矩阵的基变换,并简单介绍下LookAt矩阵。
这里涉及到三维图形学中的摄像机的概念。大家肯定都玩过游戏,现在游戏发展速度都特别快,很多游戏世界都是3D的,例如国外的荒野大镖客、巫师以及国内最近比较火的原神。游戏世界中所有的物体,例如桌子、树木、动物以及交通工具等等,它们在游戏世界中都有一个特定的位置,这个位置就是它们在游戏世界中的坐标,我们把它们在游戏世界中的位置称为世界坐标。假如同时有两个玩家A和B在游戏世界中漫游,那么这两个玩家的屏幕肯定显示的是不一样的,因为玩家在世界坐标系中的位置(世界坐标)不一样,并且视线的方向也不同,所以他们看到的屏幕肯定是不一样的。这里的A和B玩家,其实就是摄像机。假设我们以摄像机(玩家)为原点创建一个新的坐标系,可以称它为摄像机坐标系(观察空间坐标系)。那么同样的物体在世界坐标系中坐标为(300,200),那么它用摄像机坐标系如何表示呢?我用二维图形描述下这个问题。
假设平面中有一点A,此时点A的坐标为(1, 1),表示A点在如图所示的坐标系中在原点右侧1个单位,上方1个单位。如果将这个坐标系旋转45度,变成另一个坐标系X2Y2,那么在新的坐标系X2Y2中如何表示A点呢?
旋转45度,很容易计算出来A点在X2Y2坐标系中的坐标为(√2, 0)。那么有没有一个矩阵A可以使得A·P1 = P2,也就是经过矩阵A的变换,P1坐标变成了P2。这里P1表示在原来的坐标系中的坐标,P2表示在新的坐标系中同一个点的坐标表示。其实这里的A就是本篇文章要讨论的lookAt矩阵。
LookAt矩阵的作用就是,将世界坐标系中的物体坐标转换为用摄像机坐标系统描述,说白了就是在不同坐标系中描述同一个位置。
下面是learnopengl_cn官网给出的解释:
当我们讨论摄像机/观察空间(Camera/View Space)的时候,是在讨论以摄像机的视角作为场景原点时场景中所有的顶点坐标:观察矩阵把所有的世界坐标变换为相对于摄像机位置与方向的观察坐标。
首先我给大家讲述一个很重要的事实,在我上篇文章中说的几个变换矩阵,线性变换矩阵的每一列表示的都是变换后的坐标系的x、y、z轴的单位向量的表示
,即i帽、j帽和k帽。请牢牢记住这一重要特性,因为这一个特性真的很重要,它会直接影响你的线性代数的思维。你可能现在还没有认识到这一特征,没关系,请继续阅读。
还是以之前的A点的例子为例,来说明这一思想。A点坐标是(1, 1), 向量OA也是(1, 1),用i帽和j帽表示的话OA = 1 * i + 1 * j。
此时,我们将坐标系旋转45度,变成下图所示。这里我顺便小小的提一下,线性变换就是保证我画的网格线平行且等距分布,这也是为什么我会画一些网格在图中,上一篇文章讲解的几个变换矩阵都是线性变换。
正是因为是线性变换,所以变换后的A点满足如下公式:OA = 1 * i2 + 1 * j2。因为旋转45度,所以我们计算出i2和j2分别为(√2 / 2, √2 / 2)和(-√2 / 2, √2 / 2)。所以OA = (0, √2 )。
请仔细阅读我上图中的计算步骤,请保证你能看懂整个计算过程。
上图中我写了一个变换矩 阵,这个变换矩阵其实就是我们旋转45度的旋转矩阵。细心的朋友已经发现了,矩阵的第一列就是变换后的i帽,第二列就是变换后的j帽。所以还记得我之前说的那个真理吗?
线性变换矩阵的每一列表示的都是变换后的坐标系的x、y、z轴的单位向量的表示
。
还是用之前的例子,我们将变换前的坐标系称为xyo, 变换后的坐标系称为x2y2o。xyo-> x2y2o的变换矩阵如下(后面我将其称为MatA),每一列表示的是x2y2o坐标系的x和y方向的单位向量在xyo坐标系中的表示。所以将这个矩阵乘以一个坐标,其实得到的是一个在xyo坐标系中表示的坐标。
例如,例如点A(1, 1),计算MatA · A = B,得到的点B是经过线性变换后A的坐标,但是这个坐标还是用xyo坐标系表示的, 点A的坐标却是在x2y2o坐标系中的表示。所以这里MatA的作用就是将x2y2o坐标系的表示转化为xyo坐标系表示。那么反过来呢,xyo -> x2y2o如何转换?
这里引入逆矩阵的思想,逆矩阵表示相反的线性变换, 由MatA · A = B得到 A = (MatA^-1) · B ** , MatA^-1 表示的是MatA的逆矩阵。所以有MatA · A = B和A = (MatA^-1) · B**这两个公式,就可以得到同一点在xyo和x2y2o中的表示方法。
这不正是lookAt矩阵的作用吗?lookAt矩阵就是在不同坐标系下如何表示同一点。
其实这部分类容已经不重要了,因为通过上面的学习,你已经知道如何去转换坐标系了。但是我还是简单的介绍下learnOpengl_cn官网的lookAt矩阵吧。
LookAt矩阵如下, (Rx, Ry, Rz)表示摄像机的X轴方向向量,(Ux, Uy, Uz)表示摄像机坐标系的Y轴方向,(Dx, Dy, Dz)表示摄像机的视线方向及Z轴。 (Px, Py, Pz)表示摄像机位置的世界坐标。
通过上面的阅读,现在看这个矩阵,你能否自己给出证明呢?
......
......
矩阵的第二部分,是一个平移矩阵,目的是平移到(px, py, pz),矩阵中px,py,pz都加上了负号,是因为这里移动的不是摄像机而是整个场景,将场景向相反方向移动等价于移动摄像机。矩阵的第一部分就是一个线性变换的逆矩阵。计算逆矩阵通常需要计算非逆矩阵,那么非逆矩阵是什么呢?我在第二节内容说到,线性变换矩阵的每一列表示的都是变换后的坐标系的x、y、z轴的单位向量的表示。所以由 (Rx, Ry, Rz), (Ux, Uy, Uz), (Dx, Dy, Dz), 我们很容易写出线性变换矩阵。
这个线性变换矩阵我用Mat1表示,平移矩阵用Mat2表示,所以lookAt矩阵如下:
LookAt = (Mat1^-1) · Mat2。
逆矩阵的计算并不重要,写代码时,一般可以直接用函数去求解逆矩阵,重要的是你要理解我在本篇文章介绍的思想。本篇文章可能不是很好理解,我已经把我理解的尽可能详细的去描述讲解出来了,你可以多读几遍,带入思考去阅读。
(完)