第 3 章 多重坐标空间 (Multiple Coordinate Spaces)

      +

      核心结论

      • 多重坐标空间是工程必需:某些位置 / 方向只在特定参考系中已知;"绝对"坐标其实是"在我们关心的最大空间中"的坐标,并不存在真正的全局绝对。

      • 常见坐标空间:world / object (model / body) / camera / upright (inertial) 四种是图形学固定词汇;"upright space"是本书引入的中间层,原点同 object space 但轴向同 world space。

      • 变换的两种视角:移动坐标空间(换参考系看同一个点)vs 移动点(保持空间看点的位移)——数学等价,思维方向相反;理解两者才能在代码与公式间无缝切换。

      • 基向量(basis vectors):一组线性无关向量,其线性组合 span 整个空间;任何向量 \(\mathbf{v} = x\mathbf{p} + y\mathbf{q} + z\mathbf{r}\) 可唯一表示;基向量必须 线性无关,否则不是合法基。

      • 嵌套坐标空间:层级结构下,object 到 world 的变换可拆为"object → upright(旋转)"和"upright → world(平移)"两步;这是骨骼动画 / 场景图的数学基础。

      • 命名即征服(name and conquer):给中间状态(upright space)命名,可让代码自解释、避免每处都写完整的旋转 + 平移;3D 引擎的 scene graph 节点就是该思想的具体化。

      本章主旨

      本章把第 1 章的"单坐标系"扩展为"多坐标系并存"。核心论点:在不同情境下使用不同坐标空间更自然;空间之间通过 坐标空间变换 互通;变换的两种视角(动空间 vs 动点)数学等价,代码侧固定采用"动点"视角;引入 upright space 作为旋转 / 平移分解的中间层。所有 3D 引擎的 scene graph、相机栈、模型 → 世界 → 投影链都遵循本章框架。

      一、核心概念

      本章围绕 6 个核心概念展开:从"为什么需要多坐标系"出发,列出常见类型,澄清变换的两种视角,引入基向量作为坐标系的代数描述,最后给出嵌套结构与代码可读性两个实践要点。

      概念 定义 + 重要性 实现提示

      多坐标空间的必要性

      不同坐标系有不同的"局部信息优势"——"向东 100 米"在国家地图上有效,在你的房间内却没用。"绝对"实质上指"在最大参考系中"。

      §3.1 论证;§3.5 进一步说明"诚实表达"重要性。把所有点都强行转 world 坐标会损失局部语义。

      常用坐标空间

      world / object(model / body)/ camera / upright(inertial)四类是图形学固定词汇。upright 是本书引入的中间层,原点同 object 但轴向同 world。

      §3.2 给出定义。代码里用类型或命名空间区分(如 world::Vec3 vs body::Vec3),编译期防止混用。

      变换的双重视角

      视角 A:"换参考系"看同一个点(空间在动,点未动);视角 B:"动点"换位置(空间静止,点在动)。两者数学等价,思维方向相反。

      §3.3.1 详细论证;§3.3.2 给出"用另一空间的基向量表达当前空间"的精确语义。代码侧固定采用视角 B。

      基向量

      一组线性无关向量,其线性组合 span 出整个空间;任何向量可唯一表示为基向量的线性组合 v = x p + y q + z r。线性相关时坐标不唯一。

      §3.3.3 给出核心公式(式 3-2);§3.3.4 解释 span / rank / 线性相关。第 4 章矩阵的列就是基向量。

      嵌套坐标空间

      层级结构(骨骼 → 角色 → 世界);object → upright 用旋转,upright → world 用平移,组合即可表达刚体变换。

      §3.4;动画系统中骨骼链就是嵌套空间的具体实例。scene graph 节点保存"父空间变换矩阵 + 子物体列表"。

      命名即征服与 upright 哲学

      Don Knuth 的"name and conquer"——给频繁使用的中间概念命名以减少噪声;upright space 就是这种命名哲学的产物。

      §3.2.4 与 §3.5 阐述;实践上把每个变换中间结果存为命名变量,代码可读性显著提升。

      二、详细笔记

      2.1 多坐标空间的必要性 (Why Multiple Spaces)

      What:3D 图形中,不同情境下使用不同的坐标系更自然;不存在真正的"绝对位置","绝对"= "在我们关心的最大空间中"。

      Why:把所有点都强制转 world 坐标会损失局部语义(如"角色前方"),并且当某些信息只在局部可知时,强行转换是不可能的。

      How

      • 多空间的好处:每个空间保留最自然的描述;信息只在局部空间可知时无需"求全";多人协作时各管各的局部空间,最后统一到 world。

      • Cartesia vs Dyslexia 例子(§3.1):两座城市各有自己的地图;州交通工程师要做跨城公路,必须引入第三张图——这就是第三坐标系出现的合理动机。

      • "绝对"的真实含义:并非字面意义上的"全球唯一",而是"在我们关心的最大参考系(通常是 world)中的坐标"。

      历史先例
      • 亚里士多德(公元前 384–322)地心说,地球在原点。

      • 阿里斯塔克斯(公元前 310–230)日心说,太阳在原点。

      • 哥白尼(1473–1543)才把日心说确立。 多坐标系选择并非新问题——3D 图形只是把"日心 vs 地心"的争论具象化为可计算的对象。

      When:大型场景(角色 + 道具 + 地形)必须分层;UI 元素单独在自己空间(屏幕坐标);骨骼动画必然嵌套。

      Example:一个角色跑过场景——世界坐标描述"在地图哪里",角色坐标描述"在角色前方还是后方",相机坐标描述"在相机视野哪里";同一时刻用三个空间并存描述最自然。

      2.2 常用坐标空间 (Common Coordinate Spaces)

      What:4 类基础坐标空间——world、object(model / body)、camera、upright(inertial)——是图形学固定词汇。

      Why:跨引擎 / 跨论文交流时,固定词汇避免歧义;每种空间有默认轴向与原点约定。

      How

      四种空间的核心特征:

      • world space:全局参考系;原点是"我们关心的最大范围"的中心;其他空间都可用 world 表达,但 world 自己不被更大的空间表达(除非引入银河系、太阳系等更大的概念)。

      • object space(model / body):每个物体自带;物体移动 / 旋转时,其 object space 跟着移动 / 旋转。模型顶点存的就是 object space 坐标。

      • camera space:一种特殊的 object space,原点在相机、+x 右、+y 上、+z 前(左手系传统);OpenGL 习惯右手系(+z 朝向你)。

      • upright space:本书命名——原点同 object space,轴向同 world space。用来把"旋转"和"平移"在概念上分离。

      upright space 的命名之争

      本书第一版用 "inertial space",但与物理学的"惯性参考系"含义不同,故改名 upright。物理中类似概念叫"质心坐标"。这是一个"好的概念等待好名字"的例子(§3.2.4、§3.5)。

      When:建模代码(object)、场景图(world)、视图 / 投影(camera)、中间缓存(upright)各司其职。

      Example:机器人模型顶点存的是 object space;动画师想"让机器人向东走 10 米",是 upright → world 的平移;最终渲染时再 object → world → camera → screen。

      2.3 变换的双重视角 (Dual Perspectives)

      What:坐标空间变换有两种等价思维——"换参考系"(空间在动,点未动)vs "动点"(空间静止,点在动)。

      Why:理解两种视角才能在代码与公式间切换;数学推导常用视角 A(基向量替换),代码实现固定视角 B(点矩阵乘)。

      How

      • 视角 A(换参考系):点未动,描述它的参考系换了。例:"机器人向东走 10 米"等价于"在世界空间里,机器人从 (0,0,0) 移到 `(10,0,0)`"——描述不变,空间变换。

      • 视角 B(动点):空间静止,点在新空间中的坐标变了。例:把机器人的脚从 (0,0,0) 转到 (10,0,0)——空间未动,点在新坐标中位移。

      数学上的统一:把"基向量"作为"空间的别名"——视角 A 中替换基向量就是视角 B 中改写点坐标。两者在数学上完全等价。

      When

      • 公式推导(点积 / 叉积 / 矩阵变换)通常在视角 A 下表达"用哪组基向量"。

      • 代码实现(C++ / GPU shader)固定视角 B:给定变换矩阵 M,点变换 p' = M p

      • 数学直觉遇到困惑时,回到"动点"视角就能落地。

      Example:机器人从 origin 出发,先 旋转 120° 再 平移 [18, 0, 10]。视角 A 说:"原点 + 基向量同步变换";视角 B 说:"点坐标先旋转再平移"。两者结果一致。

      2.4 基向量与坐标空间描述 (Basis Vectors)

      What:一组线性无关向量 p, q, r 称为该空间的基向量;任何向量 \(\mathbf{v}\) 可唯一表示为基向量的线性组合 \(\mathbf{v} = x\mathbf{p} + y\mathbf{q} + z\mathbf{r}\)。

      Why:基向量是"用另一空间描述本空间"的代数工具;第 4 章矩阵的列就是基向量的具体化。

      How

      式 3-2(线性组合):

      \[\mathbf{v} = x\mathbf{p} + y\mathbf{q} + z\mathbf{r}\]

      基向量的关键性质:

      • 线性无关:没有向量能写成其他向量的线性组合;否则坐标不唯一。

      • span:基向量的所有线性组合构成的空间;n 个基向量最多 span n 维("full rank");少于 n 即 线性相关

      • 坐标依赖于基:\(\mathbf{p}, \mathbf{q}, \mathbf{r}\) 在 自己空间 中永远是 [1,0,0], [0,1,0], [0,0,1],但在 另一空间 中是任意值。

      基向量的常见误区

      "基向量一定是 `[1,0,0], [0,1,0], [0,0,1]`"——错。这只在"用基向量所在空间描述自身"时成立。换到另一空间,基向量可以是任意坐标。这是基向量和坐标"看起来一样"的迷惑性根源。

      When:纹理映射的切线 / 副切线 / 法线(tangent / binormal / normal)就是 不一定正交的 基向量特例;§10.9 bump mapping 详细展开。

      Example:物体空间的基向量在物体空间中是 [1,0,0] / [0,1,0] / [0,0,1];在 world 空间中可能是 [0.866, 0, 0.5] / [0, 1, 0] / [-0.5, 0, 0.866](绕 y 旋转 30° 后)。

      2.5 嵌套坐标空间 (Nested Coordinate Spaces)

      What:层级结构(物体 → 父物体 → …​ → 世界)下,每层的变换矩阵把子空间映射到父空间;嵌套展开就是累积变换链。

      Why:骨骼动画、关节链、场景图都基于此;理解嵌套才能正确处理"物体跟着父物体移动"的现象。

      How

      把 object → world 分解为两步(式 3-1 的一般化):

      • object → upright:旋转(轴向对齐)。

      • upright → world:平移(原点对齐)。

      一般化的"object → parent → grandparent → world"链:每层变换是一个矩阵;总变换 = 连乘。

      分解的好处

      把"旋转 + 平移"分解为两步的好处:旋转在原点的局部空间内做,几何上等价于"先转基向量再放点",参数(旋转轴 / 角度)更直观;平移用向量加法即可,参数更直观。两者合一("旋转 + 平移混合矩阵")虽然紧凑但容易出错。

      When:骨骼动画(每根骨头有自己的 object space,相邻骨头靠 joint 连接);UI 树(屏幕空间嵌套);粒子系统(粒子在父物体空间定义,跟随父物体运动)。

      Example:机器人举手臂——上臂的 object space 在肩膀位置;前臂的 object space 在肘部位置(相对于上臂);手掌的 object space 在腕部位置(相对于前臂)。整条链最终展开到 world。

      2.6 命名即征服与 upright 哲学 (Name and Conquer)

      What:Don Knuth 的"name and conquer"——给频繁使用的中间概念命名以减少代码噪声;本书的 upright space 就是这种命名的具体化。

      Why:每处都写完整旋转 + 平移会让代码 / 文档臃肿;命名中间状态既可读又可测。

      How

      • 命名中间结果:把"旋转量"命名为 orientation、"位置"命名为 position、"半步结果"命名为 upright_pos,比"旋转矩阵 R"和"平移向量 T"分写再相乘更易理解。

      • upright space 的命名理由:它是"既知道物体原点在哪、又知道世界轴向"的中间空间——很多中间计算自然落在它上面。

      • 代码可读性:把 M = T * R; p_world = M * p_obj; 改成 M = compose(rotation, translation); auto p_upright = rotate(p_obj, rotation); auto p_world = translate(p_upright, position); 显著更易调试。

      When:所有"多步组合"的场景——动画合成、相机栈、复合碰撞检测。

      Example:骨骼动画导出格式(FBX / glTF)通常存的是"局部旋转 + 父索引",运行时引擎自动展开嵌套——这正是 upright 哲学的工程实例。

      三、关键图表

      视觉图表

      图 3-1
      Figure 1. 图 3-1:相机空间(左手系约定)
      图 3-2
      Figure 2. 图 3-2:object / upright / world 三空间示意
      图 3-3
      Figure 3. 图 3-3:world ↔ upright(平移)+ upright ↔ object(旋转)
      图 3-4
      Figure 4. 图 3-4:广告例——机器人与鲱鱼三明治
      图 3-5
      Figure 5. 图 3-5:原始模型(原点位于脚下)
      图 3-6
      Figure 6. 图 3-6:把模型摆到目标位置
      图 3-7
      Figure 7. 图 3-7:先旋转再平移——把机器人从 object 放到 world
      图 3-8
      Figure 8. 图 3-8:upright space 充当"原点同物体 / 轴向同世界"的中间层
      图 3-9
      Figure 9. 图 3-9:把点从物体空间变换到世界空间
      图 3-10
      Figure 10. 图 3-10:四步变换链(机器人示例)
      图 3-11
      Figure 11. 图 3-11:基向量不一定正交
      图 3-12
      Figure 12. 图 3-12:两个基向量 span 出 3D 中的一个 2D 子空间
      图 3-13
      Figure 13. 图 3-13:基向量变换(世界 ↔ 物体)

      非可视化条目

      非可视化条目(表 / 算法)
      编号 内容摘要

      表 3.1

      作者所在城市经纬度:Chicago (41°57′N, 87°39′W)、Denton (33°11′N, 97°W)。用于说明"world 坐标"在物理世界中是经纬度(球坐标),与图形学的笛卡尔不同。

      式 3-1

      object → world 的"旋转 + 平移"分解:w = o + bx p + by q + bz r,其中 o 是物体原点在 world 中的位置,p, q, r 是物体基向量在 world 中的坐标。

      式 3-2

      任意向量作为基向量线性组合:v = x p + y q + z r。3D 中 3 个基向量 span 出 3D 空间。

      核心公式对照表

      核心公式对照表
      式号 公式

      式 3-1(object → world)

      \(\mathbf{w} = \mathbf{o} + b_x \mathbf{p} + b_y \mathbf{q} + b_z \mathbf{r}\)

      式 3-2(线性组合)

      \(\mathbf{v} = x\mathbf{p} + y\mathbf{q} + z\mathbf{r}\)

      object → upright

      \(\mathbf{u} = b_x \mathbf{p} + b_y \mathbf{q} + b_z \mathbf{r}\)(仅旋转,无平移)

      upright → world

      \(\mathbf{w} = \mathbf{o} + \mathbf{u}\)(仅平移)

      四、思维导图

      mindmap
        root((第 3 章 多重坐标空间))
          多空间必要性
            局部信息优势
            绝对是相对最大空间
            历史先例
          常见空间
            world全局
            object物体
            camera相机
            upright中间层
          变换双重视角
            换参考系
            动点
            数学等价
          基向量
            线性无关
            span
            坐标依赖基
          嵌套空间
            旋转加平移
            骨骼链
            累积变换
          命名即征服
            upright哲学
            代码可读
            中间结果命名

      五、重点与易错点

      1. 不存在"绝对"位置:"绝对"实质是"在最大参考系中";超出关心的范围(地球 vs 太阳系 vs 银河系)就换基向量。

      2. upright space 是本书命名:与物理的"惯性参考系"含义不同;本质是"原点同物体、轴向同世界"的中间层,便于把旋转与平移概念分离。

      3. 变换的双重视角数学等价:视角 A 替换基向量 = 视角 B 改写点坐标;公式推导用视角 A,代码实现固定视角 B。

      4. 基向量不一定是 [1,0,0]/[0,1,0]/[0,0,1]:在自己空间成立,在其他空间是任意值;这是初学者最易混淆之处。

      5. 基向量必须线性无关:相关时坐标不唯一(如 r = a 就线性相关);n 个相关基向量 span 不到 n 维。

      6. upright 在原点的局部空间:分解为"先旋转对齐基向量"与"再平移对齐原点"两步;混在一起用 4×4 矩阵虽紧凑但难调试。

      7. 嵌套空间 = 变换链:父子空间间靠变换矩阵链接;总变换 = 各级矩阵连乘;骨骼动画的"局部旋转 + 父索引"格式就是嵌套思想的具体化。

      8. camera space 的两种约定:DirectX / Unity 左手(+z 前 / 远离你),OpenGL 右手(+z 朝向你 / 远离屏幕);跨引擎时第一件事是确认朝向。

      9. 代码可读性 = 命名中间结果:避免"4×4 矩阵连乘一行"——拆成 orientation * translation + 中间变量,调试时单步检查每一级。

      10. 跨章衔接:第 4 章把基向量代数化为矩阵的列;第 5 章把"先旋转再平移"封装为矩阵乘法;第 8 章讨论多种旋转表示(欧拉角 / 轴角 / 四元数);第 10 章展开 camera space 到 screen space 的投影链。