OpenGL 矩阵(没写完)

OpenGL 矩阵(没写完)

lucas Lv4

向量

向量点乘(内积)

此方法可类比物理做功

nj.png

和位移 已给出,需要用 来表示做的功

计算方法就是

所以向量点乘(内积)就是向量模相乘再乘夹角余弦

换成坐标形式是:

向量叉乘(外积)

此方法可以

计算方法

坐标形式

坐标形式规律总结

至于为啥 用行列式来计算,我也没太明白

但是至少明白了,矩阵运算和这个没啥关系

矩阵

矩阵乘法

  • 数乘

  • 相乘

前面的行乘以后面的列
也就是,第一个矩阵的行数决定了最终矩阵的行数,第二个矩阵的列数决定了最终矩阵的列数
并且,第一个矩阵一行有几个元素,第二个矩阵一列就得有几个元素,这样才能进行运算

矩阵变换

矩阵变换一般指 要变换的向量或矩阵,左乘变换矩阵,生产成最终变换好的矩阵的过程

左乘和右乘

假设有个矩阵 A ,左乘 A 就是将 A 放到乘号左边,右乘就是将 A 放到乘号右边

这就是

或者说

缩放

这样除了对角线(左上到右下的对角线)其余都是零的矩阵,就叫缩放矩阵(对角线也可以有 0)

就是缩放向量

上面我们定义了一个 4 维向量在 3d 空间里的缩放,将 方向放大(缩小)为原来的

方向放大(缩小)为原来的 倍,将 方向放大(缩小)为原来的

位移

就是位移向量

位移(Translation)是在原始向量的基础上加上另一个向量从而获得一个在不同位置的新向量的过程,从而在位移向量基础上移动了原始向量。

齐次坐标(Homogeneous Coordinates)

一个向量 vec4(x,y,z,w) ,向量的w分量也叫齐次坐标。

w分量通常是 1.0。

使用齐次坐标有几点好处:它允许我们在3D向量上进行位移(如果没有w分量我们是不能位移向量的)。

如果一个向量的齐次坐标是0,这个坐标就是方向向量(Direction Vector),因为w坐标是0,这个向量就不能位移。

旋转

首先,绕哪个轴旋转,哪个轴不动

  • 绕 x 轴旋转

  • 绕 y 轴旋转

  • 绕 z 轴旋转

绕 x 轴旋转 90° 的例子

Rotation.png

万向节死锁

利用旋转矩阵我们可以把任意位置向量沿一个单位旋转轴进行旋转。

也可以将多个矩阵复合,比如先沿着x轴旋转再沿着y轴旋转。但是这会很快导致一个问题——万向节死锁(Gimbal Lock)。

万向节死锁的原因是坐标轴会跟着图形一起旋转,而并非一直呈现为标准的坐标轴样子

推荐在 B站 或者 YouTube 搜索一些关于万向节死锁的视频,会帮助你理解这个问题产生的原因

在这里我们不会讨论它的细节,但是对于3D空间中的旋转,一个更好的模型是沿着任意的一个轴,比如单位向量 旋转,而不是对一系列旋转矩阵进行复合。

这样的一个(超级麻烦的)矩阵是存在的,见下面这个公式,其中 代表任意旋转轴:

矩阵组合变换

假设一个向量,我们希望将其缩放2倍,然后位移 个单位

注意

当矩阵相乘时我们先写位移再写缩放变换的。

矩阵乘法是不遵守交换律的,这意味着它们的顺序很重要。

当矩阵相乘时,在最右边的矩阵是第一个与向量相乘的,所以你应该从右向左读这个乘法。

建议您在组合矩阵时,先进行缩放操作,然后是旋转,最后才是位移,否则它们会互相影响。

比如,如果你先位移再缩放,位移的向量也会同样被缩放(译注:比如向某方向移动2米,2米也许会被缩放成1米)!

现在我们验证一下,这个矩阵的效果

可以看到,他确实放大了两倍,并且平移了

实践

glm 库

我们需要一个库 glm

相信你非常容易地就猜出来了,这是 gl-math 的缩写

我们就是通过这个库来实现各种矩阵运算

glm.png

glm 下载地址

glm-0.9.9+

GLM库从0.9.9版本起,默认会将矩阵类型初始化为一个零矩阵(所有元素均为0),而不是单位矩阵(对角元素为1,其它元素为0)。

如果你使用的是0.9.9或0.9.9以上的版本,你需要将所有的矩阵初始化改为 glm::mat4 mat = glm::mat4(1.0f)。

如果你使用 kotlin 编写 OpenGL 代码,也可以用 glm for kotlin

我们需要的GLM的大多数功能都可以从下面这3个头文件中找到:

1
2
3
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

位移实践

我们以 向量(1,0,0) 位移(1,1,0)为例

1
2
3
4
5
6
7
glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);
std::cout << "转换前向量 (" << vec.x << "," << vec.y << "," << vec.z << ")" << std::endl;
glm::mat4 transMat4 = glm::mat4(1.0f);
glm::vec3 transVec3 = glm::vec3(1.0f, 1.0f, 0.0f);
transMat4 = glm::translate(transMat4, transVec3);
vec = transMat4 * vec;
std::cout << "转换后向量 (" << vec.x << "," << vec.y << "," << vec.z << ")" << std::endl;
1
2
转换前向量 (1,0,0)
转换后向量 (2,1,0)

transMat4 是单位矩阵,transVec3 是位移矩阵

glm::translate(transMat4, transVec3) 用来生成位移矩阵

然后向量左乘位移矩阵,实现向量的位移

缩放实践

1
2
3
4
5
6
7
glm::vec4 vec(1.0f, 1.0f, 1.0f, 1.0f);
std::cout << "转换前向量 (" << vec.x << "," << vec.y << "," << vec.z << ")" << std::endl;
glm::mat4 transMat4 = glm::mat4(1.0f);
glm::vec3 scaleVec3 = glm::vec3(0.5f, 0.8f, 2.0);
transMat4 = glm::scale(transMat4, scaleVec3);
vec = transMat4 * vec;
std::cout << "转换后向量 (" << vec.x << "," << vec.y << "," << vec.z << ")" << endl;
1
2
转换前向量 (1,1,1)
转换后向量 (0.5,0.8,2)

transMat4 是单位矩阵,transVec3 是缩放向量

glm::translate(transMat4, transVec3) 用来生成缩放矩阵

然后向量左乘位移矩阵,实现向量的缩放

旋转实践

写了两个例子,我们干脆直接开始旋转纹理

  • Title: OpenGL 矩阵(没写完)
  • Author: lucas
  • Created at : 2023-10-05 15:24:28
  • Updated at : 2024-01-08 16:30:58
  • Link: https://darkflamemasterdev.github.io/2023/10/05/OpenGL-矩阵/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments