之前的章节中,矩阵变换是在三维或二维世界中排列对象的工具,矩阵变换的另一个重要用途是在“三维世界的二维视角”中的位置和三维世界中的位置进行转换
3D 到 2D 的映射叫做视图变换(viewing transformation),视口变换在对象顺序渲染中很重要,因为我们要频繁地查找每个对象在 2D 中的位置
第四章中,学习了不同类型的透视、正交视图以及如何生成观察射线。
本章是第四章的逆过程,本章将阐述如何使用矩阵变换来描述“平行视图”和“透视视图”,本章中的变换会将 3D 场景中的点投影到图像中的 2D 点,并且会将给定像素的观察射线上的任意点投影回像素的位置
把三维世界中的点投影到二维,仅仅能够做到线框(wireframe)的渲染,即物体边缘。距离摄像机更近的面不会遮挡更远的面
也就是这一章仅仅是线框的渲染,之后的章节会讨论对象表面的渲染
视图变换(Viewing Transformations)
视图变换的任务是将 3D 坐标
这是个复杂的过程,取决于摄像机的位置和方向、投影类型、视野、图像的分辨率等
与所有复杂的变换一样,最好将其分解为几个更简单的变换的乘积。大多数图形系统通过使用三个变换序列来实现这一点:
- 相机变换(camera transformation)或视变换(eye transformation):将相机放置在原点,并且朝向方便计算的方向(例如
轴正方向?)。这一步仅取决于相机的位置、方向或者叫姿态(pose) - 投影变换(projection transformation):将三维场景中的点映射到相机空间(camera space),所有点将在
和 方向上都落到 到 的范围内。这一步仅取决于投影类型 - 视口变换(viewport transformation)或窗口变换(windowing transformation):将单位图像矩形映射到像素坐标系的矩形。这一步仅取决于输出图像的大小和位置
摄像机坐标系(camera coordinates)、摄像机空间(camera space)
规范视空间(canonical view volume):
视口变换(Viewport Transformation)
从规范视空间映射到屏幕空间(screen space),即将
假设现在所有线段都在规范视空间内部,之后在讨论剪切(clipping)时,会放松这个限制
上一章有一个例子,提供了一个公式,如下:
写成矩阵形式:
我们把
注意,这里好像有点问题:屏幕像素大小是
所以视口变换应该是:
正交投影矩阵
这里的正交投影应该指的是平行正交投影,最简单的一种,只需要垂直移动到图像上就可以了
首先,将视线方向的方向记作
然后,框一个长方体
构成的空间被称为正交视图空间(orthographic view volume)
从正交视图空间到规范视空间的变换很简单:
写成矩阵就是:
从正交视图空间到屏幕空间变换就是把上面得到的两个矩阵相乘,即:
画线段的伪代码:
construct M_vp
construct M_orth
M = M_vp M_orth
for each line-segment (a_i, b_i) do
p = M a_i
q = M b_i
drawline(x_p, y_p, x_q, y_q)
相机变换(Camera Transformation)
相机变换就是世界空间到相机空间的变换
有许多约定用于指定相机的位置和方向。我们将使用以下一种:
- 眼睛的位置
- 注视方向(gazing direction)
- 相机的向上向量
通过这三个向量来构建一个坐标系
首先构建一个正交基:
然后加上位移
上一章中说,仿射变换可以分解成线性变换和平移变换,它可以写成:
其中,我们知道左上的坐标系变换是正交矩阵(因为它就是由三个正交向量组成),所以后面矩阵的逆可以很轻松地求出来
前面的矩阵是平移变换,所以根据数学意义也可以轻松求出
所以:
画线段的伪代码:
construct M_vp
construct M_orth
construct M_cam
M = M_vp M_orth M_cam
for each line-segment (a_i, b_i) do
p = M a_i
q = M b_i
drawline(x_p, y_p, x_q, y_q)
投影变换(Projective Transformations)
对于透视投影,我们要把空间中的点映射到规范视空间中,我们会用到
传统的矩阵变换做不到这样(除法)
我们使用一个简单的方法推广齐次坐标的机制来进行除法:
对于之前的齐次坐标,
现在,我们让第四维是
线性变换允许我们计算:
仿射变换允许我们计算:
将
但是,还有一个限制,就是
表示成矩阵形式如下:
并且:
这样的变换称为投影变换(projective transformation)或者单应变换(homography)
有一种更优雅的方式来解释
这表示两个齐次坐标
这些点构成了一条直线
在需要笛卡尔坐标时,只需要找到它和
其实就是说给齐次向量乘上一个倍数不影响它表示的坐标
透视投影
使用投影变换后,前面的
根据惯例,在相机空间中,相机朝向
为什么
规范视空间是
上面是最常用的一种变换,它保证了当
写成矩阵形式为:
这个矩阵被称为透视矩阵(perspective matrix)
变换为:
我们看一下
由于乘上一个系数没有影响,我们乘上一个
我们乘上
一个问题是如何确定
相乘之后
在 OpenGL 中,它会让我们指定
其他的图像 API 中,通常将
规范视空间有时还会设置为
上面的决策都会改变投影矩阵
变换线段的伪代码:
construct M_vp
construct M_per
construct M_cam
M = M_vp M_per M_cam
for each line-segment (a_i, b_i) do
p = M a_i
q = M b_i
drawline(x_p, y_p, x_q, y_q)
透视变换的一些性质
直线性
一个重要性质是将线转换为线,将平面转换为平面,另外将线段转换为线段,例如,我们有这样的线段:
对它进行透视变换:
如果没有同质化,那么肯定存在线性关系,且
经过同质化后,
其中,我们如果可以找到一个线性关系:
我们就可以知道:原来是一条直线上的点,经过透视变换并同质化后仍然在一条直线上
进行一些操作:
如果我们表示成
经过透视变换后:
然后经过同质化后:
其中:
我们发现确实是这样,而且,
视野(Field-of-View)
虽然我们可以使用
这样的话只需要两个自由度就能表示这个窗口
如果我们添加了这样一个约束:
来表示“图像的性质没有失真”,即二者比例相同。
一旦二者比值被指定,那么还需要一个自由度就可以表示这个窗口了,通常使用视野来指定:
在某些系统中,
问题和练习
在透视矩阵中:
当有一个线段,它跨越了
在透视变换之后,需要把
构建视口矩阵,其中像素坐标从图像顶部向下计数:
那么矩阵为:
视口矩阵与正交矩阵相乘的意义是:一个长方体映射到正方体,再将
与 坐标映射到屏幕空间。两个操作合在一起就是将 映射到略
从代数角度证明透视矩阵保留了视场内的
值顺序。略略
略
略
略
略
使用前面的办法构建正交基即可?
根据
很容易证