齐次坐标:为什么引入齐次坐标?

做图形学或者嵌入式UI开发的朋友,一定绕不开一个概念——齐次坐标。

我第一次接触它的时候,心里想的是:这不就是给坐标多加了一个1嘛,有啥了不起的?

后来真做项目了,才发现这个「多加的1」,简直是救命的操作。

为什么需要齐次坐标?

先说说痛点。

在二维平面上,我们通常用 (x, y) 表示一个点。平移、旋转、缩放,这些操作你肯定熟悉。

但问题来了:

  • 旋转和缩放,可以用 2×2 矩阵搞定
  • 平移呢?它是个加法操作,不是乘法

你想想看,如果我想把一堆点先旋转、再平移、再缩放,就得来回切换乘法和加法。代码写起来又乱又容易出错。

齐次坐标的核心目的:把平移也变成乘法。

说白了,就是让所有变换都能用矩阵乘法统一表达。

核心思想: 在二维坐标 (x, y) 后面加一个维度 w,变成 (x, y, w)。通常 w=1,表示一个点;w=0 表示一个方向向量。

齐次坐标的几何意义

这个「多加的1」到底代表什么?

我个人的理解是这样的:

普通坐标 (x, y) 是二维平面上的一个点。齐次坐标 (x, y, w) 其实是在三维空间里的一条射线。

怎么理解?

  • 所有形如 (tx, ty, tw) 的点,都对应同一个二维点 (x/w, y/w)
  • 当 w=1 时,就是最常用的表示
  • 当 w=0 时,表示无穷远处的点——也就是方向

嗯,这里要注意:w=0 不能做除法,但它代表「方向」这个几何意义非常有用。

我在做嵌入式UI的矢量图形引擎时,就经常用 w=0 来表示光照方向或者法线方向。省去了单独处理方向向量的麻烦。

矩阵表示

有了齐次坐标,所有变换都变成了 3×3 矩阵乘法(二维情况)。

来看几个常用的变换矩阵:

平移矩阵

| 1  0  tx |
| 0  1  ty |
| 0  0  1  |

把点 (x, y, 1) 乘上去,得到 (x+tx, y+ty, 1)。完美。

旋转矩阵

| cosθ  -sinθ  0 |
| sinθ   cosθ  0 |
| 0      0     1 |

缩放矩阵

| sx  0   0 |
| 0   sy  0 |
| 0   0   1 |

复合变换

假设我想先旋转再平移再缩放,只需要把三个矩阵乘在一起:

M = M_scale * M_translate * M_rotate

然后对每个点做一次乘法就行。效率高,代码也干净。

我的习惯: 在嵌入式平台上,我会提前把复合矩阵算好,存成静态变量。运行时只做一次矩阵乘法,省掉大量浮点运算。

避坑指南

我曾经踩过的坑: 在STM32上做UI动画时,忘了把齐次坐标的 w 归一化。结果平移操作出现了奇怪的缩放效果。排查了半天才发现,是 w 从1变成了其他值。

所以每次做完变换,记得检查 w 是不是还是1。如果不是,就做一次归一化:x /= w, y /= w, w = 1。

知识体系总览

下面这张图,帮你理清齐次坐标的核心逻辑:

齐次坐标知识体系 问题:平移不是乘法 核心方案:引入齐次坐标 (x, y, w) 几何意义 w=1 点,w=0 方向 矩阵表示 3×3 矩阵统一乘法 复合变换 矩阵连乘,一次计算 统一变换,高效计算

总结一下

齐次坐标不是什么高深的东西。它就是一个技巧——给坐标多加一个维度,让平移也能用矩阵乘法搞定。

  • 为什么引入? 为了统一所有变换为矩阵乘法
  • 几何意义? w=1 是点,w=0 是方向
  • 矩阵表示? 3×3 矩阵,平移、旋转、缩放都能表达

我个人觉得,理解齐次坐标的关键就一句话:用升维的方式,解决降维的痛点。

下次你写UI动画或者图形变换时,试试用齐次坐标。你会发现代码简洁很多,bug也少很多。

一句话记住: 齐次坐标 = 普通坐标 + 一个1。这个1,让平移不再是异类。