本篇介绍
本篇介绍下视图变换,包括从世界坐标到显示器中的一系列变换。通过本篇可以了解到我们看到的一幅图像是如何渲染到显示器上的。
视图变换
视图变换包含了从3D空间到呈现到显示器上中间涉及的一系列变换,比如3D空间中物体的某个位置应该出现到显示器上哪个像素位置上。中间的过程一下子看起来会比较复杂。我们可以将该过程进行拆分,变成一系列简单变换。首先我们可以想到该流程会包含如下几个简单变换:
- Camera(eye)变换:就是将物体坐标从世界坐标系中变换到以Camera位原点的坐标系中。本质上就是将坐标从一个坐标系变换到另外一个坐标系,前面介绍过变换方法。
- 投影变换:把Camera坐标系中物体坐标变换到某个固定空间中,其实就是从3D到2D空间的变换,同时规定一个范围,位于该范围外的会被裁减掉,不送给显示器显示。
- 视口变换:从前面的2D坐标变换到显示器的坐标中。 该过程可以参考下图:
image.png 通过该流程可以看到一个物体呈现到显示器上会经历哪些变换。
视口变换
先看视口变换,本质上就是这样的一个变换:
image.png
为什么会有0.5呢,我们认为每个像素的坐标是整数,而每个坐标在屏幕上的影响范围是以该像素位中心的一个小正方体。如下图所示:
image.png
这时候的变换矩阵如下:
image.png
投影变换
投影变换就是3D到2D空间的变换,这儿有正视投影和透视投影区分。正视投影就是物体不管远近都不做缩放,而透视投影会按照近大远小来缩放一波。这儿先看下正视投影。实际上就是拿一个空间来裁剪物体,在该空间内的物体可以被放到,不在该空间中的就看不到了。 如下图所示:
image.png
这时候的变换矩阵其实就是一个缩放和平移,如下所示:
image.png
如果Camera的位置就在世界坐标系的原点,观察方向也是-z,y是上方向的话,那这时候这两个矩阵已经够了。算法如下:
image.png
需要注意下的是z坐标,目前还没用到, 实际上是有用的。通过z坐标可以做z buffer算法,看哪个坐标更近,近的坐标会遮挡远的坐标。
Camera 变换
接下来将上面的条件再一般化,Camera在世界坐标系的任意位置,观察方向也任意。这儿就涉及到了不同坐标系的转换。 这时候就可以以观察点所在的位置,方向为起点,构造一个坐标系。 如下图所示:
image.png
e是观察者所在位置,g是观察方向,t是给定的向上方向,不需要和g垂直。 这时候就可以利用叉乘构造坐标系,这块前面介绍过。公式如下:
image.png
将世界坐标系中的坐标变换到Camera构造的坐标系的变换矩阵如下:
image.png
该矩阵前面介绍过,为了方便记忆,可以看成是先把坐标平移到观察点e,再进行坐标系对齐的旋转变换。
这时候的算法如下:
image.png
透视投影
再看下透视投影,透视投影的关键在于实现物体在屏幕上呈现的大小与物体与观察点的距离呈反比。如下图所示:
image.png
e是观察点,g是观察方向。 这儿和正视投影的变换矩阵不一样的地方是变换矩阵本身还和输入的坐标有关系。这时候就可以使用前面介绍过的方法,增加1个纬度:
image.png
这时候变换矩阵的最后一行就不再是[0,0,0,1]了,而是需要将z也考虑进去,这样最后的坐标都除以w就可以实现间接除以z,也就是实现了距离越远,坐标越小的目的。
直接下就需要求解变换矩阵了,一共16个参数。
我们可以代入几个特殊点,比如近平面的点是不应该不变化的,也是就是z=n的时候,x,y坐标应该都不变。而z=f的时候,x,y都需要变换到和近平面一致。z坐标需要做到不管远近尽量不变,至少n,f点的坐标都不能变。这时候就可以得到变换矩阵:
image.png
要理解这个矩阵,可以从一个问题出发,在透视投影的时候,n,f点都是没变化的,那中间点会看起来更近还是更远呢?答案是更远了。方法就是将z = (n f)/2 代入,然后和(n f)/2 再比较下,这儿我们简单推导下:
Unnamed Draft 4.jpg
这时候的透视投影变换矩阵是
image.png
流程算法可以写成:
image.png
通过证明,也可以发现透视投影矩阵还可以保留图像的特征,变换前的直线,变换后也是直线,变换前是三角形,变换后也是三角形。
目前我们在透视投影中用的裁剪参数有6个,可以进一步简化成2个参数,近距离n,视野角度