(三维空间)核心变换:MVP


图形渲染的两个重要过程是变换着色

整个过程可以理解为画一张肖像画,变换 = 模特摆pose +画家调整远近和观测角度着色 = 在(大大小小不同的)画纸上勾勒出轮廓 + 上颜色

可以发现,前面部分变换总是处理三维空间相关的问题,后面部分着色则总是处理二维平面相关的问题。两者衔接的过程,需要把三维的数据映射到二维屏幕,叫做视口变换

虽然叫“视口变换”,但处理的是屏幕相关的问题,跟物体平移、旋转、缩放这些核心的变换没有关系。核心的变换包括模型变换M视图变换V投影变换P,统称MVP。也叫观测变换Vewing

模型变换,即物体本身的平移、旋转、缩放。

视图变换,即转动摄像机观测物体。

投影变换,即展现物体的方式,有两种。第一种:人眼看物体,离得越远显得越小,最后会交汇与远处的一个消失点,叫透视投影;第二种,设计图上画的物体远近都是一样大的,叫正交投影。

我们知道变换的数学方法是矩阵乘法,平移、旋转、缩放的矩阵分别长啥样请看:

我们发现,在三维空间中,平移和缩放两种矩可以叠在一起,并不冲突

 而旋转矩阵则被抛弃了,要单独凉一边。

我们可以把三维空间中的任何旋转分解成各自3个平面上的旋转,分别是绕x轴旋转、绕y轴旋转、绕z轴旋转,而这三兄弟的矩阵居然不是完全一样的:

可以看到,在右手定则中,绕x轴或z轴旋转,矩阵都是(cosα -sinα,sinα cosα),绕y轴旋转却是(cosα sinα,-sinα cosα)。

究其原因,是因为右手定则的z方向,是由x向y指向得到的,即x-y->z,y-z->x,z-x->y。

而从图中可以看到,绕y轴旋转,实际上是x-z,跟z-x相反,所以表示方法跟其他两兄弟不一样。

那么,有没有一个公式是给出任意角度,直接应用就可以得到新的向量/点? 

有的,叫“罗格里格斯旋转公式” ,可以计算出,绕任意方向的轴n旋转α度后的结果(轴n过原点):

注意了,旋转一定是绕着坐标轴原点(0, 0, 0)的,如果要做绕着物体中心的旋转变换,要拆解成3步:把物体中点平移到原点,做旋转变换,再逆向移回原位置。


现在我们来看视图变换的整个过程。

首先,先“摆正”摄像机的位置,这样就能减少一个变量因素。摆正的过程,是把摄像机从任意位置任意朝向->>>>放到原点位置 + 顶朝+y方向 + 看向-z方向

如图所示,摆好摄像机  = e点平移到原点 + g方向旋转到-z方向 + t方向旋转到y方向 + (g * t )旋转到x方向。

e点平移到原点,这个很好写,只要平移(-ex, -ey, -ez)即可。

而后面的三个旋转,则非常不好写,如果按常规的操作,每一个旋转都要先找到旋转轴,再应用一次上面提到的“罗格里格斯旋转公式”,复杂程度可想而知。

不过我们只要逆向思维,问题就迎刃而解:任意轴旋转到标准轴,其实就是标准轴旋转到任意轴的逆变换,也就是说,我们只要求出标准轴旋转到任意轴的变换矩阵,求它的逆,就可以得到任意轴旋转到标准轴的变换矩阵。而从标准轴旋转到任意轴,不就是分别乘3次(cosα -sinα,sinα cosα)嘛!同时,对于所有的正交矩阵,逆变换 = 转置。旋转矩阵是正交矩阵,求它的逆变换就是只需要转置一下它即可。

 至此,相机已经摆正,可以进行下一步。


我们知道,在实际生活中,一个物体同样的大小同样的位置,我们用不同的方式去描述它,就会呈现不同的结果,比如设计图和素描图。

不管是平行投影还是透视投影,最终都是要显示在屏幕上的,因此我们必须要做的一个步骤,是把摄像机所看到的范围映射到屏幕上

既然屏幕是方的,而且每种屏幕的大小各不一样,于是我们这么做:

1.虚拟建立一个2*2*2的规范化正方体

2.虚拟建立一个长方体,以表示摄像机覆盖的范围;

3.把长方体里模型的点均匀挤压到规范正方体内;

4.最后,把规范化正方体里的点映射到不同大小的屏幕上。

正交投影 

人的眼睛看向远方,看到远平面的物体和近平面的一样大,并没有缩小,即正交投影。

正交投影“把长方体里模型的点均匀挤压到规范正方体内”的方法很简单,想象一个任意大小的长方体压成2*2*2的正方体,就是把长方体的长宽高分别缩成2,即
x` = x / w *2 = (2 / (r - l)) * x  , l表示left,r表示right

y` = y / h * 2 = (2 / (t - b)) * y , t表示top,b表示bottom

z` = z / d * 2 = (2 / (f - n)) * z , f表示far,n表示near

注意,如果这个长方体的中心不是在原点,需要先平移到原点,再做缩放。

 透视投影

人的眼睛看向远方,远平面的物体缩小到近平面里,即透视投影。

透视投影变换要做2步:

1.把透视空间中的锥体Frustum压成正交空间的长方体Cuboid

2.做一次正交投影。

第2步我们已经会了,现在我们来求锥体Frustum压成长方体Cuboid的矩阵

我们称它为矩阵M。锥体Frustum上任意平面上的任意点,乘M后都会得到,对应在长方体Cuboid上的一个点。

求解的过程分几步走:

【第一步】我们通过观察发现,在所有平面,x和y值都跟z有直接关系,可以用相似三角形求出,x` = (n/z)x, y` = (n/z)y

由此可知,经过变换后的点为

在其次坐标中,我们可以把变换后的点的每一个值都乘以z,表示的是同一个点:

 

根据矩阵乘法,知道M一定长这样:

 【第二步】我们知道,在近平面上,所有的点变换以后都等于它本身,我们可以利用这个特殊情况,把n代入z,并再次利用齐次坐标的特性,让变换后的点的每一项都乘以n,可得:

现在我们只关注红色框的部分:n通过矩阵乘法得到n2,即 ?x + ?y + ?n + ?1 = n2,可知前面2个?都一定等于0

 就剩 A 和 B 的值未知了。

 【第三步】

 对于近平面上的任何点,可推出:

 现在再找一个特殊点,即远平面的中心点,它的x和y都等于0,z等于f,可推出:

 根据红框中的两个公式,可求出

 最终,我们求出了这个“挤压”的矩阵

 用它乘正交投影矩阵,即得到透视投影的矩阵变换。

注意!!!在整个求解过程中,前面所说可用相似三角形求出不同平面的x和y值,并没有说可以用同样的方法求出z值。

近平面上点的z值等于n,远平面上点的z值等于f,但其他平面上的点的z值跟z并不是直接的相似关系!

也就是说,近平面和远平面正中间的平面,挤压以后,点的z值并不是等于(zf + nf) / 2

这又是一个跟直观上有出入的结论。而结果等于多少,用“挤压”公式算一遍就知道了。