4.变换进阶

4.变换进阶


4.1 概述

主要内容:

  • 三维变换(3D Transformations)
  • 观测变换(Viewing Transformation)
    • 视图 / 相机变换(View / Camera Transformation)
    • 投影变换(Projection Transformation)
      • 正交投影(Orthographic Projection)
      • 透视投影(Perspective Projection)

从模型到最终画面,通常要经过三个主要变换:

  • 模型变换(Model Transformation):利用平移、旋转、缩放等变换,把模型从自己的局部坐标系放到世界坐标系中。
  • 视图变换(View Transformation):把世界变换到以相机为中心的坐标系。
  • 投影变换(Projection Transformation):把相机看到的三维空间进一步投影到二维画面,分为正交投影和透视投影。

因此整个过程可以概括为:

Model → View → Projection

也就是常见的 MVP 变换。


4.2 三维变换

旋转矩阵的逆

二维旋转矩阵有一个很实用的性质:

$$
R(-\theta)=R(\theta)^{-1}=R(\theta)^T
$$

也就是说,旋转矩阵的逆等于它的转置。

满足 $R^{-1}=R^T$ 的矩阵称为正交矩阵(Orthogonal Matrix)。后面的视图变换会直接用到这个性质。

三维齐次坐标

三维空间继续使用齐次坐标:

  • 三维点:$(x,y,z,1)^T$
  • 三维向量:$(x,y,z,0)^T$

对于 $(x,y,z,w)^T$,只要 $w\neq0$,它表示三维空间中的点:

$$
\left(\frac{x}{w},\frac{y}{w},\frac{z}{w}\right)
$$

三维仿射变换使用 $4\times4$ 矩阵,左上角 $3\times3$ 描述线性变换,最后一列描述平移。

缩放与平移

三维缩放矩阵:

$$
S(s_x,s_y,s_z)=
\begin{pmatrix}
s_x&0&0&0\\
0&s_y&0&0\\
0&0&s_z&0\\
0&0&0&1
\end{pmatrix}
$$

三维平移矩阵:

$$
T(t_x,t_y,t_z)=
\begin{pmatrix}
1&0&0&t_x\\
0&1&0&t_y\\
0&0&1&t_z\\
0&0&0&1
\end{pmatrix}
$$

绕坐标轴旋转

绕 $x$ 轴旋转时,$x$ 坐标不变,本质上是在 $yz$ 平面内做二维旋转:

$$
R_x(\alpha)=
\begin{pmatrix}
1&0&0&0\\
0&\cos\alpha&-\sin\alpha&0\\
0&\sin\alpha&\cos\alpha&0\\
0&0&0&1
\end{pmatrix}
$$

绕 $y$ 轴:

$$
R_y(\alpha)=
\begin{pmatrix}
\cos\alpha&0&\sin\alpha&0\\
0&1&0&0\\
-\sin\alpha&0&\cos\alpha&0\\
0&0&0&1
\end{pmatrix}
$$

绕 $z$ 轴:

$$
R_z(\alpha)=
\begin{pmatrix}
\cos\alpha&-\sin\alpha&0&0\\
\sin\alpha&\cos\alpha&0&0\\
0&0&1&0\\
0&0&0&1
\end{pmatrix}
$$

$R_y$ 的符号看起来和另外两个不太一样,原因是右手系下满足循环关系,叉乘的时候 $x\times y=z$、$y\times z=x$、$z\times x=y$。

欧拉角(Euler Angles)

一般的三维旋转可以组合三个坐标轴方向的旋转:

$$
R_{xyz}(\alpha,\beta,\gamma)
=R_x(\alpha)R_y(\beta)R_z(\gamma)
$$

三个旋转角称为欧拉角(Euler Angles)。在飞行中经常对应 Roll(翻滚)、Pitch(俯仰)、Yaw(偏航)。

罗德里格斯旋转公式

绕经过原点的单位轴 $\mathbf n$ 旋转 $\alpha$ 时:

$$
R(\mathbf n,\alpha)
=\cos\alpha I
+(1-\cos\alpha)\mathbf n\mathbf n^T
+\sin\alpha N
$$

其中矩阵 $N$ 满足:

$$
N\mathbf x=\mathbf n\times\mathbf x
$$

补充材料给出的推导思路很直观:把待旋转向量分成平行于旋转轴和垂直于旋转轴的两部分。平行分量保持不变,垂直分量在垂直平面内做二维旋转,最后再合并。

如果旋转轴不经过原点,可以和二维绕任意点旋转一样处理:先把旋转轴平移到原点,再旋转,最后平移回去。


4.3 观测变换(Viewing Transformation)

视图 / 相机变换(View / Camera Transformation)

拍一张照片可以拆成三步:

  1. 把人物和场景摆好 —— 模型变换(Model Transformation)。
  2. 把相机放到合适的位置和角度 —— 视图变换(View Transformation)。
  3. 按下快门,把三维世界变成二维图像 —— 投影变换(Projection Transformation)。

定义相机

一个相机需要三个量:

  • 位置:$\mathbf e$
  • 观察方向:$\hat{\mathbf g}$
  • 向上方向:$\hat{\mathbf t}$

其中观察方向和向上方向通常取单位向量,并假设彼此垂直。

只知道相机位置和观察方向还不够,因为相机还可以绕观察方向自身旋转;向上方向用来确定这个自由度。

把相机变换到标准位置

关键是相对运动:如果相机和场景中的所有物体一起做相同的变换,最终拍出的图像不会改变。

因此可以统一约定相机始终:

  • 位于原点 $(0,0,0)$
  • 向上方向为 $+Y$
  • 观察方向为 $-Z$

我们理解真正变化的是整个场景。相机就是在原点一直不动的观察者。这样做是因为把相机放到这样一个标准位置有一些好处的。

视图变换矩阵

视图变换的目标,是把任意位置、任意朝向的相机变换到标准位置:

  • 相机位置移动到原点。
  • 观察方向 $\hat{\mathbf g}$ 对齐 $-Z$。
  • 向上方向 $\hat{\mathbf t}$ 对齐 $+Y$。
  • 右方向 $\hat{\mathbf g}\times\hat{\mathbf t}$ 对齐 $+X$。

因此视图矩阵可以拆成平移 + 旋转:

$$
M_{view}=R_{view}T_{view}
$$

使用列向量时,矩阵从右向左作用,所以这里表示:先平移,再旋转。

平移到原点

假设相机位置为:

$$
\mathbf e=(x_e,y_e,z_e)
$$

要把相机移动到原点,只需要对整个场景平移 $-\mathbf e$:

$$
T_{view}=
\begin{pmatrix}
1&0&0&-x_e\\
0&1&0&-y_e\\
0&0&1&-z_e\\
0&0&0&1
\end{pmatrix}
$$

例如相机位于 $(3,2,5)$,那么整个场景都平移 $(-3,-2,-5)$。
这样从相机看来画面不会发生变化,但相机的位置变成了原点。

旋转到标准方向

平移之后,相机虽然已经位于原点,但朝向仍然可能是任意的。

接下来需要把相机的三个方向:

$$
\hat{\mathbf g}\times\hat{\mathbf t},
\qquad
\hat{\mathbf t},
\qquad
-\hat{\mathbf g}
$$

分别旋转到标准坐标轴:

$$
X,\qquad Y,\qquad Z
$$

也就是:

  • $\hat{\mathbf g}\times\hat{\mathbf t}\rightarrow X$
  • $\hat{\mathbf t}\rightarrow Y$
  • $-\hat{\mathbf g}\rightarrow Z$

直接写这个旋转矩阵不太好写,但它的逆变换很好写。

逆变换做的事情正好相反:

$$
X\rightarrow\hat{\mathbf g}\times\hat{\mathbf t}
$$

$$
Y\rightarrow\hat{\mathbf t}
$$

$$
Z\rightarrow-\hat{\mathbf g}
$$

矩阵的每一列就是一个标准基向量变换后的结果,因此:

$$
R_{view}^{-1} =
\begin{pmatrix}
x_{\hat g\times\hat t}&x_{\hat t}&x_{-\hat g}&0\\
y_{\hat g\times\hat t}&y_{\hat t}&y_{-\hat g}&0\\
z_{\hat g\times\hat t}&z_{\hat t}&z_{-\hat g}&0\\
0&0&0&1
\end{pmatrix}
$$

而旋转矩阵是正交矩阵,满足:

$$
R_{view}^{-1}=R_{view}^{T}
$$

所以只需要把上面的逆矩阵转置,就得到真正的视图旋转矩阵:

$$
R_{view} =
\begin{pmatrix}
x_{\hat g\times\hat t}&y_{\hat g\times\hat t}&z_{\hat g\times\hat t}&0\\
x_{\hat t}&y_{\hat t}&z_{\hat t}&0\\
x_{-\hat g}&y_{-\hat g}&z_{-\hat g}&0\\
0&0&0&1
\end{pmatrix}
$$

最终:

$$
M_{view}=R_{view}T_{view}
$$

核心思路就是:先把相机位置搬到原点,再把相机自身的三个坐标轴对齐到标准的 $X$、$Y$、$Z$ 方向。

实际计算时并不是把相机真的移动了,而是对整个场景施加相反的变换,使相机看起来固定在标准位置。

模型变换和视图变换通常连续进行,因此经常合称为 ModelView Transformation。

小结

投影变换(Projection Transformation)

投影负责把三维空间变成二维图像,主要有两种:

  • 正交投影(Orthographic Projection)
  • 透视投影(Perspective Projection)

两者最直观的区别是:

  • 正交投影没有明显的近大远小。
  • 透视投影符合人眼和相机的成像直觉,物体越远看起来越小,平行线也可能在图像中汇聚。

正交投影(Orthographic Projection)

直观理解

相机位于原点、观察 $-Z$、$+Y$ 向上时,一个最简单的理解方式是:

  1. 丢掉 $Z$ 坐标。
  2. 将剩下的二维区域平移、缩放到 $[-1,1]^2$。

真正的矩阵推导会保留深度信息,而不是简单把 $Z$ 丢掉。

映射到标准立方体

把空间中的长方体:

$$
[l,r]\times[b,t]\times[f,n]
$$

映射到标准立方体:

$$
[-1,1]^3
$$

只需要两步:

  1. 平移:把长方体中心移动到原点。
  2. 缩放:让三个方向的长度都变成 $2$。
正交投影矩阵

$$
M_{ortho}=
\begin{pmatrix}
\frac{2}{r-l}&0&0&0\\
0&\frac{2}{t-b}&0&0\\
0&0&\frac{2}{n-f}&0\\
0&0&0&1
\end{pmatrix}
\begin{pmatrix}
1&0&0&-\frac{r+l}{2}\\
0&1&0&-\frac{t+b}{2}\\
0&0&1&-\frac{n+f}{2}\\
0&0&0&1
\end{pmatrix}
$$

使用列向量时,右边的平移矩阵先执行,然后再缩放。

由于相机观察 $-Z$,课件直接用空间中的 $z$ 坐标表示 near 和 far,因此数值上有:

$$
n>f
$$

这个地方很容易因为不同坐标系约定而写反。

透视投影(Perspective Projection)

特点

透视投影具有两个非常直观的现象:

  • 近大远小。
  • 三维空间中的平行线,投影到图像后可能汇聚到同一个消失点。

回顾

先挤压,再做正交投影

透视投影可以拆成两步:

  1. 用 $M_{persp\to ortho}$ (从透视到正交的矩阵)把视锥体挤压成长方体,并保持近平面 $n$ 和远平面 $f$ 的 $z$ 值不变。
  2. 对得到的长方体做已经推导过的正交投影 $M_{ortho}$。

最终:

$$
M_{persp}=M_{ortho}M_{persp\to ortho}
$$

相似三角形得到 x、y

从侧面看视锥,通过相似三角形:

$$
y^{\prime}=\frac{n}{z}y
$$

同理:

$$
x^{\prime}=\frac{n}{z}x
$$

也就是说,深度 $z$ 越远,$x$、$y$ 被压缩得越多,这就是近大远小在数学上的来源。

利用齐次坐标写成矩阵

前面通过相似三角形已经得到:

\[
x^{\prime}=\frac{nx}{z},
\qquad
y^{\prime}=\frac{ny}{z}
\]

所以挤压后的点可以先写成:

\[
\begin{pmatrix}
\frac{nx}{z}\\
\frac{ny}{z}\\
z^{\prime}\\
1
\end{pmatrix}
\]

问题在于,矩阵乘法只能做线性组合,没法直接表示 \(x/z\) 这样的除法。

这里利用齐次坐标:

\[
(x,y,z,1)^T
\equiv
(kx,ky,kz,k)^T
\]

也就是说,齐次坐标整体乘上同一个非零数,表示的仍然是同一个点。

因此把上面的结果整体乘以 \(z\):

\[
\begin{pmatrix}
\frac{nx}{z}\\
\frac{ny}{z}\\
z^{\prime}\\
1
\end{pmatrix}
\equiv
\begin{pmatrix}
nx\\
ny\\
zz^{\prime}\\
z
\end{pmatrix}
\]

第三项还没有求出来,先记成 unknown:

\[
\begin{pmatrix}
nx\\
ny\\
\text{unknown}\\
z
\end{pmatrix}
\]

这样原来的除法就暂时消失了,可以开始写矩阵。

希望:

\[
M_{persp\to ortho}
\begin{pmatrix}
x\\
y\\
z\\
1
\end{pmatrix} =
\begin{pmatrix}
nx\\
ny\\
\text{unknown}\\
z
\end{pmatrix}
\]

第一项要得到 \(nx\),所以第一行是:

\[
(n,0,0,0)
\]

第二项要得到 \(ny\),第二行是:

\[
(0,n,0,0)
\]

第四项要得到 \(z\),第四行是:

\[
(0,0,1,0)
\]

于是先得到:

\[
M_{persp\to ortho}=
\begin{pmatrix}
n&0&0&0\\
0&n&0&0\\
?&?&?&?\\
0&0&1&0
\end{pmatrix}
\]

这里只剩第三行还没有确定。

求第三行

前面已经确定了挤压矩阵的第一、第二和第四行:

\[
M_{persp\to ortho}=
\begin{pmatrix}
n&0&0&0\\
0&n&0&0\\
?&?&?&?\\
0&0&1&0
\end{pmatrix}
\]

现在只剩第三行,也就是深度怎么变。

深度只和原来的 \(z\) 有关。如果两个点的 \(z\) 一样,只是 \(x、y\) 不同,它们投影后的深度也应该一样。

因此第三行可以写成:

\[
(0,0,A,B)
\]

矩阵暂时变成:

\[
M_{persp\to ortho}=
\begin{pmatrix}
n&0&0&0\\
0&n&0&0\\
0&0&A&B\\
0&0&1&0
\end{pmatrix}
\]

拿一个普通的点:

\[
P=
\begin{pmatrix}
x\\
y\\
z\\
1
\end{pmatrix}
\]

真正乘一次:

\[
M_{persp\to ortho}P =
\begin{pmatrix}
n&0&0&0\\
0&n&0&0\\
0&0&A&B\\
0&0&1&0
\end{pmatrix}
\begin{pmatrix}
x\\
y\\
z\\
1
\end{pmatrix} =
\begin{pmatrix}
nx\\
ny\\
Az+B\\
z
\end{pmatrix}
\]

所以矩阵乘完以后:

第三项:Az + B
第四项:z

注意这时还是齐次坐标。

第三项 \(Az+B\) 还不能直接当成最终的深度,因为第四项已经变成:

\[
w^{\prime}=z
\]

后面还会进行透视除法,也就是整个向量除以 \(w^{\prime}\):

\[
\begin{pmatrix}
nx\\
ny\\
Az+B\\
z
\end{pmatrix}
\longrightarrow
\begin{pmatrix}
\frac{nx}{z}\\
\frac{ny}{z}\\
\frac{Az+B}{z}\\
1
\end{pmatrix}
\]

所以真正的深度是:

\[
z^{\prime}=\frac{Az+B}{z}
\]

现在第三行只剩 \(A、B\) 两个未知数,可以用近平面和远平面两个条件求出来。

先看近平面。

近平面上的点满足:

\[
z=n
\]

挤压以后,近平面仍然要留在原来的深度 \(n\),所以要求:

\[
z^{\prime}=n
\]

把 \(z=n\) 代入刚才的式子:

\[
z^{\prime} =
\frac{An+B}{n}
\]

又因为希望最后结果就是 \(n\):

\[
\frac{An+B}{n}=n
\]

两边乘以 \(n\):

\[
An+B=n^2
\]

为什么右边会变成 \(n^2\)?

因为 \(An+B\) 是透视除法之前的第三项,后面还要除以第四项 \(w^{\prime}=n\)。

想让最终结果是 \(n\),除法前第三项就需要是 \(n^2\):

\[
\frac{n^2}{n}=n
\]

所以近平面给出的条件就是:

\[
An+B=n^2
\]

远平面也是同样的过程。

远平面满足:

\[
z=f
\]

挤压以后,远平面的深度仍然希望保持为:

\[
z^{\prime}=f
\]

把 \(z=f\) 代入:

\[
z^{\prime} =
\frac{Af+B}{f}
\]

要求它等于 \(f\):

\[
\frac{Af+B}{f}=f
\]

两边乘以 \(f\):

\[
Af+B=f^2
\]

原因和近平面一样。

此时第四项:

\[
w^{\prime}=f
\]

所以除法前的第三项需要先变成 \(f^2\),这样透视除法以后才会得到:

\[
\frac{f^2}{f}=f
\]

现在有两个方程:

\[
An+B=n^2
\]

\[
Af+B=f^2
\]

两式相减:

\[
A(n-f)=n^2-f^2
\]

右边使用平方差:

\[
n^2-f^2=(n-f)(n+f)
\]

所以:

\[
A(n-f)=(n-f)(n+f)
\]

由于近平面和远平面不同,\(n\neq f\),约掉 \(n-f\):

\[
A=n+f
\]

再代回:

\[
An+B=n^2
\]

得到:

\[
(n+f)n+B=n^2
\]

展开:

\[
n^2+nf+B=n^2
\]

因此:

\[
B=-nf
\]

第三行就确定了:

\[
(0,0,n+f,-nf)
\]

最后得到完整的挤压矩阵:

\[
M_{persp\to ortho}=
\begin{pmatrix}
n&0&0&0\\
0&n&0&0\\
0&0&n+f&-nf\\
0&0&1&0
\end{pmatrix}
\]

这个矩阵会把透视视锥挤压成长方体,同时让近平面仍然对应 \(n\),远平面仍然对应 \(f\)。

接下来再做正交投影,把这个长方体平移、缩放到 \([-1,1]^3\):

\[
M_{persp} =
M_{ortho}M_{persp\to ortho}
\]


4.4 总结

  • 三维变换是二维变换向 $4\times4$ 齐次矩阵的自然推广。
  • 三维旋转可以由绕三个坐标轴的旋转组合,也可以用罗德里格斯公式描述绕任意过原点轴的旋转。
  • 视图变换利用相对运动,把相机统一变换到原点、观察 -Z、Y 轴向上的标准位置。
  • 正交投影把指定长方体平移、缩放到标准立方体 $[-1,1]^3$。
  • 透视投影先把视锥体挤压成长方体,再做正交投影;近大远小来自 $x^{\prime}=nx/z$、$y^{\prime}=ny/z$。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

赏

×

喜欢就点赞,疼爱就打赏