title: 坐标系统之间的转换
date: 2017-03-14
tags: [计算机图形学, 线性代数, OpenGL]
categories: [计算机图形学]
mathjax: true
---
这篇文章中,我们来聊聊 OpenGL 中的坐标系统以及它们之间的转换。
(⚠️阅读本文需要有线性代数基础。)
坐标变换原理首先,我们需要运用一点线性代数的知识,了解不同坐标系统变换的原理。
由于本文针对的是三维坐标,所以讨论的空间是 \(R^3\) 空间。
在标准三维坐标系中,我们通常用一个向量 v=[x, y, z] 来表示一个点的位置。这里的 x、y、z 分别对应 x 轴、y 轴以及 z 轴三个方向的偏移,而标准三维坐标空间的基采用的是三个互相垂直的向量 \(\mathbf e_1=[1,0,0]\), \(\mathbf e_2=[0,1,0]\), \(\mathbf e_3=[0,0,1]\)。但根据线性无关等知识,我们完全可以找出另外三个向量作为三维空间的基,只要这三个向量线性无关,同样能够张成 \(R^3\) 空间。
现在,假设坐标系 A 采用的基向量是 {\(\mathbf v_1, \mathbf v_2, \mathbf v_3\)},坐标系 B 采用的是{\(\mathbf u_1\), \(\mathbf u_2\), \(\mathbf u_3\)}。
那么,根据线性无关性,我们可以得到线性方程组:
\[
{\mathbf u_1 = \gamma_{11}\mathbf v1+\gamma_{12}\mathbf v2+\gamma_{13}\mathbf v_3}
\]
\[ \mathbf u_2 = \gamma_{21}\mathbf v1+\gamma_{22}\mathbf v2+\gamma_{23}\mathbf v_3 \]
\[ \mathbf u_3 = \gamma_{31}\mathbf v1+\gamma_{32}\mathbf v2+\gamma_{33}\mathbf v_3 \]
用矩阵方程的形式表示为:
\[\mathbf u = \mathbf M \mathbf v\]。
由于 \(\mathbf u\), \(\mathbf v\) 都是三维空间的基,因此,对于三维空间内任意一个向量 \(\mathbf w\),\(\mathbf u\)、\(\mathbf v\)都可以通过线性组合的方式表示出 \(\mathbf w\):
\(\mathbf w = \mathbf a^T \mathbf v = \mathbf b^T \mathbf u\)(这里的\(\mathbf a^T\), \(\mathbf b^T\)分别表示不同坐标空间的标量)。
结合前面 \(\mathbf u = \mathbf M \mathbf v\),进一步得到:\(\mathbf w = \mathbf b^T \mathbf u = \mathbf b^T \mathbf M \mathbf v=\mathbf a^T \mathbf v\),
继而 :\(\mathbf a = \mathbf M^T \mathbf b\),\(\mathbf b = (\mathbf M^T)^{-1} \mathbf a\)。
好了,到这里,关键的东西就讲完了。所以坐标系统的变换很简单有木有!如果你在B坐标系(基向量为{\(\mathbf u_1\), \(\mathbf u_2\), \(\mathbf u_3\)})中有个向量 \(\mathbf w\),沿用上面的假设,\(\mathbf w\) 的坐标为 \(\mathbf b\)(即 \(\mathbf w = \mathbf b^T \mathbf u\)),这个时候,我们想求出它在 A 坐标系(基向量为{\(\mathbf v_1, \mathbf v_2, \mathbf v_3\)})的坐标表示(假设为\(\mathbf a\)),我们只需要求出矩阵 \(\mathbf M\),则:\(\mathbf a = \mathbf M^T \mathbf b\)。
反之同理。
这个时候,有同学可能会问矩阵 \(\mathbf M\) 怎么求?
假设一个坐标系统的基向量为{\(\mathbf u_1\), \(\mathbf u_2\), \(\mathbf u_3\)},而另一个系统采用标准向量{\(\mathbf e_1\), \(\mathbf e_2\), \(\mathbf e_3\)},假设存在关系:\(\mathbf u = \mathbf M^T \mathbf e\)(这个式子的理解是:如果 \(\mathbf M\) 是两个坐标系统的变换矩阵,那么两个系统内的任意向量可以通过这个矩阵相互转换,基向量只不过是特殊的向量,一样可以通过 \(\mathbf M\) 进行转换),那矩阵 \(\mathbf M\) 其实可以表示为 [\(\mathbf u_1, \mathbf u_2, \mathbf u_3\)]。这个结果其实很好理解,只要换种写法:
\(\mathbf u = \begin{bmatrix} \mathbf u_1 \\ \mathbf u_2 \\ \mathbf u_3 \\ \end{bmatrix}\),\(\mathbf e = \begin{bmatrix} \mathbf e_1 \\ \mathbf e_2 \\ \mathbf e_3 \\ \end{bmatrix}\),可以发现,\(\mathbf e\)其实是一个单位矩阵。
而如果是非标准坐标系统之间的变换,则需要解一个线性方程组:\(\mathbf u = \mathbf M^T \mathbf v\),而且可以肯定,这个解存在且唯一。
尽管从上面的推论中我们可以得出,不同坐标系统可以通过一个唯一的 3*3 矩阵 \(\mathbf M\) 来变换,但都是基于坐标原点相同的前提。如果原点也发生变化,这时就必须引入第四个维度来表示平移的偏移量,也就是常说的齐次坐标。
引入第四维后,\(\mathbf u=[\mathbf u_1,\mathbf u_2,\mathbf u_3,\mathbf p]\),\(\mathbf v=[\mathbf v_1,\mathbf v_2,\mathbf v_3,\mathbf q]\),我们再次用一个矩阵 \(\mathbf M\) 来转换这两个坐标系统,不同的是,这里的 \(\mathbf M\) 是一个 4*4 的矩阵:
\[
\mathbf M= \begin{bmatrix}
\gamma_{11} & \gamma_{12} & \gamma_{13} & 0 \\
\gamma_{21} & \gamma_{22} & \gamma_{23} & 0 \\
\gamma_{31} & \gamma_{32} & \gamma_{33} & 0 \\
\gamma_{41} & \gamma_{42} & \gamma_{43} & 1 \\
\end{bmatrix}
\]
\[
\mathbf u = \mathbf M^T * \mathbf v
\]
除了多出一维外,齐次坐标与上面使用的三维坐标本质上没有区别,计算方法也基本一致,在对应到三维坐标系时,只需要舍弃第四个维度即可。
OpenGL 的坐标系统有六种:
Object (or model) coordinates
World coordinates
Eye (or camera) coordinates
Clip coordinates
Normalized device coordinates
Window (or screen) coordinates