recp/cglmGitHub 仓库 🎥
OpenGL 数学 (glm) 的 C
语言版本
几乎所有的函数(内联版本)和参数都在对应的头文件中进行了文档描述。
完整文档:http://cglm.readthedocs.io
关于先前版本的说明
- 对于先前版本,_dup(复制)已被更名为_copy。例如
glm_vec_dup -> glm_vec3_copy
- 移除与 OpenGL 相关的函数,以使此库与平台和无第三方依赖
- 确保您有最新版本,并随时报告错误或问题
- [错误修复] 欧拉角(euler angles)的实现顺序错误(外部的),已修复,现在是内部的。请确保您有最新版本
- [主要变更] 从 v0.4.0 开始,四元数存储为 [x, y, z, w],在 v0.3.5 和更早的版本中是 [w, x, y, z]
- [API 重命名] 从 v0.4.5 开始,glm_simd 函数更名为 glmm_
- [新增选项] 从 v0.4.5 开始,您可以禁用对齐要求,有关文档中的选项检查。
- [主要变更] 从 v0.5.0 开始,vec3 函数使用 glm_vec3_ 命名空间,在 v0.5.0 之前是 glm_vec_
- [主要变更] 从 v0.5.1 开始,从 vec3 和 mat3 类型中移除了内置对齐
- [主要变更] 从 v0.7.3 开始,在发布/生产模式下禁用内联打印函数以消除打印成本(请参阅文档中的选项)。如果需要,您还可以禁用颜色(请参阅文档)
对于 C++ 开发者的说明
如果你还不熟悉原始的 GLM 库,你还可能想看看: https://github.com/g-truc/glm
新手的注意事项(重要)
vec4
和mat4
变量必须对齐。(稍后将提供非对齐版本)- in 和 [in, out] 参数必须初始化(请务必如此)。但是 [out] 参数不必初始化,初始化出参也是多余的
- 如果你不想使用带有 glmc_ 前缀的预编译版本,所有函数都是内联的,你可以忽略构建过程。只需包含头文件。
- 如果你的调试器带你进入了 cglm 头文件,请确保你不是在尝试复制 vec4 到 vec3 或者处理对齐问题...
- 欢迎!
经验丰富的开发者的说明
- 由于我在项目中测试了这个库,有时会出错;如果有多个开发者和他们的项目或知识找到这些错误并进行改进,将会更容易。如果你怀疑有什么问题,可以考虑进行一些测试,任何反馈、贡献和错误报告都非常欢迎。
分配?
cglm
不会在堆上进行内存分配。所以它不提供任何分配器。如果你传递了内存位置的指针,你还需要为 out 参数分配内存。别忘了,vec4(以及quat/ versor)和 mat4 必须对齐(16 字节),因为 cglm 如果可用,会使用SIMD指令来优化大多数操作。
返回向量或矩阵...
cglm 支持同时使用 数组API 和 结构体API,因此如果您使用结构体API(glms_
)的话,您可以返回结构体。
其他API如Vulkan、Metal、Dx?
目前,cglm 使用默认裁剪空间配置(-1,1)用于相机函数(透视、提取角...),未来将支持其他裁剪空间配置。
像一些其他图形库(尤其是OpenGL)一样,此库使用列主序布局以在内存中保持矩阵。
未来库可能会支持使用行主序布局的选项,目前如果您需要行主序布局,您需要将其转置。
|
|
功能
- 数组API和结构体API,你可以使用数组或结构体。
- 通用的矩阵操作(mat4,mat3)
- 链式矩阵乘法(仅限平方)
- 通用的向量操作(叉积、点积、旋转、投影、角度...)
- 仿射变换
- 矩阵分解(提取旋转、缩放因子)
- 优化的仿射变换矩阵(乘法、刚体逆变换)
- 相机(lookat)
- 投影(正交、透视)
- 四元数
- 欧拉角/偏航-俯仰-翻滚到矩阵
- 提取欧拉角
- 内联或预编译函数调用
- 视锥体(提取视锥体平面、角...)
- 包围盒(在视锥体中(裁剪)、裁剪、合并...)
- 包围球
- 投影、反投影
- 缓动函数
- 曲线
- 曲线插值助手(SMC、deCasteljau...)
- 将cglm类型转换为Apple的simd库的助手,以便在Metal GL中使用cglm类型而不在两侧打包它们
- 光线追踪助手
- 等等...
您有两个选项来调用函数/操作:内联或库调用(链接)。几乎所有函数都标记为内联(always_inline),所以编译器可能会内联。要调用预编译版本,请使用 glmc_
(c代表'call')而不是 glm_
。
#include <cglm/cglm.h> /* for inline */
#include <cglm/call.h> /* for library call (this also includes cglm.h) */
mat4 rot, trans, rt;
/* ... */
glm_mul(trans, rot, rt); /* inline */
glmc_mul(trans, rot, rt); /* call from library */
大多数数学函数都使用SSE2进行手动优化(如果可用),如果不行?别担心,所有操作都有非SSE版本。
您可以将矩阵和向量作为数组传递给函数,而不是获取地址。
mat4 m = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
glm_translate(m, (vec3){1.0f, 0.0f, 0.0f});
该库包含通用的mat4乘法和逆函数,并且包含这些函数一些特殊形式(优化)用于仿射变换矩阵。如果您想乘以两个仿射变换矩阵,可以使用glm_mul代替glm_mat4_mul,以及使用glm_inv_tr (ROT + TR)代替glm_mat4_inv。
/* multiplication */
mat4 modelMat;
glm_mul(T, R, modelMat);
/* othonormal rot + tr matrix inverse (rigid-body) */
glm_inv_tr(modelMat);
结构体API
结构体API这样工作,注意类型后有`s`后缀,函数前有`glms_`前缀,常量前有`GLMS_`前缀。
#include <cglm/struct.h>
mat4s mat = GLMS_MAT4_IDENTITY_INIT;
mat4s inv = glms_mat4_inv(mat);
结构体函数通常使用值作为参数并返回结果,而不是使用指针并将输出参数写回。这意味着您的参数通常是const
,如果您喜欢的话。
使用的类型实际上是允许以多种方式访问相同数据的联合。其中一种方式涉及匿名结构,自C11以来可用。MSVC还支持早期C版本的匿名结构,GCC/Clang在启用-fms-extensions
的情况下也支持。要显式启用这些匿名结构,请将CGLM_USE_ANONYMOUS_STRUCT
定义为1
,要禁用它们,请将其定义为0
。为了向后兼容,您还可以定义CGLM_NO_ANONYMOUS_STRUCT
(值无关紧要)以禁用它们。如果没有显式指定,cglm将根据您的编译器和使用的C版本进行最佳猜测。
构建
CMake(所有平台)
$ mkdir build
$ cd build
$ cmake .. # [Optional] -DCGLM_SHARED=ON
$ make
$ sudo make install # [Optional]
CMake选项(带默认值)
option(CGLM_SHARED "Shared build" ON)
option(CGLM_STATIC "Static build" OFF)
option(CGLM_USE_C99 "" OFF) # C11
option(CGLM_USE_TEST "Enable Tests" OFF) # for make check - make test
与您的CMake项目一起使用
- 示例
cmake_minimum_required(VERSION 3.8.2)
project(<Your Project Name>)
add_executable(${PROJECT_NAME} src/main.c)
target_link_libraries(${LIBRARY_NAME} PRIVATE
cglm)
add_subdirectory(external/cglm/)
# or you can use find_package to configure cglm
Meson(所有平台)
$ meson build # [Optional] --default-library=static
$ cd build
$ ninja
$ sudo ninja install # [Optional]
带有默认值的Meson选项
c_std=c11
buildtype=release
default_library=shared
enable_tests=false # to run tests: ninja test
与您的Meson项目一起使用
- 示例
# Clone cglm or create a cglm.wrap under <source_root>/subprojects
project('name', 'c')
cglm_dep = dependency('cglm', fallback : 'cglm', 'cglm_dep')
executable('exe', 'src/main.c', dependencies : cglm_dep)
Swift(Swift包管理器)
目前只支持默认构建选项。将 cglm 依赖项添加到您的项目中
...
Package(
...
dependencies: [
...
.package(url: "https://github.com/recp/cglm", .branch("master")),
]
...
)
现在将 cgml 添加为目标依赖项。产品选择包括
- cglm 用于库的内联版本,只能进行静态链接
- cglmc 用于库的编译版本,无链接限制
...
.target(
...
dependencies: [
...
.product(name: "cglm", package: "cglm"),
]
...
)
...
Unix(Autotools)
$ sh autogen.sh
$ ./configure
$ make
$ make check # [Optional]
$ [sudo] make install # [Optional]
这也会安装pkg-config文件,因此您可以使用 pkg-config --cflags cglm
和 pkg-config --libs cglm
来检索编译器和链接器标志。
文件将被安装到指定的前缀下(通常在Linux系统中默认为/usr/local
),但你的pkg-config可能没有配置实际上检查这里的设置。你可以通过运行pkg-config --variable pc_path pkg-config
来找出其查找位置,并通过./configure --with-pkgconfigdir=/your/path
更改文件安装的路径。或者,你可以添加前缀路径到你的PKG_CONFIG_PATH
环境变量。
Windows (MSBuild)
有关Windows的构建文件和项目文件位于win
文件夹中,确保你处于cglm/win
文件夹内。已启用代码分析,所以构建可能需要一些时间。
$ cd win
$ .\build.bat
如果msbuild
不起作用(因为多版本VS),那么尝试使用devenv
进行构建。
$ devenv cglm.sln /Build Release
在Windows上运行测试
你可以在相同的Visual Studio解决方案文件中看到测试项目。只需运行该项目即可运行测试。
构建文档
首先你需要安装Sphinx:https://sphinx-doc.cn/en/master/usage/installation.html然后
$ cd docs
$ sphinx-build source build
它将编译文档到构建文件夹中,你可以运行该文件夹中的index.html。
如何使用
如果你想要使用函数的内联版本,那么包含主头文件
#include <cglm/cglm.h>
头文件将包含所有头文件。然后调用你想要的函数,例如沿着轴线旋转矢量
glm_vec3_rotate(v1, glm_rad(45), (vec3){1.0f, 0.0f, 0.0f});
一些函数是重载的,例如你可以归一化矢量
glm_vec3_normalize(vec);
这将归一化vec并将归一化的矢量存储到vec
中,但如果你要将归一化的矢量存储到另一个矢量中,这样做
glm_vec3_normalize_to(vec, result);
像这样的函数,你可能看到_to
后缀,这些函数将结果存储到另一个变量中,并节省临时内存
要调用预编译版本,包含带c
后缀的头文件,c代表调用。预编译版本不过是包装器。
#include <cglm/call.h>
这个头文件将包含所有带c后缀的头文件。你需要用带c后缀的方式调用函数
glmc_vec3_normalize(vec);
函数用法和参数在相关头文件中进行了文档说明。在某些例子中,您可能看到相同的参数被传递了两次,如下所示
glm_mat4_mul(m1, m2, m1);
/* or */
glm_mat4_mul(m1, m1, m1);
前两个参数是 [in] 参数,最后一个参数是 [out] 参数。将 m1 和 m2 相乘后,结果存储在 m1 中。这就是为什么我们要传递两次 m1。您也可以将结果存储在不同的矩阵中,这只是一个示例。
示例:计算 MVP 矩阵
选项 1
mat4 proj, view, model, mvp;
/* init proj, view and model ... */
glm_mat4_mul(proj, view, viewProj);
glm_mat4_mul(viewProj, model, mvp);
选项 2
mat4 proj, view, model, mvp;
/* init proj, view and model ... */
glm_mat4_mulN((mat4 *[]){&proj, &view, &model}, 3, mvp);
如何发送矩阵到 OpenGL
mat4 是 vec4 的数组,vec4 是浮点数的数组。 glUniformMatrix4fv
函数接受 float*
作为 value
(最后一个参数),所以您可以将其转换为 float*
,或者可以将矩阵的第一个列作为矩阵内存的起始点。
选项 1:发送第一列
glUniformMatrix4fv(location, 1, GL_FALSE, matrix[0]);
/* array of matrices */
glUniformMatrix4fv(location, 1, GL_FALSE, matrix[0][0]);
选项 2:将矩阵转换为指针类型(也适用于多维数组)
glUniformMatrix4fv(location, 1, GL_FALSE, (float *)matrix);
您可以用相同的方式将矩阵传递给其他 API,例如 Vulkan、DX...
备注
- 此库仅使用浮点类型,尚不支持整数、双精度等。
- 如果头文件与您的编译器或 IDE 不正常工作,请提交问题,因为我使用 GCC 和 clang 进行测试,有时可能是 MSVC
待办事项
- 单元测试(进行中)
- 比较 cglm 与 glm 结果的单元测试
- 添加版本信息
- 未对齐操作(例如
glm_umat4_mul
) - 补充文档
- ARM Neon 架构(进行中)
贡献者
本项目的存在归功于所有贡献者。[贡献]
赞助者
感谢所有的赞助者!
赞助商
通过成为赞助商支持本项目。您的标志将在这里显示,并带有指向您网站的链接。[成为赞助商]
许可
MIT。请查看LICENSE文件