1. 点乘:向量在另一个向量方向的“投影测量仪”
1.1 先从一道最简单的题说起
我当年学线性代数时,第一节课老师就在黑板上写了两组数:a = (1, 2),b = (3, 4),然后问我们:a · b等于多少?
那时所有人都会算:1×3 + 2×4 = 11。但你接着问一句“这个11到底是什么意思?”——全班沉默了。
这就是点乘最尴尬的地方:计算太简单,含义却极其容易被跳过。很多人矩阵、行列式都学完了,还是没想明白点乘到底在几何上干了什么。
点乘的运算规则一句话就能说清:两个向量对应分量相乘,再把所有乘积加起来。一维、二维、三维乃至n维全是这套逻辑:
- 二维:
a · b = a₁b₁ + a₂b₂ - 三维:
a · b = a₁b₁ + a₂b₂ + a₃b₃ - n维:
a · b = Σ aᵢbᵢ
但为什么这个“对应分量相乘再相加”的操作有意义?因为点乘的几何定义是一个更直观的式子:
a · b = |a| |b| cosθ
其中|a|和|b|分别是两个向量的长度,θ是两向量之间的夹角。
这两个定义,一个是代数形式,一个是几何形式,它们在物理上描述的是同一件事:一个向量在另一个向量方向上的贡献度。用大白话说,点乘衡量的是“你在我的方向上有多少分量”,或者说“我们俩方向重叠了多少”。
1.2 点乘的几何直觉:投影才是灵魂
理解点乘,核心要抓住“投影”这个概念。
你想一个场景:你拉着一辆小车往前走。绳子与地面的夹角是θ,你用的力是向量F,小车前进方向是向量d。真正让小车往前走的力不是你使出的全部力量,而是力在前进方向上的分量。这个分量是多少?就是|F|cosθ,也就是力向量F在方向d上的投影长度。
点乘F · d = |F| |d| cosθ做的正是这件事:先把F投影到d的方向上,得到一个投影长度|F|cosθ,再乘以d的长度。如果|d|刚好是单位长度1,那点乘结果就直接等于投影长度。
这个直觉能解释点乘的所有性质。为什么两个向量垂直时点乘等于0?因为夹角90度时cosθ = 0,你在我的方向上没有任何分量,我自然也在你的方向上找不到任何投影——两个方向正交,互不贡献。
为什么两个向量同向时点乘最大?因为夹角0度时,投影就是全长,贡献达到最大值|a||b|。夹角180度时,投影变成了负的,说明方向完全相反,点乘得到负值。
所以判断两个向量的方向关系,不用画图,直接看点乘的符号:
| 点乘结果 | 夹角范围 | 几何意义 |
|---|---|---|
| 大于0 | θ < 90° | 方向基本一致,投影为正 |
| 等于0 | θ = 90° | 相互垂直,投影为零 |
| 小于0 | θ > 90° | 方向基本相反,投影为负 |
1.3 点乘的分量计算与几何计算为什么是一回事
看到这里你可能会问:代数定义算出来的是一个数,几何定义算出来的是“长度乘长度乘余弦”,这俩为什么能等价?
关键在余弦定理。考虑两个向量a和b,它们的差a - b构成一个三角形的第三边。根据余弦定理:
|a - b|² = |a|² + |b|² - 2|a||b|cosθ
再把|a - b|²按分量展开:
(a₁ - b₁)² + (a₂ - b₂)² + (a₃ - b₃)² = (a₁² + a₂² + a₃²) + (b₁² + b₂² + b₃²) - 2|a||b|cosθ
左式展开后,平方项和右侧的平方项全部抵消,剩下的部分整理出来就是:
a₁b₁ + a₂b₂ + a₃b₃ = |a||b|cosθ
代数定义和几何定义完美统一。理解了这条推导,你对点乘的理解就从“背公式”升级到了“知根知底”。
1.4 点乘的经典应用场景
点乘最有价值的用途之一是判断方向。游戏开发里判断一个角色是否在另一个角色的正前方,做法就是把角色的朝向向量和指向目标的向量做点乘。结果大于0就说明目标在前方,小于0就在后方。这套逻辑在自动驾驶的障碍物检测、无人机的避障算法里同样是标配。
另一个高频用途是光照计算。Lambert漫反射模型把法线向量n和光线方向向量l做点乘,得到的就是表面明暗程度。n · l大于0说明光线照得到,数值越大越亮,等于0或小于0就是背光面。这是几乎所有实时渲染引擎里最常见的运算之一,一帧画面里可能有数百万次点乘在同时执行。
机器学习里的余弦相似度也是点乘的变体。把两个向量各自归一化后再做点乘,得到的就是夹角的余弦值,用来衡量两个文本或两个用户偏好向量的相似程度。推荐系统、人脸识别、词向量相似度计算,底层全都在用点乘。
再比如向量分解。想把一个向量a分解成平行于b和垂直于b两个分量,第一步就是计算投影长度:proj_b(a) = (a · b) / |b|² · b。这个公式在力学、信号处理、数值计算里到处都是。
2. 叉乘:构造垂直向量的利器
2.1 叉乘的定义,远没有点乘那么“听话”
点乘大家都能接受,因为结果是一个数,直观好理解。叉乘初学时容易懵,因为它的结果变成了一个向量,而且这个向量还垂直于原来的两个向量。
叉乘的代数定义是行列式形式的,拿三维向量a = (a₁, a₂, a₃)和b = (b₁, b₂, b₃)来说:
a × b = | i j k | | a₁ a₂ a₃ | | b₁ b₂ b₃ |展开这个三阶行列式:
a × b = (a₂b₃ - a₃b₂, a₃b₁ - a₁b₃, a₁b₂ - a₂b₁)
看这个式子,每个分量都像是“交叉相乘再相减”,所以叫叉乘。
叉乘的几何定义同样直白:
|a × b| = |a| |b| sinθ
也就是说,叉乘结果向量的长度等于两个向量围成的平行四边形的面积。方向则垂直于这两个向量所在的平面,且遵守右手定则。
这里有个初学者特别容易栽的坑:点乘结果可以想象成一个标量,叉乘结果确实是一个向量,它既有大小也有方向。光记|a||b|sinθ这串公式,你可能从此忽略了方向——但方向恰恰是叉乘真正的价值所在。
2.2 右手定则怎么用
叉乘的方向由右手定则确定。右手四指从第一个向量a弯向第二个向量b,大拇指所指方向就是a × b的方向。
我在教学中发现,右手定则描述起来三句话,实操起来不少人还是会搞混。一个补救技巧是:自己动手比划三次,记住“食指指a,中指指b,拇指指结果”的手势。
注意一个关键性质:叉乘不满足交换律。a × b和b × a长度相同,但方向完全相反:
a × b = -(b × a)
这是叉乘和普通乘法最本质的区别之一。如果你在某段程序里把叉乘的两个操作数写反了,法线方向就会反掉,光照效果直接是错的,而且极难排查出来。
两个向量平行时叉乘结果为零向量。因为夹角是0度或180度,sinθ = 0。这也给出一个非常实用的判断共线的方法——之前判断共线要么用比例关系,要么算向量是否成倍数,现在直接用叉乘模长是否等于0来验证,编程时尤其方便。
2.3 手算一个完整例子
光看公式容易头晕,我们实际算一次。
设a = (1, 2, 3),b = (4, 5, 6),求a × b。
按行列式展开:
- 第一个分量:
a₂b₃ - a₃b₂ = 2×6 - 3×5 = 12 - 15 = -3 - 第二个分量:
a₃b₁ - a₁b₃ = 3×4 - 1×6 = 12 - 6 = 6 - 第三个分量:
a₁b₂ - a₂b₁ = 1×5 - 2×4 = 5 - 8 = -3
所以a × b = (-3, 6, -3)。
验证一下这个结果是否垂直于a:(-3, 6, -3) · (1, 2, 3) = -3 + 12 - 9 = 0,没问题。
验证是否垂直于b:(-3, 6, -3) · (4, 5, 6) = -12 + 30 - 18 = 0,也没问题。
这个验证过程强烈建议初学的朋友手动做一遍。多算几次你就会形成直觉:叉乘结果和原两个向量的点乘一定为0——这不是巧合,而是叉乘方向被定义成“垂直于平面”的直接后果。
2.4 叉乘在三维空间里的应用
叉乘在计算机图形学里最经典的应用是求平面法向量。已知三角形三个顶点,先算出两条边向量AB和AC,然后做叉乘AB × AC,得到的就是这个三角形的法向量。有了它才能做光照计算、背面剔除、碰撞检测。
三角形面积也能顺手求出来。平行四边形面积是|AB × AC|,三角形面积正好是它的一半。这个算法在网格简化、物理碰撞模拟、地形生成里都用得上,比海伦公式快得多,还不用开好几层根号。
判断一个点是否在三角形内部,也会用到叉乘。设三角形三个顶点为A、B、C,要判断点P是否在内部,做法是分别计算PA×PB、PB×PC、PC×PA,看三个叉乘的z分量符号是否一致。都为正或都为负,点就在三角形内部;符号不一致就在外部。
物理中的力矩也是叉乘定义的:τ = r × F,力臂向量叉乘力向量得到力矩。力矩的方向垂直于r和F所在的平面,代表转动趋势的方向。电流在磁场中的安培力、运动电荷在磁场中的洛伦兹力,本质上全是叉乘在起作用。
3. 点乘与叉乘放在一起看
3.1 一张表理清两个运算的核心差异
很多初学者把点乘叉乘记混,核心原因是他们没有把两个运算当成“完全不同的工具”来理解。我整理了一张对照表,建议收藏后反复琢磨:
| 对比维度 | 点乘 a·b | 叉乘 a×b |
|---|---|---|
| 结果类型 | 标量(一个数) | 向量(有大小有方向) |
| 几何含义 | 一个向量在另一个向量方向上的投影贡献 | 两个向量围成的平行四边形面积(带方向) |
| 公式要素 | 用到 cosθ | 用到 sinθ |
| 垂直关系判断 | 点乘为0时两向量垂直 | 叉乘为零向量时两向量平行 |
| 交换律 | 满足,a·b = b·a | 不满足,a×b = -(b×a) |
| 运算维度 | 适用于任意维度 | 标准定义仅适用于三维(七维是特殊的推广) |
| 方向性 | 无方向 | 垂直于原向量所在平面,遵守右手定则 |
| 常用场景 | 夹角判断、投影、相似度、光照 | 法向量计算、面积计算、方向判断、物理力矩 |
这张表最核心的区分逻辑是:遇到“求角度、求投影、判断方向关系”的问题想点乘,遇到“求垂直向量、求面积、判断旋转方向”的问题想叉乘。
3.2 用一个工程场景统一理解
为了帮你把这两个运算焊死在脑子里,我讲一个完整的小案例:给三维空间里的一个三角面片计算光照。
假设三角形的三个顶点是A(0,0,0)、B(1,0,0)、C(0,1,0),光源从方向L = (0, 0, 1)照过来。我们需要计算这个面片的明暗程度。
第一步:求法向量。用叉乘。取两条边向量:
AB = B - A = (1, 0, 0)
AC = C - A = (0, 1, 0)
做叉乘:n = AB × AC = (0, 0, 1)
法向量就是z轴正方向。
第二步:判断光线与法线的关系。用点乘。n · L = 1 > 0,说明光线方向与法线方向一致,这个面片是朝向光源的,可以照亮。
第三步:如果是用Lambert模型计算最终亮度,就做归一化和点乘,得到光照强度系数。如果n · L的值接近1,说明光线几乎垂直打向表面,亮度最高;如果接近0,说明光线平行擦过表面,几乎是暗的。
这个简单的流程里,叉乘负责建立表面的朝向信息,点乘负责评价光线和朝向之间的关系。两种运算分工明确,互相不能替代。
4. 常见错误与排错技巧
4.1 方向判断错误:叉乘顺序反了
我见过太多人在写渲染代码时把法线求反,导致物体表面一片漆黑或者出现异常的明暗条纹。原因往往是叉乘写成了AC × AB而不是AB × AC。
换个角度看:AB × AC = (0, 0, 1),AC × AB = (0, 0, -1)。法向量完全反了。光照判断从“面向光源”变成“背向光源”,结果当然不对。
排查技巧很简单:在代码里算完法向量后,随手输出一次法向量和视线向量的点乘,看符号是否符合预期。如果是三角形网格,还要注意三角形的顶点绕序是否统一。OpenGL里默认逆时针方向是正面,好多人建模时没注意绕序,导致法向量整体翻转。
4.2 混淆“垂直”和“平行”的判断条件
这是考试和面试里最经典的送命题。有一个高频误区:初学者分不清什么时候用点乘判断垂直,什么时候用叉乘判断平行。
点乘为零判断的是垂直,叉乘为零判断的是平行。你只要记住一条逻辑链:垂直意味着夹角90度,cosθ等于0,点乘正好为0;平行意味着夹角0度或180度,sinθ等于0,叉乘模长正好为0。
我建议遇到这类问题先在草稿纸上画一个坐标轴,把两个向量的夹角画出来,再看要求的是cos(点乘)还是sin(叉乘),只要分清三角函数就不会错。
4.3 忘掉叉乘结果是向量
另一个常见错误是把叉乘结果当标量使用,或者只取了叉乘的模长,导致丢失了方向信息。
我记得以前做碰撞检测时,想判断一个物体在另一个物体的左边还是右边。有人直接用了叉乘模长,结果只能知道“不共线”,根本判断不了左右。后来改成保留叉乘结果的z分量(在二维投影场景下),z大于0就是左侧,z小于0就是右侧,问题立刻解决。
方向信息是叉乘比点乘多出来的维度,也是它威力最大的地方。做开发时如果你的叉乘结果只保留了长度,那你十有八九用错了工具。
4.4 二维空间里叉乘怎么办
很多学图形学的朋友在二维平面里做向量运算,发现叉乘需要三维坐标才能算,就开始犯难。
实际工程里有个标准做法:把二维向量补一个0当三维向量处理。设a = (a₁, a₂, 0),b = (b₁, b₂, 0),叉乘结果一定是(0, 0, a₁b₂ - a₂b₁)。
这样处理之后,叉乘的z分量就变成了二维平面上唯一的有效信息。这个z分量的正负,直接告诉你从a到b是顺时针还是逆时针旋转。刚体物理、2D游戏碰撞、多边形凹凸性判断,全都在用这个技巧。
判断多边形顶点是凸的还是凹的,就是依次取相邻边向量做叉乘,看z分量符号是否一致。符号全部一致就是凸多边形,有正有负就是凹多边形。这个算法在路径规划、碰撞网格预处理里非常实用。
4.5 关于维度的提醒
点乘在所有维度都能用,因为“对应分量相乘再相加”这一步在n维空间里完全可以执行。但叉乘的定义就要小心了:中学课本里的叉乘只定义了三维。七维空间也有叉乘,但那是数学家研究的高维代数结构,工程里基本遇不到。
如果你需要处理四维甚至更高维的向量,并且需要找一个“垂直于两个向量的向量”,那大概率不能用叉乘,得换成外代数里的楔积来处理。不过这块内容偏数学专业,普通开发者和理工科学生用到的情况极少,先有个印象就行。
5. 最后再分享一点实操心得
这套点乘和叉乘的算法,我已经在项目里反复用了很多年。老实说,公式本身五分钟就能背下来,真正的难点从来都不是计算,而是在具体问题里想清楚“该用哪个运算”。
我的习惯是拿到任何涉及向量的新需求,先问自己三个问题:
- 我要求的是一个数值还是一个方向?
- 我要判断的关系是“方向是否一致”还是“是否垂直/是否平行”?
- 我关注的几何量是投影长度还是面积?
第一个问题答“数值”就优先想点乘,答“方向”就优先想叉乘。第二个问题里“方向一致”用点乘,“垂直”还是看点乘是否为0,“平行”就要用叉乘模长。第三个问题更是决定了你工具选择的唯一标准,要投影长度就用点乘,要面积或法向量就上叉乘。
这套判断流程看起来简单,但能把很多看似复杂的问题瞬间拆解清楚。比如判断一个点在三角形内部,看起来是个几何问题,本质上是三次叉乘方向的组合判断;算两个向量的夹角,看起来是角度问题,本质上是点乘加反余弦操作。
另外建议你把向量运算的调试过程可视化。我调试图形学的代码时,经常把向量和计算结果用箭头画出来,看方向和大小是否符合直觉。一旦叉乘顺序写反了,箭头会立刻指向错误方向,比盯着几十行的数值输出高效得多。视觉反馈在向量问题上永远是最好用的排错器。
点乘和叉乘是线性代数里少有的、在工程中天天直接使用的运算。不仅是图形学,机器人运动规划、力学仿真、机器学习特征计算,全都离不开这两个基础工具。把它们的几何含义和适用场景彻底吃透,你后面学矩阵、特征值甚至更高级的数学工具时,会顺畅得多。