Chapter 34 · ShapeEx 路径构建

2D 仿射矩阵基础

仿射矩阵是 ShapeEx 变换系统的核心。本章学习单位矩阵、乘法、平移、缩放、旋转。

34

概念

  • xge_shape_ex_matrix_t:6 个 float(A,B,C,D,E,F),对应 2×3 仿射矩阵。
  • 变换公式:x' = A·x + C·y + E,y' = B·x + D·y + F。
  • 单位矩阵:A=1,B=0,C=0,D=1,E=0,F=0 → 无变换。
  • 乘法组合:多个变换通过矩阵乘法组合,注意顺序(先乘先应用)。

API 速查

函数说明
xge_shape_ex_matrix_t { fA, fB, fC, fD, fE, fF }2D 仿射矩阵结构体
int xgeShapeExMatrixIdentity(xge_shape_ex_matrix_t* pMatrix)设为单位矩阵
int xgeShapeExMatrixMultiply(xge_shape_ex_matrix_t* pOut, const ...* pParent, const ...* pLocal)矩阵乘法 Out = Parent × Local
int xgeShapeExMatrixTranslate(xge_shape_ex_matrix_t* pMatrix, float fTX, float fTY)追加平移
int xgeShapeExMatrixScale(xge_shape_ex_matrix_t* pMatrix, float fSX, float fSY)追加缩放
int xgeShapeExMatrixRotate(xge_shape_ex_matrix_t* pMatrix, float fRadians)追加旋转(弧度)

编译本章示例

gcc -O2 -I. -o ch34.exe ch34_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch34.exe

示例 1:单位矩阵与平移

xge_shape_ex_matrix_t mat;
xgeShapeExMatrixIdentity(&mat);
// mat = { 1, 0, 0, 1, 0, 0 }  → 无变换

// 追加平移 (100, 50)
xgeShapeExMatrixTranslate(&mat, 100.0f, 50.0f);
// 现在 mat.E=100, mat.F=50

示例 2:缩放 + 旋转组合

xge_shape_ex_matrix_t mat;
xgeShapeExMatrixIdentity(&mat);

// 先缩放到 2 倍
xgeShapeExMatrixScale(&mat, 2.0f, 2.0f);

// 再旋转 45°
xgeShapeExMatrixRotate(&mat, 3.14159265f / 4.0f);

// 最后平移到 (300, 200)
xgeShapeExMatrixTranslate(&mat, 300.0f, 200.0f);

示例 3:矩阵乘法(Parent × Local)

// 父级变换:平移 (200, 100)
xge_shape_ex_matrix_t parent;
xgeShapeExMatrixIdentity(&parent);
xgeShapeExMatrixTranslate(&parent, 200, 100);

// 子级变换:旋转 30°
xge_shape_ex_matrix_t local;
xgeShapeExMatrixIdentity(&local);
xgeShapeExMatrixRotate(&local, 3.14159265f/6.0f);

// 合成:先应用 local,再应用 parent
xge_shape_ex_matrix_t result;
xgeShapeExMatrixMultiply(&result, &parent, &local);

完整代码

将以下代码保存为 ch34_main.c,编译后运行即可看到仿射矩阵的平移、缩放、旋转组合效果:

#include "xge.h"

static xge_shape_ex g_rect = NULL;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);

    // 原始位置(无变换)
    xge_shape_ex_matrix_t id;
    xgeShapeExMatrixIdentity(&id);
    xgeShapeExTransformSet(g_rect, &id);
    xgeShapeExFillColor(g_rect, 0x4FD8C240);
    xgeShapeExDraw(g_rect, 0.25f);

    // 平移 + 缩放
    xge_shape_ex_matrix_t m1;
    xgeShapeExMatrixIdentity(&m1);
    xgeShapeExMatrixTranslate(&m1, 350, 0);
    xgeShapeExMatrixScale(&m1, 1.5f, 1.5f);
    xgeShapeExTransformSet(g_rect, &m1);
    xgeShapeExFillColor(g_rect, 0xFFB454FF);
    xgeShapeExDraw(g_rect, 0.25f);

    // 旋转 30° + 平移
    xge_shape_ex_matrix_t m2;
    xgeShapeExMatrixIdentity(&m2);
    xgeShapeExMatrixTranslate(&m2, 100, 300);
    xgeShapeExMatrixRotate(&m2, 3.14159265f / 6.0f);
    xgeShapeExTransformSet(g_rect, &m2);
    xgeShapeExFillColor(g_rect, 0xFF6B5EFF);
    xgeShapeExDraw(g_rect, 0.25f);

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch34 - Affine Matrix";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

    // 创建一个矩形路径
    xgeShapeExCreate(&g_rect);
    xgeShapeExMoveTo(g_rect, 50, 50);
    xgeShapeExLineTo(g_rect, 200, 50);
    xgeShapeExLineTo(g_rect, 200, 150);
    xgeShapeExLineTo(g_rect, 50, 150);
    xgeShapeExClose(g_rect);

    xgeRun(onFrame, NULL);

    xgeShapeExDestroy(g_rect);
    xgeUnit();
    return 0;
}

代码讲解

  • 复用同一对象:每帧通过 xgeShapeExTransformSet 改变矩阵,同一矩形路径在不同位置/角度绘制三次。
  • 追加语义:Translate/Scale/Rotate 是右乘追加,顺序影响结果。
  • Identity 初始化:每次构建新矩阵前必须 Identity,否则字段为随机值。
  • 弧度制:Rotate 参数为弧度,30° = 3.14159265f/6。

要点与陷阱

  • 追加语义:Translate/Scale/Rotate 是在现有矩阵上"追加"(右乘),不是替换。
  • 顺序敏感:先 Scale 后 Translate ≠ 先 Translate 后 Scale。
  • Multiply 语义:Out = Parent × Local,即 Local 先应用,Parent 后应用。
  • 弧度制:Rotate 参数为弧度,90° = 3.14159265f/2。
  • 初始化:使用前必须 Identity 初始化,否则字段为随机值。

进阶练习

  1. 手动计算 Translate(10,20) × Scale(2,2) 的结果,与 API 输出对比。
  2. 实现"绕指定点旋转":Translate(cx,cy) → Rotate(θ) → Translate(-cx,-cy)。
  3. 用矩阵乘法实现一个层级变换系统(父→子→孙三级嵌套)。
2D 仿射矩阵基础效果
图:2D 仿射矩阵基础渲染效果