6 - 变换

前面我们将小矩形贴上了纹理,接下来我们将通过 变换(Transformation) 的方式,让它动起来。有关变换的理论知识有很多,前置知识就有向量、矩阵什么的,详见在GAMES101中写的文章。这里直接跳到实践部分。

实践

配置GLM

OpenGL没有自带的数学库,因此得自己搞或者上网找现成的,在这里可以找到一个专门为OpenGL量身定制的数学库 GLM

下载好文件后,只需将glm/glm文件夹复制到includes文件夹即可:

然后包括这些头文件,我们需要的大多数GLM功能就在其中:

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

可以写一段测试代码:

glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);
// 我用的是glm0.9.9版本,默认会将矩阵初始化为0矩阵,而不是单位矩阵
glm::mat4 trans = glm::mat4(1.0f);
// 如果是glm0.9.9以下的,应该是这一行
// glm::mat4 trans;
trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));
vec = trans * vec;
std::cout << vec.x << vec.y << vec.z << std::endl;

这段代码把一个向量(1, 0, 0)位移(1, 1, 0)个单位。第一行告诉我们如何声明一个向量(这里使用齐次坐标,因此是4D)。然后创建了一个单位矩阵trans用于接下来的变换操作,通过glm::translate(mat4, vec3)将单位矩阵和一个位移向量组合成该位移向量的变换矩阵,并对刚开始的向量进行相乘,最终得到结果210.

变换小矩形

接下来可以对画出来的小矩形进行变换,例如对其先缩放0.5倍,然后逆时针旋转90°。

首先创建变换矩阵:

glm::mat4 trans = glm::mat4(1.0f);
// 先缩放0.5倍,然后在原点绕z轴逆时针旋转90°(注意弧度制)
trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));
trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));

其中,glm::rotate(trans, angle, axis)函数将trans矩阵右乘一个旋转angle度(注意弧度制),绕axis旋转的旋转矩阵;glm::scale(trans, vec3)trans右乘一个按照vec3缩放的缩放矩阵。并且注意到,由于OpenGL采用的是列向量,矩阵是从右往左乘的,因此是先缩放后旋转

得到的效果如图:

接下来,尝试结合glfwGetTime()函数让该小矩形动起来:

// in rander loop
// ...
// ----------------矩阵变换---------------
glm::mat4 trans = glm::mat4(1.0f);
trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));
trans = glm::rotate(trans, (float)(glfwGetTime()), glm::vec3(0.0, 0.0, 1.0));
// --------------------------------------
        
// 设置矩阵变换的transform变量
unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));

效果如下:

十分有趣。

参考资料

  • 变换 - LearnOpenGL CN (learnopengl-cn.github.io)