正交投影矩阵和透视投影矩阵

在介绍投影矩阵之前,需要先说明一下标准化设备坐标空间,即 NDC 空间。它为后续的图形处理提供统一的坐标系统。

NDC 空间每个轴的范围都在 -1 到 1。本篇文章讲的正交投影矩阵和透视投影矩阵都要映射到 NDC 空间。

1. 正交投影矩阵

在正交投影中,不同深度的对象大小是一样的,不会因为距离而变化。

我们首先指定正交投影需要的参数。left、right、bottom 和 top,指定视图体积在 x 轴和 y 轴上的边界;near 和 far 指定视图体积在 z 轴上的边界。

正交投影这边的视图体积对应的一个立方体。如果我们要把它映射到 NDC 空间的话,可以先把中心点移动到坐标原点,然后再进行大小缩放。

视图立方体对应的中心点为 \((\frac{\textbf{left}+\textbf{right}}{2},\frac{\textbf{bottom}+\textbf{top}}{2},\frac{\textbf{near}+\textbf{far}}{2})\),因此平移矩阵为

\( \begin{pmatrix} 1 & 0 & 0 & -\frac{\textbf{left}+\textbf{right}}{2} \\ 0 & 1 & 0 & -\frac{\textbf{bottom}+\textbf{top}}{2} \\ 0 & 0 & 1 & -\frac{\textbf{near}+\textbf{far}}{2} \\ 0 & 0 & 0 & 1 \end{pmatrix} \)

缩放值是长宽高对应的比例,所以缩放矩阵为

\( \begin{pmatrix} \frac{2}{\textbf{right}-\textbf{left}} & 0 & 0 & 0 \\ 0 & \frac{2}{\textbf{top}-\textbf{bottom}} & 0 & 0 \\ 0 & 0 & \frac{2}{\textbf{far}-\textbf{near}} & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} \)

把缩放矩阵和平移矩阵相乘,就能得到最终的正交透视矩阵

\( M_{ortho}= \begin{pmatrix} \frac{2}{\textbf{right}-\textbf{left}} & 0 & 0 & -\frac{\textbf{right}+\textbf{left}}{\textbf{right}-\textbf{left}} \\ 0 & \frac{2}{\textbf{top}-\textbf{bottom}} & 0 & -\frac{\textbf{top}+\textbf{bottom}}{\textbf{top}-\textbf{bottom}} \\ 0 & 0 & \frac{2}{\textbf{far}-\textbf{near}} & -\frac{\textbf{far}+\textbf{near}}{\textbf{far}-\textbf{near}} \\ 0 & 0 & 0 & 1 \end{pmatrix} \)

2. 透视投影矩阵

在透视投影中,物体会随着距离的增加而看起来越来越小,即模拟了人眼对深度的感知。

针对透视投影我们定义和正交投影相同的参数。如图 1 所示,透视投影因为“视线射线”作用,视图体积对应的是四棱台。我们目前转化的思路是,想把这个四棱台也“压缩成”立方体,然后就能套用正交投影的过程,转化到 NDC 空间。

图1 思路

这边对应的是棱台的原因是,near 后续截面和 near 近截面大小不一致。“压缩”的思路就是把后续截面上的点“映射”到近截面的范围。

以侧视图为例,如图 2 所示,我们通过“视线射线”把视图范围内的一个点,“映射”到近平面范围。通过相似三角形可得

\(\frac{\textbf{near}}{y^\prime}=\frac{z}{y},y^\prime=\frac{\textbf{near}}{z}y\)

同理,通过俯视图可以得到 \(x^\prime=\frac{\textbf{near}}{z}x\)

式子也反应了“进大远小”的效果。

图2 侧视图

目前我们“映射”的思路是这样的 \((x,y,z)\rightarrow ({\frac{\textbf{near}}{z}x,\frac{\textbf{near}}{z}y,z})\)。单纯写成变换矩阵为

\( \begin{pmatrix} \frac{\textbf{near}}{z} & 0 & 0 \\ 0 & \frac{\textbf{near}}{z} & 0 \\ 0 & 0 & 1 \end{pmatrix} \)

但是这边的 \(z\) 是变量,操作不了。我们试着减少 \(z\) 变量的数量,同乘以 \(z\)。引入齐次坐标,记录 \(z\):

\(({\frac{\textbf{near}}{z}x,\frac{\textbf{near}}{z}y,z,1})\rightarrow (\textbf{near}\cdot x,\textbf{near}\cdot y,z^2,z)\)

这时,可以发现的确使用到 \(z\) 的地方变少了,只有第三行使用到了。

\( \begin{pmatrix} \textbf{near} & 0 & 0 & 0\\ 0 & \textbf{near} & 0 & 0\\ 0 & 0 & z & 0 \\ 0 & 0 & 1 & 0 \end{pmatrix} \)

消除这个 \(z\),我们采用解线性方程组来求得,记

问题就在这个 \(z^2\) 上,看着不能线性表示。

虽然不知道这个问题实际上是不是个线性问题,但是这边既然已经用到矩阵了,就只能把它当作线性问题了。

我是这样说服自己的。

\( \begin{pmatrix} \textbf{near} & 0 & 0 & 0\\ 0 & \textbf{near} & 0 & 0\\ 0 & 0 & A & B \\ 0 & 0 & 1 & 0 \end{pmatrix} \)

有两个和 \(z\) 相关的变量待解,需要两条方程。我们取两个“映射”时的情况:

一个是近平面上的点,经过映射后,点不变。即

\((x,y,\textbf{near},1)\rightarrow (x\cdot \textbf{near},y\cdot \textbf{near},\textbf{near}^2,\textbf{near})\)

另一个是远平面的中心点,经过映射后,点不变。即

\((0,0,\textbf{far},1)\rightarrow (0,0,\textbf{far}^2,\textbf{far})\)

代入可得

\( \begin{flalign} \left\{ \begin{aligned} A\cdot \textbf{near} + B &= \textbf{near}^2 \\ A\cdot \textbf{far} + B &= \textbf{far}^2 \end{aligned} \right. \end{flalign} \)

解得

\(A=\textbf{near}+\textbf{far},B=-\textbf{near}\cdot \textbf{far}\)

即“压缩”变换矩阵为

\( \begin{pmatrix} \textbf{near} & 0 & 0 & 0\\ 0 & \textbf{near} & 0 & 0\\ 0 & 0 & \textbf{near}+\textbf{far} & -\textbf{near}\cdot \textbf{far} \\ 0 & 0 & 1 & 0 \end{pmatrix} \)

既然已经“压缩”成立方体了,我们只需要复用上一节中的正交投影矩阵 \(M_{ortho}\),相乘得到透视投影矩阵为

\( M_{perspective}= \begin{pmatrix} \frac{2\cdot\textbf{near}}{\textbf{right}-\textbf{left}} & 0 & \frac{\textbf{left}+\textbf{right}}{\textbf{left}-\textbf{right}} & 0 \\ 0 & \frac{2\cdot\textbf{near}}{\textbf{top}-\textbf{bottom}} & \frac{\textbf{bottom}+\textbf{top}}{\textbf{bottom}-\textbf{top}} & 0 \\ 0 & 0 & \frac{\textbf{far}+\textbf{near}}{\textbf{far}-\textbf{near}} & \frac{2\cdot \textbf{far} \cdot \textbf{near}}{\textbf{near}-\textbf{far}} \\ 0 & 0 & 1 & 0 \end{pmatrix} \)

我们可以对这个矩阵进行“改造”一下。因为我们之前代入方程求解的时候,已经假设裁剪平面的中心在坐标轴上了,即裁剪平面是对称的。

我们引入视场角 fov 和宽高比 aspect 这两个变量来替换近平面 left、right、top、bottom 这四个变量。

如图 3 所示,我们可以得到

\(\textbf{top}=\textbf{near}\cdot tan(\frac{\textbf{fov}}{2}),\textbf{bottom}=-\textbf{near}\cdot tan(\frac{\textbf{fov}}{2})\)

图3 fov

再根据宽高比,可以求得

\(\textbf{right}=\textbf{aspect}\cdot \textbf{near}\cdot tan(\frac{\textbf{fov}}{2}),\textbf{left}=-\textbf{aspect}\cdot \textbf{near}\cdot tan(\frac{\textbf{fov}}{2})\)

最终,代入原先的 \(M_{perspective}\) 中,得到

\( M_{perspective}= \begin{pmatrix} \frac{1}{\textbf{aspect}\cdot tan(\frac{\textbf{fov}}{2})} & 0 & 0 & 0 \\ 0 & \frac{1}{tan(\frac{\textbf{fov}}{2})} & 0 & 0 \\ 0 & 0 & \frac{\textbf{far}+\textbf{near}}{\textbf{far}-\textbf{near}} & \frac{2\cdot \textbf{far} \cdot \textbf{near}}{\textbf{near}-\textbf{far}} \\ 0 & 0 & 1 & 0 \end{pmatrix} \)