3D Transforms

这里可以类比二维的变化,依旧是使用齐次坐标系:

  • 3D point = (x, y, z, 1)
  • 3D vector = (x, y, z, 0)

并且同样的,当w≠0,(x, y, z, w)就是点(x/w, y/w, z/w, 1)。

3D下的齐次坐标矩阵

针对3D下的齐次坐标矩阵,做更多的细节解释。

在三维空间中,也是先应用线性变换,再应用平移变换。针对左上角的3×3矩阵,缩放变换则是一个对角矩阵,从上到下依次是x、y、z的缩放比例;旋转分为三种:

3D下的旋转矩阵

当我们想要在三维空间中进行任意地旋转很难写,我们可以从简单的开始写起,即绕着某一个轴旋转。我门可以看到,绕着哪个轴转,哪个轴的值就不变。剩下的二维矩阵就是一个二维下的旋转。这一点对于绕y轴的旋转有所不同,这是因为在右手坐标系中,x可以通过y叉乘z得到,z可以通过x叉乘y得到,而y是由z叉乘x得到,不是按照xyz的顺序,所以这里sin的正负相反。

这样,三维空间的旋转,可以通过三个平面的旋转来表示:

Rxyz(α, β, γ) = Rx(α)Ry(β)Rz(γ)

这里的旋转都是默认的逆时针旋转。这三个角又被称为欧拉角。

飞行中的旋转组合

飞机运行中的旋转也类似的可以分解为pitch、yaw、roll。

Rodrigues’ Rotation Formula

公式

这样,绕任意轴旋转任意角度可以通过这个公式计算变换的结果。另外,三维空间中,如果绕着某一条平行于坐标轴的轴旋转,依旧可以采取先将该轴移回坐标轴进行旋转,再进行一个平移的逆变换的方式进行计算。

(这里没有介绍四元数的概念,四元数可能主要用于插值)

Viewing(观测) transformation

View(视图)/Camera translation

我们最终的目的是把一个三维空间世界看到的内容转化为二维空间中的一个图像。可以先想想如何拍一张照片,首先找到一个地方,并安排好要拍的内容(model transformation),然后找到一个角度来放置照相机(view transformation),最后拍下(projection transformation)。这个过程也可以简称为mvp变换。

要定义view transformation,首先要定义这个camera,分别是向上方向,看的方向和所在位置。为了方便,我们将这个相机放在原点,向上方向为y的正方向,看向-z方向。所以我们可以通过矩阵Mview即以下一系列操作将一个在e点朝向g,向上方向为t的相机变成我们想要的位置:

相机移动原点

可以将两个旋转变成它们的叉乘的向量旋转到x,因为它们俩其实是互相垂直的,并且可以反过来,将x轴旋转到g×t。因为x旋转到g×t的同时,y旋转到t,z旋转到-g,所以左上3×3矩阵的第一列就是g×t的结果,第二列就是向量t,第三列就是向量g的负值。又因为旋转矩阵的逆矩阵就是它的转置,所以我们只要转置这个矩阵就得到了做变换的旋转矩阵。

所以我们只要对空间中其他的物体做对相机相同的变换即可保持model在设置好的相机中的正确位置。所以模型变换和试图变换常被放在一起称为ModelView Transformation。

Projection(投影)transformation

  • Orthographic(正交)projection
  • Perspective(透视)projection
投影

投影变换分为正交投影和透视投影,如上图所示。人的眼睛看物体更偏向于右图中的透视投影,我们会看到平行线不再平行,这其实是近大远小的缘故。左边的正交投影更多用于制作工程制图,它并不会带来近大远小。

两种投影的对比解析

可以通过上面两张图来解释,透视投影我们认为camera是一个点,从camera出发连向平面,可以连出一个四棱锥。正交投影则假设相机离观察物体无限远,这样,近和远就一样大了。

Orthographic projection

正交投影很简单,如果相机固定在固定点(原点)处,这样我们只要把z的坐标给丢掉(这里没有z之后如何区分物体的前和后呢?这个后面会解决),然后无论原来的x、y范围多大都缩小到[-1,1]就得到了正交投影的结果。为什么要移动到这个范围内,是为了方便后续的计算。

不过实际当中,不一定如此简单,所以我们要进行一些定义。

正交投影的分析

我们首先定义空间中的一个立方体(这里可能意味着把部分观测区域视为一个立方体),我们定义这个立方体的上下左右以及远近在坐标系中的位置,把这样一个立方体映射到最右边的这个(正则、规范、标准)的立方体(canonical cube)。

这个映射怎么做呢,首先把左侧一开始说的立方体的中心移到原点,然后把x、y、z轴都拉伸到[-1,1]。这个和前面说到的直接丢掉z不同,是先做平移,再做缩放。另外我们定义的上下左右,都是下比上小,左比右小,而在远近中,由于我们看的是-z方向,所以近其实比远大(所以比如在opengl中,用的是左手系,就是在这一点上会方便一点,但也会造成别的问题)。

变换矩阵如下:

正交投影的矩阵

在线性变换中,拿左右举例,因为原来是r-l,变换后是[-1,1]所以是变换到1-(-1) = 2,所以乘上因子如图所示。

Perspective projection

透视投影是用的最广泛的投影,广泛的用于图形学中。在透视投影中,我们同样定义近和远,这个截头锥体的小的一面为近,大的一面为远。

透视投影的截头锥体

所以我们做的透视投影,可以先将远的平面的内容向内挤压收缩到小平面上,再利用正交投影到近处的平面上。在这个挤压的过程中我们定义几个事情:

  • 近平面永远不变(近处平面上的所有内容都不会在这个操作下发生变化)
  • 远平面的z值不会发生变化,一直是f
  • 原平面的中心点也不会发生变化,挤压后依旧是中心

我们已知了正交投影怎么做,现在只要解决挤压的变化即可。

透视投影的分析

我们从侧面往这个frustum看,图示是这个frustum的一半,用来分析。对于f处的任何一点(x, y, z)在经过挤压了之后我们想知道它对应于近处平面的位置,我们可以找一个y对应的关系,即一个相似三角形。对于x也是同样的道理:

透视投影x的关系

至此,已经获得了很多信息:

已知信息

对于一个点,我们知道了x,y的变化,只差一个z的变化,并且可以通过同乘一个z化简这个点的表现形式。

计算式1 计算式2

我们可以通过计算推导这个矩阵。还记得前面提到的一些关于不变达成的共识,所以我们可以利用如下:

计算式3

即一个近处的点永远会在乘上这个矩阵后被映射回它自己,所以:

计算式4

目前,只通过这一个式子(An + B = n2)还不够确定AB的值,但是还有一点远处的中心变换后仍然是中心,可以得到:

计算式5

于是我们解出A = n + f,B = -nf,现在我们将这个挤压的矩阵再左乘一个正交矩阵就得到了最终的透视变换。

另外还有一个思考的问题,就是这对于中间的某一个点,在经过挤压之后,它的z是更接近n还是f?

根据挤压的矩阵,假设原来一点为(x, y, z, 1),变换后为(nx, ny, z(n + f) - nf, n)。和原来的点(nx, ny, nz, n)对比来看,nz + zf - nf - nz = (z - n)f,此值小与0,所以比原来的值更小,即更接近f。