上一篇: 飞走的盒子
今天,是我从乡下老家返城的第三天。为了拯救这个世界,我决定能不出门就不出门。第一天上午出去买的菜,如果一直放不坏,兴许能吃十天。缺锌,有葡萄糖酸锌片。缺维生素 B,有复合维生素 B 片。这让我觉得,养活一个像我这样的人,成本实在太低了,很容易让我变得没追求。现在想想,我没追求好像已经挺久了。
POV Ray 认为我现在的状态适合继续学习用咒语画画,用线性代数,这是一切图形学的内功。我这才注意到,他今天是以矩阵的形式出现的,而且打量我的眼神像是在观察一个向量。他盯着我看了半天,忽然双掌合十,旋即左掌上升,右掌下降,双掌之间出现一个三维向量,
$$ \begin{bmatrix} x \\ y \\ z \end{bmatrix} $$
然后问我,「它能表示什么?」
「一个点,或一个方向,或三个数字形成的集合什么的。」这点基本的常识,我还是有的。
POV Ray 点点头,「在画画的时候,这个向量可以表示为
。不过,这不是重点。重点是,在画画的时候,当你看到这样的向量时,你知道它表示的点还是方向?」
「如果是我画的,那么在 6 个月后,大概就不知道了。」我想起来计算机软件行业的一个定律,大概是这么说的。
「所有二义性或多义性的东西都可以通过增加信息的方式让它们的含义变得明确。从现在开始,你要记住
$$ \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} $$
表示三维空间中的一个点,而
$$ \begin{bmatrix} x \\ y \\ z \\ 0 \end{bmatrix} $$
表示三维空间中的一个方向。这个叫齐次坐标。」
「你的意思,在画画时,一个点,要写成
?」
「不用。画画的时候,我们没法直接去画一个方向。方向,不过是我们的想象。要画出一个方向,至少要需要两个点。所以,在画画的时候,点的坐标的最后一位是省略的,这个秘密只有我和 povray 知道。」
「都省略了,还学什么齐次坐标?」
「因为齐次坐标能够表示坐标系,也能统一表示所有的仿射变换——旋转、平移、缩放、错切。你不喜欢具有一致性的东西吗?不然,你该出去练习摩托车了,而不是把自己隔离在家中。」
「你说的都对……」我有些累了,开始想念一个人,在某个第四维分量为 0 的向量上。
「现在,有三个方向和一个点,
$$ \begin{bmatrix} 1 \\ 0 \\ 0 \\ 0 \end{bmatrix} \quad \begin{bmatrix} 0 \\ 1 \\ 0 \\ 0 \end{bmatrix} \quad \begin{bmatrix} 0 \\ 0 \\ 1 \\ 0 \end{bmatrix} \quad \begin{bmatrix} 0 \\ 0 \\ 0 \\ 1 \end{bmatrix} $$
你能想像出它们的含义吗?」
「前三个,似乎分别是 X,Y,Z 轴的正方向,第四个是原点吧?」
「然。如果把它们写到一起,就是一个矩阵,
$$ \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} $$
这个矩阵表示的就是世界坐标系,而且它恰好也是一个单位矩阵。当我们说一个点可以表示为
$$ \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} $$
时,实际上它应该写成
$$ \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} $$
只是因为世界坐标系是单位矩阵,所以被省略了。这个点,应该叫世界坐标系下的点。」说完,POV Ray 停顿了一会,站在那里吐故纳新。也许他觉得,向我透漏了一个莫大的秘密,让自己透支了太多精力,不得不停下来喘口气。
我需要用力点点头,即便我是在听一个似乎和我关系不大的故事,而且我还要追问下去,「那么,这种写法有什么用处?」
「至少可以揭示,坐标系是我们想像的,并不真实存在。真实存在的,是那些点。它们在任何一个坐标系下所拥有的坐标,不过是它们的名字。」
「嗯……名可名,非恒名。」我发现用《道德经》里的句子,可以让任何对话持续下去。
「夫物芸芸,各复归其根。归根曰静,是谓复命。复命曰常,知常曰明,不知常,妄作,凶。一个点,就是一个点,在世界坐标系
$$ \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} $$
下,它叫
$$ \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} $$
在另一个坐标系
$$ \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & \cos{\theta} & -\sin{\theta} & 0\\ 0 & \sin{\theta} & \cos{\theta} & 0\\ 0 & 0 & 0 & 1 \end{bmatrix} $$
下,名字就变了,但这个点本身却没有变,它始终在那里,独立而不改。」
「名字变成了什么?」
「对
$$ \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} $$
进行一次变换就知道了。为了形式上简化一些,将世界坐标系称为 $A$,那个带有正弦和余弦值的坐标系称为 $B$。由 $A$ 和 $B$ 可以确定一个矩阵 $T$,
$$ A = BT \quad\rightarrow\quad T = B^{-1}A $$
$B^{-1}$ 表示 $B$ 的逆矩阵,由于 $B$ 是标准正交矩阵,所以它的逆矩阵等于它的转置矩阵,
$$ B^{-1} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos{\theta} & \sin{\theta} & 0 \\ 0 & -\sin{\theta} & \cos{\theta} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} $$
矩阵 $T$ 称为从 $B$ 到 $A$ 的过渡矩阵。」说完,POV Ray 又停顿了一会,装作看看窗外是不是在下雪。
是在下雪。我也趁机向窗外瞄了一眼,但同时在督促他,「趁着我还清醒,继续讲。」
「还记得我们要做什么吗?我们是要求解一个点,
$$ \begin{bmatrix} x' \\ y' \\ z' \\ 1 \end{bmatrix} $$
令它满足
$$ A\begin{bmatrix} x \\ y \\ z \\ 1\end{bmatrix} = B\begin{bmatrix} x' \\ y' \\ z' \\ 1\end{bmatrix} $$
由于 $A = BT$,所以,
$$ BT\begin{bmatrix} x\\ y\\ z\\ 1\end{bmatrix} = B\begin{bmatrix} x'\\ y'\\ z'\\ 1\end{bmatrix} $$
由于 $B$ 是标准正交矩阵,必定可逆,所以
$$ \begin{bmatrix} x' \\ y' \\ z' \\ 1\end{bmatrix} = T\begin{bmatrix} x \\ y \\ z \\ 1\end{bmatrix} $$
求解结束。」
「意思就是,由两个坐标系矩阵可以确定一个过渡矩阵,然后让这个过渡矩阵作用于已知名字的点?」
「嗯。坐标系矩阵的学名叫基。确定过渡矩阵的过程叫基变换。刚才所讲的,实际上是基变换和点的坐标变换的关系。有的时候,在世界坐标系里要构造一些局部坐标系,在局部坐标系下构造一些点,但是要画这些点的时候,需要把它们变化到世界坐标系下,否则画面就乱了。」
「假设我知道 $T$,这对画画有什么帮助?」好像由两个基确定过渡矩阵 $T$ 并不难,因为这些矩阵都是标准正交矩阵,是非常友好的矩阵……
「看这几句咒语,
object {
foo
matrix < 1, 0, 0,
0, 0.866, 0.5,
0, -0.5, 0.866,
0, 0, 0 >
}
这个矩阵,实际上就是
$$ T = \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & \cos{\theta} & -\sin{\theta} & 0 \\ 0 & \sin{\theta} & \cos{\theta} & 0 \\ 0 & 0 & 0 & 1\end{bmatrix} $$
的转置,$\theta = \frac{\pi}{6}$,只是最后一行
$$ \begin{matrix} 0 & 0 & 0 & 1\end{matrix} $$
被省略了。这个矩阵可以把 foo
绕 X 轴旋转了约 30 度,等价于
object {
foo
rotate 30 * x
}
」
「为什么咒语里不写成 $T$,而要用它的转置矩阵?」
「因为咒语里的点,用的不是用列向量,而是行向量。
$$ T \begin{bmatrix} x \\ y \\ z \\ 1 \\ \end{bmatrix} = \begin{bmatrix} x & y & z & 1\end{bmatrix} T^* $$
$T^*$ 表示 $T$ 的转置。」
「我讨厌行向量。让一个向量作用于一个矩阵,我觉得有些难受。」
「行向量的写法,比较节省书本的纸张。注意,如果你想让 foo
绕 X 轴转动 30 度角,然后把它向正方向移动 2 米,可以写成
object {
foo
matrix < 1, 0, 0,
0, 0.866, 0.5,
0, -0.5, 0.866,
2, 0, 0 >
}
等价于
object {
foo
rotate 30 * x
translate 2 * x
}
」说完,POV Ray 神秘地笑了笑,变成了一个行向量,然后不见了。
我依然觉得用矩阵去变换物体的方位既不直观又繁琐,也许以后会有些用处。不过,学线性代数的时候,老师应该讲图形学。
下一篇: 坐标系