You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL中文本未围绕中心旋转:基于CGLM库的技术求助

嘿,我完全懂你现在的困扰——旋转文本时中心总是不对,再加上用多纹理渲染单个字母,确实容易越搞越懵。我之前用CGLM处理2D文本旋转时也踩过同样的坑,核心问题其实出在变换的顺序和矩阵乘法的逻辑上,下面一步步给你理清楚:

核心思路:绕中心旋转的三步变换

不管是单个物体还是一组字母,绕自身中心旋转的本质都是「把中心移到原点 → 旋转 → 移回原位置」,但因为矩阵运算的顺序是反向的(列主序),所以矩阵组合的顺序要特别注意。

第一步:先算出整个文本的中心坐标

因为你是逐个渲染字母,首先得遍历所有字母,计算出整个文本的边界框(Bounding Box),这样才能拿到准确的旋转中心:

#include <math.h>
#include <float.h>
#include <cglm/cglm.h>

// 假设你有一个Letter结构体存储每个字母的位置和尺寸
typedef struct {
    float x, y;      // 字母在屏幕上的原始位置
    float width;     // 字母宽度
    float height;    // 字母高度
} Letter;

vec2 calculate_text_center(Letter* letters, int num_letters) {
    float min_x = FLT_MAX, max_x = FLT_MIN;
    float min_y = FLT_MAX, max_y = FLT_MIN;

    for (int i = 0; i < num_letters; i++) {
        Letter l = letters[i];
        min_x = fmin(min_x, l.x);
        max_x = fmax(max_x, l.x + l.width);
        min_y = fmin(min_y, l.y);
        max_y = fmax(max_y, l.y + l.height);
    }

    return (vec2){(min_x + max_x) / 2.0f, (min_y + max_y) / 2.0f};
}

第二步:构建旋转所需的三个矩阵

用CGLM生成对应的变换矩阵,注意顺序不能乱:

// 假设你要绕Z轴旋转45度
float rotate_angle = 45.0f;
vec2 text_center = calculate_text_center(your_letters, your_num_letters);

mat4 translate_to_origin, rotate_mat, translate_back, global_transform;

// 1. 把文本中心平移到坐标系原点(取反中心坐标)
glm_translate_make(translate_to_origin, (vec3){-text_center.x, -text_center.y, 0.0f});
// 2. 生成旋转矩阵(记得转弧度!)
glm_rotate_make(rotate_mat, glm_rad(rotate_angle), (vec3){0.0f, 0.0f, 1.0f});
// 3. 把旋转后的文本移回原中心位置
glm_translate_make(translate_back, (vec3){text_center.x, text_center.y, 0.0f});

// 组合全局变换矩阵:顺序是 平移回 → 旋转 → 平移到原点
// 因为矩阵乘法是右到左应用变换,所以这个顺序对应先移到原点,再旋转,最后移回
mat4 temp;
glm_mul(rotate_mat, translate_to_origin, temp);
glm_mul(translate_back, temp, global_transform);

第三步:给每个字母应用变换

因为每个字母有自己的原始位置,所以要给每个字母单独构建局部平移矩阵,再和全局变换矩阵组合:

for (int i = 0; i < your_num_letters; i++) {
    Letter l = your_letters[i];
    mat4 letter_translate;
    // 构建字母的局部平移矩阵:把字母从原点移到它的原始位置
    glm_translate_make(letter_translate, (vec3){l.x, l.y, 0.0f});

    // 最终的字母模型矩阵:全局变换 × 局部平移
    // 这样字母先被移到原始位置,再跟着整个文本绕中心旋转
    mat4 letter_model;
    glm_mul(global_transform, letter_translate, letter_model);

    // 把letter_model传给着色器的model矩阵uniform,然后渲染这个字母
    // ... 你的渲染代码 ...
}

关键注意点

  • 矩阵乘法顺序:CGLM的glm_mul(a, b, result)是计算result = a × b,变换是从右到左生效的,所以一定要按「平移回 → 旋转 → 平移到原点」的顺序组合全局矩阵。
  • 正交投影适配:如果是2D文本,确保你的正交投影矩阵是正确的(比如glm_ortho的参数要匹配你的屏幕坐标系),MVP矩阵的顺序是projection × view × model(view矩阵通常是单位矩阵,因为2D不需要相机)。
  • 字母间距(Advance):如果你的字体是带字符间距的,计算边界框时要把每个字母的advance(不是width)算进去,不然文本中心会偏移。

这样调整后,你的文本应该就能准确绕自身中心旋转了!

内容的提问来源于stack exchange,提问作者Ruks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:55:33