在前面的章节中,我们看到了如何使用矩阵变换作为在二维或三维空间中排列几何对象的工具。 几何变换的第二个重要用途是在 3D 世界的 2D 视图中移动它们的 3D 位置与其位置之间的对象。这种 3D 到 2D 映射称为视图变换,它在对象顺序渲染中起着重要作用,其中我们需要快速找到场景中每个对象的图像空间位置。
我们在第 4 章中研究光线追踪时,我们涵盖了不同类型的透视视图和正交视图,以及如何根据任何给定视图生成视图射线。 本章是关于该过程的逆过程。在这里,我们解释了如何使用矩阵变换来表达任何平行或透视视图。视图变换将场景(世界空间)中的 3D 点投影到图像(图像空间)中的 2D 点,它将给定像素射线上的任何点投影回图像空间的像素位置上。
将点从世界投影到图像只适用于生成线框渲染——渲染只绘制物体的边缘,较近的表面不遮挡更远的表面。正如光线跟踪器需要沿着每条观察光线找到最近的表面相交一样,逐物体的渲染器也需要确定正在绘制的像素点对应空间中哪个最近的几何体表面。
在本章中,我们假设我们正在绘制一个线框模型,这些线段由它的两个端点确定。后面的章节将讨论产生固体表面渲染所需的机制。
视图变换的工作是将 3D 位置映射到图像中的坐标,以像素为单位表示。这是一个复杂的过程,取决于许多不同的东西,包括相机位置和方向、投影类型、视场和图像的分辨率。与所有复杂的转换一样,最好通过将它分解成几个更简单的转换的乘积来接近。大多数图形系统通过三个步骤来做到这一点:
- 摄相机变换或视变换,这是一种刚体变换,它将摄像机的位置视为原点。它仅取决于相机的位置和方向或姿势。
- 投影变换,它从摄像机空间中将点投影(在相机的右向量和上向量上作规格化)到-1 和 1 之间。它仅取决于所需的投影类型。
- 视口变换或窗口变换,它将这个单位图像矩形映射到像素坐标中所需的矩形。它仅取决于输出图像的大小和位置。
摄像机变换将点从规范坐标(或世界空间)转换到到相机坐标(将它们放置在相机空间中)。投影变换将点从相机空间移动到规范视图中。最后,视窗变换将标准视见体映射到屏幕空间。
我们假设我们想要观察的几何图形在标准视图体积中,并且我们希望使用正交相机朝-z 方向观察它。 标准视图体积是包含笛卡尔坐标在-1 和+1 之间的所有 3D 点的立方体(并非所有几何体都在-1 和 1 之间,之外的几何体摄像机看不见)。我们将 x=-1 投影到屏幕左侧,x=+1 投影到屏幕右侧,y=-1 投影到屏幕底部,和 y=+1 到屏幕顶部。
回顾第 3 章中关于像素坐标的约定:每个像素拥有一个以整数坐标为中心的单位正方形;图像边界有一个半单位的块超过像素中心。最小的像素中心坐标是(0,0)。如果我们要绘制一个由 NY 像素组成的图像(或屏幕上的窗口),我们需要将正方形[-1,1]2 映射到矩形[-0.5,n-0.5]×[-0.5,NY-0.5]。
现在,我们假设所有要绘制的线段都完全位于标准视图体积内(裁剪将稍后讨论)。 由于视区变换将一个轴对齐的矩形映射到另一个,它的公式是: 注意,这个矩阵忽略了标准视区中点的 z 坐标,因为一个点在投影方向上的距离不会影响该点在图像中的投影位置。但是在我们正式称之为视口矩阵之前,我们添加了一行和一列来携带 z 坐标而不改变它。我们在本章中不需要它,但是最终我们将需要 z 值,因为它们可以用来几何体的远近。
当然,我们希望渲染不只局限于标准视图体积。我们在生成视点的第一步将保持视点方向和方向不变,但允许查看任意矩形。我们将在视窗变换的右侧另外乘上一个矩阵来实现投影变换。
在这些约束下,视点体积是一个轴对齐的长方体,大小为$[l,r]\times[b,t]\times[f,n]$。我们称它为正交视图体积。
f 和 n 分别是近平面和远平面
从正交视图体积到规范视图体积的变换是另一个窗口变换,因此我们可以简单地将正交视见体和规范视见体的边界代入方程,以获得该变换的矩阵: 为了在正交视图体中绘制 3D 线段,我们将它们投影到屏幕的 x 和 y 坐标中,并忽略 z 坐标。我们通过组合等式来实现这一点。注意,在程序中,我们将这些矩阵相乘形成一个矩阵: $$\begin{bmatrix} x_{pixel}\y_{pixel}\z_{canonical}\1 \end{bmatrix}=\big( M_{vp}\cdot M_{orth} \big)\begin{bmatrix} x\y\z\1 \end{bmatrix}$$ 现在,z 轴分量在-1 到 1 之间,它们在后续的 z-buffer 程序中会发挥作用。
我们希望能够在 3D 中改变视点并以任何视角观察几何体。因此需要以下信息:
- 摄像机位置 e
- 视方向 g
- 摄像机上向量 t
眼睛的位置是眼睛“看到”的位置。如果你认为图形是一个摄影过程,它是透镜的中心。凝视方向是观察者正在观看方向上的任何矢量。上矢量是平面上的任何矢量,这个平面既将观察者的头部一分为二,又指向站在地面上的人“指向天空”(t 不一定要和 g 垂直,只要能和 g 构建一个平面就行)。这些矢量为我们提供了足够的信息来建立以 e 为原点以 UVW 为基准的坐标系: $$\begin{cases} w=- \frac{g}{\Vert g \Vert}\ u=\frac{t\times w}{\Vert t\times w\Vert}\ v=w\times u\end{cases}$$ 如果我们想要变换的所有点都存储在以原点 e 和基矢量 uvw 的坐标中,我们的工作就完成了。但是,模型是以规范世界坐标的形式存储的。我们只需将希望绘制的线段端点的坐标从 xyz 坐标转换为 uvw 坐标。实现这种变换的矩阵是: 或者,可以将此变换视为首先将 e 移动到原点,然后将 u、v、w 对齐到 x、y、z。
要使以前仅限 z 轴的查看算法适用于任何位置和方向的相机,我们只需将此相机变换添加到视窗变换与投影变换的点乘中。
为了了解我们需要做什么,让我们看看透视投影变换需要对相机空间中的点做些什么。回想一下,视点位于原点,相机沿着 z 轴观看。 透视的关键是,对于一只在原点抬头看负 z 轴的眼睛来说,屏幕上对象的大小与 1/z 成比例(越远的物体越小)。
图中位于距离 z 的大小为 y,他应该在画面中显示的大小为 ys
我们希望用矩阵的机制计算透视投影。然后,我们可以简单地将另一个矩阵相乘到我们的复合矩阵中,并使用我们已经拥有的算法。然而,这种类型的变换,其中输入向量的坐标之一出现在分母中,不能用仿射变换来实现。
我们可以用一个简单的方法推广我们在仿射变换中齐次坐标的机制来进行除法。我们已经拥有用齐次向量[x y z 1]来表示点(x, y, z)的共识。额外的坐标 w 总是等于 1,这是通过总是使用[0 0 0 1]T 作为仿射变换矩阵的第四行来保证的。
我们不再仅仅将 1 视为附加在矩阵乘法上以实现平移的额外部分,而是将其定义为 x、y 和 z 坐标的分母:齐次向量[x y z w]表示点(x/w, y/w, z/w)。当 w = 1 时,这没有什么区别,但如果我们允许变换矩阵的底行中有任何值,则可以实现更大范围的变换,从而使 w 取 1 以外的值。
在 2D 齐次坐标中,我们使用 3 向量来表示平面中的点,我们可以使用齐次向量[-2;-1;2]T 来表示点(-1,-0.5),或直线上的任何其他点 xa[-1-0.5 1]T。直线上的任何齐次向量都可以映射到直线与平面 w1 的交点上,以获得其笛卡尔坐标。
可以根据需要多次变换齐次向量,而不必担心 w 坐标的值——事实上,w 坐标在某些中间阶段为零也是可以的。只有当我们需要一个点的有序笛卡尔坐标时,我们才需要将其归一化为具有 w=1 的等价点。
投影变换的机制使得实现透视所需的 z 除法变得简单。对于 8.2 一开始的那张图而言,投影变换可以这么写: $$\begin{bmatrix} y_s\1 \end{bmatrix}\sim\begin{bmatrix} dy\ z \end{bmatrix}=\begin{bmatrix} d&0&0\0&0&1 \end{bmatrix}\begin{bmatrix} y\z\1 \end{bmatrix}$$ 对于 3D 中的“标准”透视投影矩阵,我们将采用通常的惯例,即在面向- z 方向的原点处设置摄像机,。 与正交投影一样,我们也采用了远近平面的概念,这限制了可以看到的距离范围。在这种情况下,我们将使用近平面作为投影平面,因此像平面距离为- n(近平面在-z 方向上,n 是负数)。 $$P=\begin{bmatrix} n&0&0&0\0&n&0&0\0&0&n+f&-fn\0&0&1&0 \end{bmatrix}$$ 第一行、第二行和第四行简单地实现了透视图方程。第三行,就像在正交投影和视口矩阵中一样,被设计成带着 z 分量保留下来,这样我们就可以在以后使用它来移除被遮住的表面。 在透视投影中,不寻常的分母的加入使我们无法保留 z 的值——实际上,让 x 和 y 的值有意义的同时,还能让 z 分量保持不变是不可能的。相反,我们选择保持近平面或远平面上的点的 z 不变。
有许多矩阵可以作为透视矩阵,它们都非线性地扭曲了 z 坐标(为什么要非线性的扭曲 z 轴?)。它使(z = n)平面上的点完全独立,并使(z = f)平面上的点在 x 和 y 方向上适当地“挤压”。矩阵对点(x, y, z)的影响为: (这个公式对 z 轴的变换是非线性的) x 和 y 是按比例缩放的,更重要的是除以 z。因为 n 和 z(在视区内)都是负数,所以 x 和 y 中没有翻转。变换还保留了 z=n 和 z=f 之间的 z 值的相对顺序,允许我们在应用此矩阵后进行深度排序。
[!NOTE] 关于透视投影矩阵 这里引用和整理知乎大佬的分析:图形学:正交/透视投影矩阵的推导(多个思路) - 知乎 (zhihu.com) 请看这份笔记:关于透视投影矩阵的推导
有时,我们会想要取矩阵 P 的逆,例如,将屏幕坐标加 z 带回原始空间, 由于在齐次空间中数乘变换矩阵不会改变变换后点的实际位置,P 的逆变换可以这么写:
透视矩阵简单地将透视视图体积(其形状类似于金字塔的切片或截锥体)映射到正射影体(其是一个与轴线对齐的盒子)。透视矩阵的美妙之处在于,一旦我们应用了它,我们就可以使用正交变换来获得规范视图体积。因此,所有的正交变换机制都适用,我们所添加的只是一个矩阵和除以 w。
透视矩阵只是将截锥体变换成了立方体,对立方体再应用一次正交变换(透视矩阵右乘正交变换矩阵),才是完整的透视投影变换。
感觉没什么用。。。
虽然我们可以用(l,r,t,b)和 n 来指定任意的窗口,但有时我们希望有一个更简单的系统。者需要一些约束条件,比如,我们向窗口的中心看去: