点、向量与坐标系

1. 向量

1.1 向量与点

向量和点到底有什么区别?

从计算的角度来说,没有。因为计算机里对一个三维点和三维向量都存的是三个浮点数。从数学概念的角度来说,当然有。所谓向量代表的是位移。为什么教科书上说,一个向量可以随便移动?因为它代表的是位移嘛,表示的是一个相对的东西。而所谓的点呢?它代表的是坐标系里的一个绝对位置,不能随便改变的。

向量代表方向(往哪里走),点代表位置(呆在哪里)

1.2 坐标系

(只讨论笛卡尔坐标系)

多坐标空间是实时渲染里的数学基础。为什么要用多个坐标空间?因为相对位置在很多情况下要方便。

多坐标系让人迷惑的第一点就是:世界坐标系只有一个。这里世界坐标系的含义是,原点在零点的那个坐标系。或许称它为尺度更合适。也就是说,无论你要定义什么坐标系,你的原点和轴都得有数字表示吧,而你选这些数字都是相对我而言的。

明确了世界坐标系后,就可以开始讨论其它坐标系了。首先,定义一个坐标系的要素是:原点和坐标轴。坐标轴一般都是相互正交的。

这里的原点是一个,而坐标轴是向量(更具体地说,单位向量)。有了原点和坐标轴,其他任意的点和向量都可以用它们来表示出来。所以就有了书里常见的几种写法,它们都是等价的(符号游戏)。

一定一个三维坐标系,它包括一个原点和三个坐标轴:

[o = (o_x, o_y, o_z) \ vec{i} = (i_x, i_y, i_z) \ vec{j} = (j_x, j_y, j_z) \ vec{k} = (k_x, k_y, k_z) ]

坐标系里的向量表示:

[vec{v} = (v_x, v_y, v_z) \ = v_x vec{i} + v_y vec{j} + v_z vec{k} + o \ = v_xleft(egin{matrix}i_x\i_y\i_zend{matrix} ight) + v_yleft(egin{matrix}j_x\j_y\j_zend{matrix} ight) + v_zleft(egin{matrix}k_x\k_y\k_zend{matrix} ight) + left(egin{matrix}o_x\o_y\o_zend{matrix} ight) \ = v_xleft(egin{matrix}i_x,i_y,i_zend{matrix} ight) + v_yleft(egin{matrix}j_x,j_y,j_zend{matrix} ight) + v_zleft(egin{matrix}k_x,k_y,k_zend{matrix} ight) + left(egin{matrix}o_x,o_y,o_zend{matrix} ight) ]

1.3 坐标系转换

那么多坐标系之间如何转换呢?如果转换不了,或者不方便,那多坐标系有什么好的呢?所以坐标系转换当然是直观而且便于运算的。拿二维坐标系举例。如下图,定义了两个坐标系:Frame W(世界坐标系)和 Frame A。

[ extbf{Frame W} \ o = (0,0) quad vec{i} = (1, 0) quad vec{j} = (0, 1) \ extbf{Frame A} \ o_A = (2,3) quad vec{i_A} = (-1, 0) quad vec{j_A} = (0, -1) ]

Frame W 中的有个点 v = (-3,-1),求:在 Frame A 中 v = ?

首先来看这个点的等价写法:

[vec{v} = v_x vec{i} + v_y vec{j} + o \ = v_x(i_x,i_y) + v_y(j_x,j_y) + (o_x,o_y) \ Leftrightarrow (-3,-1) = -3(1,0) + -1(0,1) + (0,0) ]

现在来引入齐次坐标。齐次坐标简单来说就是多用一个维度,比如用四维向量来表示三维向量。实际的三维向量通过将四维向量的前三维都除以第四维得到。

[vec{v} = (v_x, v_y, v_z, v_w) Leftrightarrow (frac{v_x}{v_w}, frac{v_y}{v_w}, frac{v_z}{v_w}) ]

对于点,w=1;对于向量,w=0。用零点或零向量则依情况而定。齐次坐标等价写法:

[(v_x,v_y,1) = v_x (i_x,i_y,0) + v_y (j_x,j_y,0) + (o_x,o_y,1) \ Leftrightarrow (-3,-1,1) = -3(1,0,0) + -1(0,1,0) + (0,0,1) ]

接着来引入矩阵。向量是特殊的矩阵,向量是“一个维度”的,而矩阵是“两个维度的”。同样,在计算机眼里它们都是一堆数字,给它们赋予含义的是数学。引入矩阵如何使得计算变得更直观?回到点的等价表示上:

