ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

GLM 实践笔记:C++ 矩阵变换和 GLSL 逐行对齐

GLM 实践笔记:C++ 矩阵变换和 GLSL 逐行对齐

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接入项目

接入方式适用场景关键步骤
拷贝头文件小项目、无 CMakeglm/目录进 include 路径,不链接任何库
CMake find_package用系统装好的 GLMfind_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),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进