UGM
Ubpa Graphics Mathematics,Ubpa 图形数学库
名字取自 GLM,OpenGL Mathematics
该处“图形”概念有点大,主要面向渲染,不同于“图形学”
特点
- 着重“正确”的代数概念(环、线性、度量、赋范、内积、欧式空间、仿射空间等)
- 面向对象(所有方法都是类方法)
- 只有头文件 head-only
- 高性能:SIMD 加速,各算法最优化
- 利用单继承化优化代码结构(不使用恶心的宏)
- 提供 natvis 优化 debug 信息
- ...
0. 前言
项目地址
Ubpa: UGMgithub.com直接把 glm,Eigen 等扔掉
目录
- 简介
- 示例
- 安装
- 设计思路
- 接口
- SIMD
- Natvis
1. 简介
UGM 是着重于代数概念的数学库,区分点、向量、法向、颜色等,从而尽可能地避免了错误的计算。
常用的数学库(如 Eigen,glm)只提供 vec
类,并使其能做各种运算(如 +-*/
等),但从代数方面考虑,这并不合理。
示例
- 点与点之间不能相加减
- 颜色与点之间没有关系
- 变换矩阵(4x4)与法向的乘积不同于一般向量
- 在考虑齐次坐标时变换矩阵(4x4)与向量和点的乘积不同
- ...
我们通过提供 point
,vec
,normal
,rgb
等来区分不同的代数概念,并仅让他们支持合理的操作,这样就能在编译期就发现各种代数方面的错误,另外还能减轻心智负担(根据类型执行不同的操作)。
此外,我们还通过单继承的技术实现了极佳的代码编写,特点如下
- 复用函数实现(不同于 c++20 的
concept
或者接口,他们只是对类支持的“操作”进行了约束) - 空基类优化
- ...
2. 示例
![525d062d91f9de4a3e75800e0263b829.png](https://i-blog.csdnimg.cn/blog_migrate/0513bc91e5f3ad9ab22a0e821bdd1e22.jpeg)
3. 安装
3.1 环境
- Win10
- Git
- VS 2019
- CMake-GUI 3.16.3 及以上
- 支持 SIMD 扩展指令集 SSE 4.1
其他环境自行测试,如成功请告知
3.2 步骤
详细参考项目 README.md
3.3 使用
![61a7a6c21e8ae2065a202d464540d082.png](https://i-blog.csdnimg.cn/blog_migrate/da2711250933100c4871b92ab11ff446.png)
![1edcf04c04be114afc00e49e51c7e0ad.png](https://i-blog.csdnimg.cn/blog_migrate/19e280c063f903a9960ca8f88f86097c.png)
4. 设计思路
为了更好地使用该数学库,我们很有必要先了解下该库的设计思路。
4.1 代数概念
该库着重于“正确”的代数概念,使用者可能对这方面并不了解,但只要知道基础的线性代数知识即可,然后遇到不了解的查查 wiki 即可。
下边我简单介绍下该库涉及的主要代数概念。
- 加法
IAdd
:相同元素之间的运算,具有交换性(a+b==b+a
)和可逆性(a+(-a)=0
) - 乘法
IMul
:相同元素之间的运算,具有可逆性(a*(1/a)=1
),不一定具备交换性(a*b==b*a
)。 - 数乘
IScalarMul
:类与标量(如float
)之间的运算,具有交换性。 - 线性
ILinear
:加法 + 数乘,该空间中的元素称为向量 - 环
IRing
:加法 + 乘法 - 度量
IMetric
:也叫距离 - 赋范
INorm
:满足非负齐次三角不等式的向量 => 标量的函数,一般也叫大小 / 长度,可自然诱导出度量(distance(a,b) == (a-b).norm()
) - 内积
IInnerProduct
:线性空间中的正定非退化共轭双线性的向量 x 向量 => 标量的函数,可自然诱导出范数(sqrt(dot(x, x)) == norm
) - 仿射空间
IAffine
:具有位置概念的空间,该空间中的元素称为点,会对应一个线性空间,两空间之间的元素有关联,如point-point => vector
,point+vector => point
4.2 底层存储类型
- 数组
IArray
:有序的元素序列,这将是我们各种类的基类,一般是std::array<T, N>
,其中T
可以是float
,int
,也可以是point
,vec
- 矩阵
IMatrix
:一维数组的数组
由于底层存储类型不同,上述代数概念的具体实现有所不同(抽象 => 具体),并引申出新的代数概念
4.2.1 数组
底层存储类型为数组时,则可引申出如下代数概念
- 欧式(向量)空间
IEuclideanV
:线性空间 + 内积(dot(a,b) == a.x*b.x + a.y*b.y + a.z*b.z
) - 欧式仿射空间
IEuclideanA
:欧式(向量)空间对应的仿射空间 - 逐元素乘
IArrayHadamardProduct
:a*b=(a.x*b.x, a.y*b.y, a.z*b.z)
上述各种概念在具体为数组时会有对应的实现,如
![f1a85886d290e1399c72194b320d8f2d.png](https://i-blog.csdnimg.cn/blog_migrate/1a0095c43b53b11f7b43dc2e760c0109.png)
4.2.2 矩阵
由于该库用于离线渲染,实时渲染,游戏等,基本只要用 float4,因此也只需 3x3 和 4x4 的矩阵,因此该库也限制为只支持 3x3 和 4x4 的矩阵(并特化矩阵的乘法与逆的实现,如循环展开,simd 加速,以提高性能)。
大型矩阵的支持一般需要用线性代数库,如 Eigen 等。
底层通过一维数组的数组来实现,右乘,列优先,同于 OpenGL 与 DX(右乘+列优先的方案十分适合于 SIMD,同理左乘+行优先也如此)。
4.3 类
通过组合多个代数概念并加上具体类型支持的操作,可以轻松得到各种各样的代数类。他们满足不同的操作,极大地帮助使用者避免错误。
目前各种组合(主要部分)如下
![654fdfdb7cca5bc36b072e034e9ec665.png](https://i-blog.csdnimg.cn/blog_migrate/d7640efc7597bc82fa1af3e351558fe2.jpeg)
图中含有的类有
- 向量
vec
- 法向
normal
:本质是二重向量 bivector(wiki, stackoverflow) - 点
point
- 四元数
quat
:限制为单位四元数,用于表示旋转 - 矩阵
mat
- 变换
transform
:可表示仿射变换(平移,旋转,缩放)和射影变换(正交投影,透视投影) - 颜色
rgb
- 缩放
scale
该库还含有类
- 值
val
:加法 + 数乘 + 逐元素乘 - 欧拉角
euler
:roll -> pitch -> yaw,同于 Unity3D - 透明颜色
rgba
- 表面向量
svec
:切空间的单位向量,上方向为 z 轴 - 齐次向量
hvec
- 包围盒
bbox
:axis-aligned bounding box (AABB) - 三角形
triangle
- 直线
line
- 射线
ray
5. 接口
类由多个代数概念组合而成,所以关键在于把握代数概念的接口,各代数概念位于 include/UGM/Interfaces/。
所有接口都是类方法,方便使用,大部分情况下都可以利用 IDE 的代码提示功能(如 VS2019 的 intellisense)来查询接口。
此外还提供了图形学常见函数 / 算法,如相交(位于 line
,ray
内)、采样、材质 等。
6. SIMD
该库支持 SIMD,只要求支持 SSE 指令,使用了 xsimd 作为 SSE 指令的装饰类(wrapper),但大部分情况都直接使用 SSE 指令,并通过检阅汇编代码的指令数来优化与判断加速比。
加速的类为 float4
,包括 vecf4
,pointf4
等。
注意 float3
并没有 SIMD 加速,这是为了保持 sizeof(float3)==3*sizeof(float)
,部分数学库通过使用含 __m128
的 float3
来实现 SIMD 加速,但这样 sizeof(float3)==4*sizeof(float)
。目前可以通过显式将 float3
转成 float4
来获取加速效果。
加速部分包括
+-*/ ...
min/max/min_component/max_component/abs/sin/cos/...
transform * float4/bbox/transform
transform inverse
ray
和sphere/triangle/bbox
的相交float3
的dot/cross
(需要扩展成float4
并使用float4::dot3
和float4::cross3
)
7. Natvis
泛型编程在 debug 时会引入大量的单继承,该库使用了单继承化技术,单继承深度也很大,导致在 IDE 中查看类成员变量会很麻烦。
![821017d0f5be872298ba4f40d5309c98.png](https://i-blog.csdnimg.cn/blog_migrate/f1f51b0559adc787713de8885e08cde6.jpeg)
我们可使用 VS2019 的 natvis 功能来实现定制的视图
![b5630cbfebc63148062f7849a6231633.png](https://i-blog.csdnimg.cn/blog_migrate/b8a01ff0af6692a4154ccad105ddccbf.png)
当使用 find_package(UGM REQUIRED)
时,会自动给解决方案添加一个项目,包含 UGM_<VERSION>.natvis
,从而使得其他项目都可以支持 natvis(VS2019 支持多种方式引入 natvis,但这是目前我能想到的最合适的方式)。
![124c64e322b29f57bdf0577351e28e18.png](https://i-blog.csdnimg.cn/blog_migrate/e95b9dfd7082e42ce8d1e9056c3338fb.jpeg)
感谢大家的阅读,最后再重复贴一下项目地址
Ubpa: UGMgithub.com欢迎使用