3、二维平移变换:平移矩阵推导,使用齐次坐标实现平移

好,咱们今天聊一个非常基础但又极其重要的东西——二维平移变换。

你可能会想,平移不就是把点从(x,y)挪到(x+tx, y+ty)吗?这有什么好讲的?

嗯,没错,数学上确实就这么简单。但问题在于——当你想要把平移和旋转、缩放组合在一起时,事情就没那么单纯了。我在做嵌入式GUI框架时,就因为这个“简单”的平移,踩过不少坑。

3.1 平移的向量表达

先看最直观的形式。假设平面上有一个点P(x, y),你想把它沿x方向移动tx,沿y方向移动ty,得到新点P'(x', y'):

x' = x + tx
y' = y + ty

用向量写就是:

P' = P + T

其中T = [tx, ty]ᵀ 是平移向量。

这有什么问题呢?问题在于——这是一个加法运算。而旋转、缩放都是乘法运算(矩阵乘法)。

你想想看,如果你先旋转再平移,或者先平移再旋转,运算顺序不同,结果完全不同。但如果你想把它们写成一个统一的变换矩阵,加法就变成了障碍。

核心矛盾:旋转和缩放可以用2×2矩阵乘法表示,但平移是加法。两种运算不兼容,无法合并成一个矩阵。

3.2 齐次坐标的引入

那怎么办?

我记得第一次遇到这个问题是在做一个小型2D游戏引擎。当时我想把物体的位置、旋转、缩放用一个矩阵搞定,结果发现平移死活塞不进去。查了半天资料,才明白——需要升维。

具体做法是:给二维点增加一个维度,变成三维向量。

原来:P = [x, y]ᵀ
现在:P = [x, y, 1]ᵀ

这个多出来的“1”就是齐次坐标的w分量。对于二维点,我们通常设w=1。

为什么要加这个1?

因为这样一来,平移就可以写成矩阵乘法了:

[x']   [1  0  tx] [x]
[y'] = [0  1  ty] [y]
[1 ]   [0  0   1] [1]

展开看看:

x' = 1·x + 0·y + tx·1 = x + tx
y' = 0·x + 1·y + ty·1 = y + ty
1  = 0·x + 0·y + 1·1  = 1

结果完全一致。但形式上,它变成了矩阵乘法。

个人习惯:我一般把平移矩阵记作T(tx, ty)。写代码时,我会专门封装一个函数来生成这个矩阵,避免手算出错。

3.3 平移矩阵的几何意义

这个3×3矩阵的结构很有意思:

位置 含义
左上角2×2 旋转/缩放部分(这里是单位矩阵,表示不做旋转和缩放)
右上角2×1 平移量 [tx, ty]ᵀ
底部行 [0, 0, 1],保持齐次坐标结构

说白了,这个矩阵就是在说:“先保持原来的形状不变(左上角单位矩阵),然后整体挪个位置(右上角平移量)”。

3.4 代码实现

在实际项目中,我习惯用C语言来实现。下面是一个简单的平移矩阵生成和应用的例子:

// 定义3x3矩阵(行主序)
typedef struct {
    float m[3][3];
} Mat3;

// 生成平移矩阵
Mat3 mat3_translate(float tx, float ty) {
    Mat3 result = {{
        {1, 0, tx},
        {0, 1, ty},
        {0, 0, 1}
    }};
    return result;
}

// 应用平移矩阵到点
void apply_translate(Mat3* mat, float* x, float* y) {
    float x_new = mat->m[0][0] * (*x) + mat->m[0][1] * (*y) + mat->m[0][2];
    float y_new = mat->m[1][0] * (*x) + mat->m[1][1] * (*y) + mat->m[1][2];
    *x = x_new;
    *y = y_new;
}

我曾经踩过的坑:在嵌入式平台上,浮点运算比较慢。如果你只是做纯平移,直接用加法比用矩阵乘法快得多。我建议只有在需要组合多种变换时,才使用齐次坐标矩阵。否则,老老实实做加法就好。

3.5 逆平移矩阵

有正就有反。平移的逆操作很简单——往反方向移动同样的距离。

平移矩阵T(tx, ty)的逆矩阵是T(-tx, -ty):

T⁻¹ = [1  0  -tx]
      [0  1  -ty]
      [0  0   1 ]

验证一下:T(tx, ty) · T(-tx, -ty) = 单位矩阵。嗯,完美。

3.6 本章知识体系

下面我用一张SVG图来总结本章的核心逻辑:

二维平移变换知识体系 问题:平移是加法 解决方案:引入齐次坐标(升维) 平移矩阵 T(tx, ty) = [[1,0,tx],[0,1,ty],[0,0,1]] 点P(x,y) → 齐次坐标 [x,y,1]ᵀ → 矩阵乘法 → 新点 应用:组合变换、图形学、GUI、游戏 逆矩阵:T⁻¹ = T(-tx, -ty)

这张图把整个逻辑串起来了:从“平移是加法”这个矛盾出发,引出齐次坐标这个解决方案,然后给出具体的矩阵形式,最后落到实际应用上。

3.7 小结

二维平移本身不复杂,但它是理解齐次坐标和组合变换的敲门砖。我个人觉得,齐次坐标是计算机图形学里最优雅的设计之一——用一个额外的维度,把加法和乘法统一了起来。

你想想看,如果没有齐次坐标,每次做组合变换时,你都得手动拆成加法和乘法两部分,代码写起来又臭又长。有了齐次坐标,一切都可以用矩阵乘法搞定,简洁、统一、高效。

下一节我们会讲二维旋转,到时候你就会发现,齐次坐标的真正威力在于——平移、旋转、缩放可以无缝组合成一个矩阵。嗯,到时候你就明白了。