ARTICLE · 1294023
与AI一起从零开始的GAMES101之旅 02(上)|线性代数:向量、坐标与点乘
Lecture 02 · Review of Linear Algebra | 闫令琪(UCSB)| 原视频 BV1X7411F744 第 2 集
写在前面
这是《与AI一起从零开始的GAMES101之旅》的第 2 篇(上),我自学 GAMES101 的笔记。素材是闫令琪老师的公开课,我对照字幕整理。分工说清楚:AI 先出初稿——分节、补推导、标出后面哪一讲会用到;我再逐节复核,改措辞、拆长句、删掉写偏的地方。技术判断以课程为准,其余是我的;哪里讲错了,是我复核没做到位。
这一讲是复习课,内容本身不深,工科本科都学过。但它在整门课里的地位是最高的,原因只有一句:
后面二十讲不会再有新的线性代数概念,只会有这些工具的组合。
所以检验标准不是“看懂了”,是能不能不查资料写出点乘、叉乘、矩阵乘法,并且知道每个操作在几何上意味着什么。做不到这一条,后面每一讲都会有点悬。
如果你也是非科班、想靠自己把这门课啃完的人,那这份笔记大概就是写给你的。
课程版权归闫令琪老师及原课程团队所有。这里只做学习记录,不转载视频、不提供课件。
这一讲要交出的四件工具
这张表建议存下来。它是这一讲的目录,也是后面二十讲的索引。
这一讲的结构
全讲 59 分 49 秒,分十节。前三节(01–04)在本篇,05–07 在中篇,08–10 在下篇。
怎么读
十章建议全读。如果时间被切碎,按这个优先级:
- 必须吃透(缺了后面直接卡)
:08 判内外(第五讲光栅化的前提)、09 矩阵乘法与形状规则(第四讲的前提) - 高频复用(几乎每讲都用)
:04 点乘求夹角、07 叉乘求法线 - 容易忽略但会致命
:03 列向量约定——搞错这一条,你抄来的所有变换矩阵都会转反,而且极难从画面上看出来 - 可以快读
:01(依赖清单,当索引看)
每章读完的自检:如果你能不看原文说出“点乘的结果为什么是一个数”“叉乘为什么没有交换律”“矩阵的每一列代表什么”,这一讲就过了。
一个记法约定:文中用 a、b、n 这样的字母表示向量,‖a‖ 表示长度,â 表示同方向的单位向量,a · b 是点乘,a × b 是叉乘,Aᵀ 是转置,A⁻¹ 是逆。矩阵如果有多行,会用等宽块写出来,一行一行看即可。
01 · 图形学站在哪些学科上
原视频 P2 00:00–06:05(约 6 分钟)
这一节解决什么
学一门课最怕的是“不知道这块知识以后用在哪”。这一节把图形学的依赖关系摊开,让你在学后面每一章时都知道自己正在补哪块地基。
同时它给出一个重要的心理预期:图形学不是靠聪明,是靠拼装。 它要求的东西都不深,但要求你同时握着好几样。
依赖清单
课程列了五类,这里按“你会在哪一章用到”重新排一遍:
| 线性代数 | ||
| 微积分 | ||
| 概率与统计 | ||
| 物理:光学 | ||
| 物理:力学 | ||
| 信号处理 | ||
| 数值分析 | ||
| 美学 |
这张表值得存下来。当你在第 14 讲被蒙特卡洛积分卡住时,回头看第三行——你不是在学图形学,你是在补概率论。 这个认知能省掉很多自我怀疑。
三个需要展开的点
第一,光线不一定是直的。
课程提到一个前沿方向:波动光学。标准图形学假设光沿直线传播(几何光学),这足以解释反射、折射、阴影、景深。但当你要解释衍射、干涉、结构色——比如蝴蝶翅膀的蓝、肥皂泡的彩纹、CD 背面的彩虹——直线假设就失效了,必须把光当波处理,去算相位。
这个前沿和第一讲的“黑洞”例子是同一类事情:默认假设被打破的地方,就是研究前沿。 你不需要现在会算波动光学,但要知道这条路存在,将来遇到“渲染不出真实的彩虹”时不会以为是自己的 bug。
第二,信号处理是抗锯齿的理论基础。
课程说“走样、反走样技术背后都要解决信号处理的问题”。这句话在第 6 讲会变成一套具体工具:采样定理、频域、低通滤波。
先给一个直觉,帮你建立预期:屏幕上一条斜线看起来有锯齿,本质是“连续的线被离散的像素网格采样”这件事必然产生的失真。而抗锯齿不是把线画细一点,是在做采样之前先滤掉高频信息——这是一个信号处理操作,不是画图操作。所以第 6 讲会先从一维信号讲起,而不是从三角形讲起。别觉得跑题,那就是正题。
第三,渲染是一个递归定义的积分。
课程说“渲染整个过程其实就在解一个递归定义的积分”。这句话是整门课的题眼,第十三讲之后会反复出现。
用一句话解释:某个点朝某个方向发出的光,等于它自己发的光,加上它接收到的所有方向的光乘以反射比例再积分——而“接收到的光”本身又是同一件事。这就构成了递归,或者说一个无穷级数。
理解了这一点,你就明白为什么光线追踪要“弹跳”:每弹一次,就是展开一层递归。也明白为什么路径追踪要用随机采样:这个积分没有解析解,只能估。
验收
- 能归类。
“怎么让一张纹理在远处不闪烁”——这属于哪一类依赖?(答案:信号处理。) - 能说出光为什么可以被当直线。
什么情况下不行?举一个日常现象。 - 故意制造一个错误。
如果有人说“图形学只要学好线性代数就够了”,用这张表反驳他,说出至少三个线性代数解决不了的环节。
合上页面,回答这三个问题
渲染方程为什么是“递归”的? 抗锯齿为什么是信号处理问题,而不是画图问题? - (超出本节)
这张依赖表里缺了一样东西,是什么?
第 3 题的参考答案:数据结构与算法。课程没列,但图形学里到处是它:层次包围盒(BVH)是树、网格简化是图算法、空间划分是哈希与八叉树、并行光栅化要处理竞争。第 14 讲的 BVH 加速结构,本质是一个“用几何换复杂度”的算法设计问题。这也是为什么说学原理比学 API 重要——API 不教你这些。
02 · 向量:只有方向和长度的量
原视频 P2 06:05–13:15(约 7 分钟)
这一节解决什么
从这一节开始,图形学的语言就是向量。你必须先建立两个直觉:向量不关心起点,只关心“从哪指向哪”;并且它带长度。
这两个直觉决定了后面所有操作的正确性。特别是“不关心起点”这一条,如果不牢,你会在第四讲学平移矩阵时彻底卡住——因为“平移一个向量”和“平移一个点”是两件不同的事,而它们看起来一样。
向量的定义
一个从 A 指向 B 的箭头,记作 AB。它的数值等于:
AB = B − A
就这么简单:终点坐标减起点坐标,逐分量相减——二维里减两次,三维里减三次。
课程强调了一句关键的话:向量最重要的两个属性是方向和长度。
方向:从哪指向哪 长度:这个箭头有多长
没有第三个属性。 特别是——没有“位置”。
平移不变性:最容易忽略的一条
把一个向量整体搬到别的地方,它还是同一个向量。从 (0,0) 指向 (1,1) 的箭头,和从 (5,5) 指向 (6,6) 的箭头,是同一个向量,因为相对位移没变。
课程的说法是“我们并不关心它绝对开始的位置”。
这条性质在数学上叫自由向量。它有一个非常实用的推论:任何向量都可以平移到原点,从原点出发来表示它。
于是所有向量共享同一个起点,加法、减法、点乘、叉乘全都在这个统一起点上做几何解释——这就是为什么教材里的向量图总是从原点画起。
但这个性质很快就会变成一个坑。 第三讲之后你会遇到“点”:一个位置。位置是不能随便平移的——把 (1,1) 这个位置搬到 (5,5),那是另一个位置。
所以在图形学里,向量和点虽然用同样的三个数字表示,语义完全不同:
这门课在第三讲会用齐次坐标(homogeneous coordinate,第四维取 0 或 1)把这两者区分开。你现在只要先记住“它们不是一回事”,到时候就不会觉得多出来的第四维是多余设计。
记号:长度和单位向量
长度的写法是两侧加双竖线:‖a‖。有些书写成 |a|,单竖线,含义一样。
有了长度,就能定义单位向量:长度为 1 的向量。任何非零向量除以自己的长度,就得到同方向的单位向量:
â = a / ‖a‖
读作 “a hat”。
课程说了一句很实用的话:图形学里一提到“方向”,默认就是用单位向量表示,不关心它的长度。
为什么这个约定重要?因为很多计算在单位向量下会退化成一个极简形式。举两个后面会碰到的例子:
求夹角:cos θ = â · b̂——两个单位向量点乘,结果直接就是夹角的余弦,不用再除以两个长度(第四节点乘会讲) 求投影长度:‖b‖ cos θ = b · â——直接一次点乘出来(第五节讲投影)
这就是“归一化”的实际收益:把除法提前做掉,让公式短一半。
一个必须注意的边界: 如果向量长度是 0(零向量),归一化会除零。零向量没有方向,也没有单位向量。写渲染器时这类地方是最常见的 NaN 来源——法线长度为零、光线方向为零、三角形退化成一条线。以后你调用 normalize() 之前,先想一下它可能为零吗。
向量加法:两种画法,一个结果
平行四边形法则:把两个向量的起点放在一起,向两边张开,补成一个平行四边形,对角线就是从共同起点出发的和。
三角形法则:把第二个向量的起点接到第一个向量的终点上,从第一个的起点到第二个的终点,就是和。
两种画法得到同一条向量,因为向量只有方向和长度。课程提到三角形法则在图形学里用得也挺多,原因很实际:它可以连续用到任意多个向量上。三个、五个、一百个位移叠在一起,你就一个接一个地首尾相连,最后连起点和终点——这就是多边形法则。
所以:
a + b + c + d = 从第一个起点到最后一个终点
用几何法算加法适合理解,不适合写代码。代码里就是分量各自相加:两个 x 加起来、两个 y 加起来,三维再多一个 z。下一节讲笛卡尔坐标时会正式写出来。
验收
- 能判断两个箭头是不是同一个向量。
画三个箭头:A 从 (0,0) 到 (2,1),B 从 (3,3) 到 (5,4),C 从 (1,1) 到 (2,3)。哪个和 A 相同? - 能归一化。
把 (3, 4) 归一化,写出过程和结果。 - 故意制造一个错误。
一个开发者把“相机位置”和“相机朝向”都存成 Vector3,然后对位置也做了归一化。会发生什么?——相机永远在单位球面上移动,不管你输入多远,它都只在半径 1 的地方。因为归一化丢掉了长度,而位置的“长度”就是它离原点的距离。 这个 bug 你能预判,说明你抓住了“向量不关心起点、点关心位置”这个差别。
合上页面,回答这三个问题
为什么向量可以随便平移而点不行? 三角形法则相比平行四边形法则的优势是什么? - (超出本节)
如果一个向量是零向量,它有什么、没有什么?
第 3 题的参考答案:它有长度(长度为零),没有方向(因为没有箭头指向哪里),所以没有单位向量。它在加法里是单位元(加它等于不加),在任何需要归一化的地方都是炸弹。
03 · 笛卡尔坐标:为什么用这套基,以及为什么默认列向量
原视频 P2 13:15–17:10(约 4 分钟)
这一节解决什么
前面讲向量都是几何的(箭头)。计算机不能存箭头,只能存数字。这一节解决“箭头怎么变成数字”,以及一个看似无关但会一直跟着你的约定:向量竖着写还是横着写。
第二个问题不是排版习惯,它决定了第四讲所有变换矩阵的乘法顺序。选错一边,你的图会转反。
从箭头到数对
在平面上画一个直角坐标系:原点在左下,x 轴向右,y 轴向上,x 和 y 都是长度为 1 的单位向量。
现在有一个向量 a。把它平移到原点(可以这么做,因为向量不关心起点),然后沿 x 轴数格子、沿 y 轴数格子。
如果 x 方向走了 4 格、y 方向走了 3 格,那么就记作:
a = (4, 3)ᵀ
这就是笛卡尔坐标(也叫直角坐标)表示。数学上它是一个分解:
a = 4x̂ + 3ŷ
意思是“这个向量等于 4 个 x 单位向量加 3 个 y 单位向量”。这个分解形式很重要,因为它说明了:任何一个向量都可以用一组基向量的线性组合表示。 后面的坐标系、变换、甚至傅里叶变换,都是这句话的推广。
为什么一定要正交且单位
课程说了一句“如果两个轴垂直、而且都是单位向量,算长度就非常简单”。这句话背后是一条值得记住的设计理由:基的选择,决定了公式的复杂度。
在正交单位基下:
‖a‖ = √(x² + y²)
这就是勾股定理。比如 (4,3) 的长度是 5。
如果基向量不垂直(比如两个轴夹角 60°),或者长度不是 1,那么长度公式会变成一个带交叉项的东西——√(x² + y² + 2xy cos θ)——每多一维就更难看。
更关键的是投影。第四节会讲:在正交单位基下,把向量投影到某个轴上,只需要一次点乘。 如果基不正交,你要求解一个方程组。
所以整个图形学(以及大部分工程领域)默认使用正交单位基。这不是数学上必须的,是在性能和可读性上最划算的选择。
一个例外值得知道:在骨骼动画里会用到非正交的基(骨骼的局部坐标系可能有缩放或剪切),所以那时候变换矩阵会包含非正交部分,法线变换必须用“逆转置矩阵”而不是原矩阵。这个坑在第七、八讲会碰到。
列向量 vs 行向量:一个影响全局的约定
课程明确说了:在图形学上,给一个向量,默认认为它是列向量,也就是竖着一列数。
同一组数字写成横的,要加转置符号:
aᵀ = (4, 3)
为什么要统一成列? 因为矩阵乘法要求“左矩阵的列数 = 右矩阵的行数”。如果把向量当列向量,那么:
M(3×3) · v(3×1) = v'(3×1)
矩阵在左、向量在右,结果还是列向量——形状自洽,可以连乘。这就是课程说的“矩阵在左边,向量在右边,向量永远是 m×1”。
如果反过来用行向量,就得写成 vᵀM,结果的形状才自洽。数学上两种都能用,但不能混。混了会出现两个后果:
- 乘法顺序反了。
列向量约定下,“先 A 后 B”写成 BAv(后做的矩阵在左边)。行向量约定下写成 vAB。如果你照着某份资料抄公式而它用的是另一套约定,你的旋转会转反方向。 - 转置忘了加。
所有“向量点乘写成矩阵”的地方都要跟着变。
课程明确说“更多的应用,特别是图形学硬件和 OpenGL 之类的东西,默认都在用列向量”。所以这门课全程用列向量,矩阵在左。
一条实操建议: 以后看任何图形学资料(尤其是 DirectX 系的老文档),第一件事是查它用行向量还是列向量。这不是小事——两套约定下的同一个旋转矩阵,数字长得一模一样,但转的方向相反。
验收
- 能互相转换。
写出向量“沿 x 走 −2、沿 y 走 5”的列向量形式、行向量形式,以及分解成 x̂、ŷ 的表达式。 - 能算长度。
(3,4)、(1,0)、(−5,12) 的长度分别是多少? - 故意制造一个错误。
假设你在一个行向量约定的引擎里(比如某些 DirectX 教程),把课程给的旋转矩阵直接拿来乘列向量。旋转方向会怎样?——会反过来转。因为正确的行向量版本应该是它的转置。这个错误极难通过“看图不对”发现,因为图确实转了,只是转错方向。
合上页面,回答这三个问题
为什么图形学默认用正交单位基? 列向量约定下,“先平移再旋转”应该写成 v 左乘哪个矩阵? - (超出本节)
如果基向量不正交,(x,y) 这个坐标还能唯一确定一个向量吗?
第 3 题的参考答案:能唯一确定,只要两个基向量线性无关(不共线)。坐标就是“沿两个基各走多少步”的系数,与基是否垂直无关。但长度和投影的公式会变复杂——这就是为什么我们偏好正交基:不是为了能表示,是为了算得简单。
04 · 点乘:两个向量之间的一次“相关性测量”
原视频 P2 17:10–22:00(约 5 分钟)
这一节解决什么
向量有两种乘法,点乘和叉乘。它们的名字很像,作用完全不同。这一节讲点乘,它回答的问题是“这两个方向有多一致”。
这是整门课用得最多的一个运算——第七讲之后所有光照计算的核心都是点乘。所以这里必须彻底搞清定义、性质和算法。
定义
a · b = ‖a‖‖b‖ cos θ
三个数相乘:a 的长度 × b 的长度 × 它们夹角的余弦。
结果是一个数,不是一个向量。 课程特别强调了这一点,因为这是点乘和叉乘最根本的区别:
| 一个标量 | ||
| 一个向量 |
课程的原话是“左边是两个向量,点乘是一个数字,或者叫数量”。
反过来用:求夹角
把定义式两边除一除,就得到:
cos θ = (a · b) / (‖a‖‖b‖)
如果两个向量已经是单位向量,长度都是 1,分母消失:
cos θ = â · b̂
这就是上一节说的“归一化的实际收益”——公式短了一半。
性质
点乘的三个性质,和普通数字乘法几乎一样:
注意第三条:这里 k 是标量,所以“结合律”在点乘里表现为“标量可以随便进出”。点乘不涉及三个向量的连乘——a · b · c 没有定义,因为 a · b 已经是数了,数再点乘向量没有意义。
对照记一下:叉乘没有交换律,a × b = −(b × a)。这个差别后面会造成实际 bug——如果把点乘和叉乘在代码里混用,编译器不报错,结果全错。
怎么算:坐标形式
定义式里有 θ,实际写代码时你并不知道夹角。所以需要坐标形式。
在笛卡尔坐标下,把 a、b 的分量分别记作 (a₁, a₂, a₃) 和 (b₁, b₂, b₃)。二维:
a · b = a₁b₁ + a₂b₂
三维:
a · b = a₁b₁ + a₂b₂ + a₃b₃
用一句话记:对应分量相乘,再全部加起来。
这个形式比定义式好用得多,因为你手上永远有坐标、没有角度。而且它自动给出了余弦值,不需要开根号、不需要三角函数。
在图形学里用来做什么(第一次正式出现)
课程在这里点了名:光照模型。
回想一下光照的直觉:一束光正对着表面照过来,最亮;斜着照过来,同样的光铺在更大的面积上,单位面积就暗了。这个“正对程度”,恰好就是光线方向和表面法线的夹角余弦。
所以最基础的漫反射公式长这样:
L_d = k_d · max(0, n̂ · l̂)
其中 n̂ 是表面法线(单位向量),l̂ 是指向光源的方向(单位向量)。两个都是单位向量,所以点乘直接给余弦,再截断到非负(背光面没有漫反射)。
第七讲会讲这个公式,现在你只需要认识它为什么会长成这样:因为“亮度随角度变化”这件事,在数学上就是余弦,而点乘免费给你余弦。
一个实用边界:很少真的用 arccos
教材上写 θ = arccos(…),但真实渲染代码里几乎不调用 acos。两个原因:
- 没有必要。
着色公式里用的都是 cos θ 本身,不需要角度值。 - 有代价。
acos 是超越函数,比乘加慢得多;而且当 cos θ 接近 ±1 时(两个方向几乎相同),acos 的数值精度会急剧变差——输入差一点点,输出差很多。
所以实践中:
需要“亮度”“衰减”“插值权重”→ 直接用点乘结果,并且 clamp 到 [0, 1] 极少数真的需要角度(比如决定两个方向是否在某个锥角内)→ 比较 cos 而不是比较角度:dot > cos(threshold) 就够,连 acos 都省了
这条判断依据课程没讲,但它能解释你以后看别人代码时“为什么不按公式写”的疑惑。
验收
- 能手算。
a = (1,2,3),b = (4,−5,6)。求 a · b 和它们夹角的余弦。 - 能判断类型错误。
下面哪个式子合法:①a · b · c ②(a · b)c ③a · (b · c) - 故意制造一个错误。
写光照代码时忘了把法线归一化(长度不是 1)。画面会怎样?——整体变亮或变暗,而且亮度随模型缩放变化。 模型放大两倍,法线长度可能变成两倍,漫反射就翻倍。这个 bug 的症状是“同一个模型换个尺寸颜色就不对”,你能预判它,说明你记住了点乘公式里那两个长度。这也是渲染器里最常见的 bug 之一。
合上页面,回答这三个问题
点乘的结果为什么能代表“两个方向有多一致”? 为什么说“归一化能让公式短一半”?举两个例子。 - (超出本节)
如果 a · b > 0,a 和 b 的夹角在什么范围?如果等于 0 呢?
第 3 题的参考答案:> 0 说明夹角小于 90°(锐角,方向大致一致);= 0 说明夹角正好 90°(垂直、正交);< 0 是钝角(方向大致相反)。这个判据下一篇会用得很狠——它一次性解决了“左右”“前后”“内外”三个问题。
这一篇到此为止
向量、坐标、点乘,这三件东西加起来,构成了后面所有光照计算的语法。你现在应该能做到两件事:把一个方向拆成三个数字并且知道那三个数字依赖哪组基;看见一个点乘就知道它给出的是夹角余弦,不用绕到角度上去。
这一篇的技术内容都能用文字完整替代,没有非看不可的画面。
中篇从投影开始——点乘的第一个几何应用,也是“把一个向量拆成两个”这个动作的来源。拆出来的两个分量,一个决定亮度,一个决定反射方向,后面十七讲都在用。















































































