向量乘法



向量之间可以相互作乘法,但与标量乘法不一样,向量乘法有许多种不同类型。在游戏编程中,我们最常使用以下两种乘法:

  • 点乘(也被称作标量乘或内积),和

  • 叉乘(也被称作向量乘或外积)。

两个向量之间的点乘将产生一个标量,它被定义为向量各部分乘积的和:


点乘还可以被写作是两向量的大小乘积再乘以两向量夹角的余弦值:


向量投影

如果u是一个单位向量(|u| = 1),那么点乘(a · u)代表了向量a投影在由向量u的方向所定义的无限长直线上的投影长度,如图4.10所示。这个概念同等地适用于二维、三维以及更高的维度,以解决各种各样的三维问题。



作为点乘的大小

一个向量的平方大小可以由向量与自身的点乘得出。因此向量的大小可以简单地做平方根运算后得出:

这之所以可行是因为角度0的余弦值为1,因此剩下来的就是|a||a| = |a|^2。

点乘测试

点乘非常适合用来测试两个向量是否共线或垂直,以及他们是否大致上指向同一方向或相反方向。对于两个任意的向量ab,游戏程序员通常使用以下测试,如图4.11所示:

  • 共线。  (a b) = |a||b|= ab(也就是说,两个向量之间的夹角正好为0度 —— 当两个向量均为单位向量时,结果为+1)。

  • 共线但反向。 (a b) = –a(也就是说,两个向量之间的夹角为180度 —— 当两个向量均为单位向量时,结果为-1)。

  • 垂直。 (a b) = 0(也就是说,两个向量之间的夹角为90度)。

  • 同向。(a b) > 0(也就是说,他们之间的夹角小于90度)。

  • 反向。(a b) < 0(也就是说,他们之间的夹角大于90度)。

点乘的一些其他应用

点乘可运用于游戏编程中的方方面面。例如,假设我们想要知道一个敌人是处于玩家的身前还是处于玩家的身后。我们可以通过将玩家的位置P与敌人的位置E相减(v = E - P)。假设我们拥有一个向量f指向玩家面对的方向。(我们将会在4.3.10.3中看到,向量f可以直接从玩家的模型世界矩阵中取得。)点乘d = v  f可以被用来测试敌人是否在玩家身前 —— 如果结果为正数则敌人在玩家身前,负数则是在身后。

点乘还可以用于判断一个点是处于平面的上方还是下方(这在编写一个月球登陆游戏中可能会很有用)。我们可以使用两个向量来定义一个平面:平面上的任意一点Q,以及一个垂直于平面的单位向量n(法向量)。为了找出点P相对于平面的高度h,我们首先要计算出从平面上任意点(点Q就很好)指向点P的向量。因此我们有了v = P - Q。向量v与单位向量n的点乘结果就是向量v在由向量n定义的直线上的投影。这正是我们想要寻找的高度。因此,h = v=(Q)n。这如图4.12所示。

叉乘

两个向量的叉乘(也被称作外积和向量积)将产生另一个垂直于这两个向量的向量,如图4.13所示。以下仅给出三维的叉乘运算:
叉乘的大小

叉乘结果向量的大小是每个被乘向量大小的积再乘以两向量夹角的正弦值。(这与点乘大小的定义十分相似,不过要把余弦换成正弦)。

叉乘|b|的大小等于以ab为边的平行四边形的面积,如图4.14所示。因为一个三角形是一个平行四边形的一半,以位置向量V1、V2和V3围成的三角形面积可以由其任意两条边的外积的大小的一半求得:

叉乘的方向

当使用右手坐标系时,你可以使用右手定则来确定叉乘的方向。将你的手握成杯状,手指从向量a转向向量b,则拇指指向的方向即为叉乘(b)的方向。

注意当使用左手坐标系时,叉乘的方向由左手定则确定。这意味着叉乘的方向取决于所选择的坐标系统。这可能在最开始看上去有点奇怪,但请记住,坐标系统的选择并不会影响我们将要进行的数学计算 —— 它仅改变了数字在三维空间中的可视化效果。当将右手坐标系和左手坐标系相互转换时,所有点和向量的数值保持不变,只是一条轴发生了反转。因此如果叉乘正好发生在我们进行了反转的那条轴(例如z轴)上时,我们需要将那一条轴所对应的值反转。如果不这样做,那我们就需要对叉乘本身的数学定义进行修改,以使得叉乘后z轴的值会在心坐标系中取反。我不会让这些规则导致我失眠。只需要记住:当可视化叉乘时,在右手坐标系中使用右手定则,而在左手坐标系中使用左手定则。

叉乘的属性

叉乘不符合交换率(因此是顺序相关的):

× b ≠ × a

然而,它符合反交换率:
× b = -× a

叉乘符合加法分配律
× (c) = (× b) + (× c)

它和标量的乘法结合如下:

(sa) × b = a × (sb) = s(a × b)

笛卡尔基本向量与叉乘的关系如下:
(i x j) = -(j x i) = k
(j x k) = -(k x j) = i
(k x i) = -(i x k) = j

这三个叉乘定义了绕轴的正方向旋转。从x到y的正方向旋转(绕z轴),从y到z的正方向旋转(绕x轴),以及从z到x的正方向旋转(绕y轴)。正如我们将会看到的,这给了我们一个提示,那就是为什么绕y轴旋转的矩阵看上去与绕x或绕z轴旋转的矩阵相反。

实际中运用的叉乘

叉乘在游戏中有许多应用。其中一个最常见的用法是用来寻找垂直于另两个向量的向量。正如我们将在章节4.3.10.2所看到的,如果我们已经知道一个对象的本地单位向量组(本地向量ijk),那么我们就可以很容易找到表示这个对象朝向的矩阵。假设我们只知道一个对象的本地向量k —— 也就是该物体面对的方向。如果我们假设物体没有绕k方向的旋转,我们就可以通过将本地向量k(我们已知的)与世界坐标系的上方向向量(等于[0 1 0])做叉乘,以求得本地向量i。然后我们就可以通过简单地对ik做如下叉乘j = k x i以求得本地向量j

非常相似的方法可以用来求出一个三角形或其它形状的表面的法向量。给出平面上的三点P1、P2和P3,法向量n = normalize[(P2 - P1) x (P3 - P1)]。

叉乘还用于物理模拟。当一个力施加到一个对象上时,它将使对象产生旋转运动(如果力并非施加在对象的重心)。这个旋转力被称作力矩,它是如下计算的。给定力F,以及从重心到受力点的向量r,力矩N = r x F