[(v_x,v_y,1) = v_x (i_x,i_y,0) + v_y (j_x,j_y,0) + (o_x,o_y,1) ]

如果把等式右边的行向量从上到下叠起来,再把系数往左移到一起,最后把圆括号换成方括号,就会变成(矩阵出现了!):

[left[egin{matrix}v_x & v_y & 1end{matrix} ight] = left[egin{matrix}v_x & v_y & 1end{matrix} ight] left[egin{matrix}i_x & i_y & 0 \ j_x & j_y & 0 \ o_x & o_y & 1end{matrix} ight] = left[egin{matrix} (vec{i},0) \ (vec{j},0) \ ({f{o}},1)end{matrix} ight] ]

在 Frame A 里,应该有着相似的形式:

[left[egin{matrix}v_x & v_y & 1end{matrix} ight] = left[egin{matrix}v_Ax & v_Ay & 1end{matrix} ight] left[egin{matrix}i_Ax & i_Ay & 0 \ j_Ax & j_Ay & 0 \ o_Ax & o_Ay & 1end{matrix} ight] = left[egin{matrix} (vec{i_A},0) \ (vec{j_A},0) \ ({f{o_A}},1)end{matrix} ight] \ Leftrightarrow left[egin{matrix}-3 & -1 & 1end{matrix} ight] = left[egin{matrix}5 & 4 & 1end{matrix} ight] left[egin{matrix}-1 & 0 & 0 \ 0 & -1 & 0 \ 2 & 3 & 1end{matrix} ight] \ Leftrightarrow left[egin{matrix}v_x & v_y & 1end{matrix} ight] = left[egin{matrix}v_Ax & v_Ay & 1end{matrix} ight] M_A ]

运用一下矩阵的运算法则:

[left[egin{matrix}v_x & v_y & 1end{matrix} ight] M^{-1}_A = left[egin{matrix}v_Ax & v_Ay & 1end{matrix} ight] M_A M^{-1}_A \ Longleftrightarrow left[egin{matrix}v_Ax & v_Ay & 1end{matrix} ight] = left[egin{matrix}v_x & v_y & 1end{matrix} ight] M^{-1}_A ]

举个例子,在 这篇博客 里,构建 M_view 的时候,我们是要把 V_world 的点转换到 V_view 里去。按照上面这个式子,有:

[left[egin{matrix}v_{x_{world}} & v_{y_{world}} & 1end{matrix} ight] = left[egin{matrix}v_{x_{view}} & v_{y_{view}} & 1end{matrix} ight] left[egin{matrix} vec{u} & 0 \ vec{v} & 0 \ f{Q} & 1end{matrix} ight] \ Leftrightarrow {v_{world}}= {v_{view}} {M_{view}}^{-1} \ Leftrightarrow left[egin{matrix}v_{x_{view}} & v_{y_{view}} & 1end{matrix} ight] = left[egin{matrix}v_{x_{world}} & v_{y_{world}} & 1end{matrix} ight] left[egin{matrix} vec{u} & vec{v} & 0\ - {f{Q}}vec{u} & - {f{Q}} vec{v} & 1end{matrix} ight] \ Leftrightarrow {v_{view}}= {v_{world}} M_{view} ]

所以为什么要求坐标轴要正交?因为正交的话,逆矩阵就等于转置矩阵,算转置可比求逆容易多了。

1.4 变换

当前语境下的变换,就是点位置的改变。大致有两条路来得到,描述点位置变化的矩阵:

  1. 点从一个坐标系转换到另一个坐标系:需要知道目标坐标系的参数(视图变换适用,如上节的例子所示)
  2. 进行多少缩放操作?平移多少?旋转多少?(所有变换都适用,在 这篇博客 里介绍了用组合操作的方法如何推导出 M_view)

对第 2 条路,最常见的变换操作是缩放和旋转,属于线性变换。因为它们只能做到:

[x' = ax + by \ y' = cx + dy \ Leftrightarrow left[egin{matrix}x' & y'end{matrix} ight] = left[egin{matrix}x & yend{matrix} ight] left[egin{matrix}a & b \ c & dend{matrix} ight] ]

而平移变换,属于仿射变换,因为它可以做到:

[x' = ax + by + e \ y' = cx + dy + f \ Leftrightarrow left[egin{matrix}x' & y' & 1end{matrix} ight] = left[egin{matrix}x & y & 1end{matrix} ight] left[egin{matrix}a & b & 0\ c & d & 0 \ e & f & 1end{matrix} ight] ]

这样引入齐次坐标的理由就显而易见了:一个矩阵就能装下最常用的三个变换。

原文地址:https://www.cnblogs.com/tandandan/p/14803904.html