GLM 实践笔记:C++ 矩阵变换和 GLSL 逐行对齐
【免费下载链接】glmOpenGL Mathematics (GLM)项目地址: https://gitcode.com/gh_mirrors/gl/glm
写过相机管线的人都烧过:proj、view、model 三个矩阵乘反一个,画面就斜,透视公式每次还得翻资料。GLM(OpenGL Mathematics)是按 GLSL 规范写的 C++ 数学库,向量、矩阵变换、四元数、投影都在里面,header-only,拷走头文件就能用,C++ 端和着色器端函数签名一致,互相对照很方便。
30秒看懂GLM
一句话:GLM 是把 GLSL 逐条对齐到 C++ 的数学库,着色器里写什么,C++ 这边基本就写什么。
- header-only:不编译、不链接,把
glm/目录放进 include 路径即可 - GLSL 兼容命名:
vec3、mat4、perspective等直接对照 GLSL 规范 - 基于 C++11,大量函数带
constexpr;CMake 选项可开 C++17/20 test/下有 core、ext、gtc、gtx 四层单测,行为拿不准就查测试- CMake target 是 INTERFACE 库,按头文件引用,无二进制依赖
三种方式把GLM接入项目
| 接入方式 | 适用场景 | 关键步骤 |
|---|---|---|
| 拷贝头文件 | 小项目、无 CMake | glm/目录进 include 路径,不链接任何库 |
| CMake find_package | 用系统装好的 GLM | find_package(glm CONFIG REQUIRED),链接glm::glm-header-only |
| git 克隆源码 | 要跑测试、锁 commit、改源码 | git clone https://gitcode.com/gh_mirrors/gl/glm,工程里add_subdirectory(glm)后链接glm::glm |
GLM CMake 配置本身很轻:仓库里的 CMake 默认会产出一个glm::glm(把所有头文件包成静态库),另有一个glm::glm-header-only,是纯 INTERFACE 库,只加 include 路径。纯 header-only 集成只需要后者。最小可跑的例子:
// 最小用法:包含全局头文件即可 #include <glm/glm.hpp> int main() { glm::vec3 v(1.0f, 2.0f, 3.0f); return (int)glm::length(v); // 函数名与 GLSL 一致 }向量、矩阵、四元数三件套讲明白
向量 = 带方向的箭头。位置、法线、视线方向都是向量,vec2/vec3/vec4与 GLSL 一一对应,支持 swizzle 取分量。
矩阵 = 一条"变换规则"。缩放、旋转、平移都是 4x4 矩阵,乘上去向量就被变换。GLM 的mat4默认列主序,内存布局和 OpenGL 的 uniform 一致。
四元数 = 一次旋转的"描述"。一次旋转用 4 个数表示,不受万向锁影响,两次旋转之间还能 slerp 平滑插值,是 C++ 四元数旋转场景里比角度更稳的表示。
// 向量:带方向的箭头 glm::vec3 p(1.0f, 2.0f, 3.0f); float len = glm::length(p); // 模长 |p| glm::vec3 n = glm::normalize(p); // 单位化 // 矩阵:"变换规则" glm::mat4 m = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 0.0f, 0.0f)); // 四元数:"旋转的描述" glm::quat q(glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)); glm::mat4 r = glm::mat4_cast(q); // 四元数 -> 4x4 旋转矩阵20行代码搭相机与变换管线
一条相机管线就是三个矩阵加一次连乘:
#include <glm/glm.hpp> // 1) GLM 透视投影:垂直视场 60°,16:9,近 0.1 远 100 glm::mat4 proj = glm::perspective(glm::radians(60.0f), 16.0f / 9.0f, 0.1f, 100.0f); // 2) 相机放 (0,0,5) 看原点,上方向 +Y glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, 5.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); // 3) 模型:先绕 Y 轴转 45°,再沿 +X 移 1 米——后发生的操作写外层 glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 0.0f, 0.0f)); model = glm::rotate(model, glm::radians(45.0f), glm::vec3(0.0f, 1.0f, 0.0f)); // 4) 管线:裁剪空间 = proj * view * model * 世界顶点 glm::vec4 clip = proj * view * model * glm::vec4(glm::vec3(0.0f), 1.0f);最常被踩的两个点:
- 变换顺序:列向量约定下"右边的矩阵先作用",
translate(...) * rotate(...)表示先转后移;想要"绕自身转完再挪动",就把 translate 写在外面。 - 列主序:
m[i][j]是第 i 列的第 j 个分量,不是第 i 行第 j 列;交给 uniform 时直接&m[0][0],内存就是 OpenGL 的列主序布局。
上生产前会遇到的坑
- 旋转角度差 90 倍 → 现象是转了个怪角度:GLM 角度一律用弧度,传角度前统一套
glm::radians()。 - 单独包含分离子头文件后符号缺失 → 投影、变换等扩展在
glm/ext/下,按手册用全局头<glm/glm.hpp>或补全子头。 vec3直接乘mat4编译不过 → 缺齐次坐标,补w = 1.0f转成vec4。- 对齐、精度宏改了半截 →
GLM_FORCE_DEFAULT_ALIGNED_GENTYPES、GLM_FORCE_PRECISION_*会改变默认类型,只在工程级统一头里定义,别逐文件加。 - SIMD 行为对不上 → 定义
GLM_FORCE_INTRINSICS但编译选项没开 SSE/NEON;用 CMake 的GLM_ENABLE_SIMD_SSE2等选项配套开启,或GLM_FORCE_PURE回退纯 C++ 定位问题。
GLM 资源地图
| 资源 | 路径 | 用途 |
|---|---|---|
| 官方手册 | manual.md | 宏说明、FAQ、代码示例全在这 |
| 核心头文件 | glm/glm.hpp | 全局头,先包含它 |
| 扩展模块 | glm/ext/ | 投影、变换、常量等细粒度头文件 |
| 四元数 | glm/gtc/quaternion.hpp | 四元数类型与矩阵互转 |
| 测试用例 | test/ | 各模块单测,是现成的 API 用法参考 |
| API 文档 | doc/api/ | Doxygen 生成的可检索在线文档 |
矩阵之外,glm/gtc/random.hpp有一组随机分布(球面、圆盘、球体内均匀点等),glm/gtc/noise.hpp提供 perlin、simplex 噪声,官方手册里附了各分布的点云示意,方便核对采样是否正确:
GLM 适合 C++ 端有大量向量矩阵代码的工程——渲染器、游戏引擎、物理仿真、机器人——尤其是同一套数学还要在着色器里再写一遍的项目。上手最快的路线:先用全局头文件把上面管线例子跑通,再按 doc/api/ 查函数,行为拿不准就翻test/里对应的测试用例。
【免费下载链接】glmOpenGL Mathematics (GLM)项目地址: https://gitcode.com/gh_mirrors/gl/glm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考