【OpenGL】笔记六、GLM配置

1. 流程

GLM是OpenGL Mathematics的缩写,它是一个只有头文件的库,有了它,我们完成各种矩阵和向量操作就变得方便了许多,下载完 文件 后将它加入include目录即可

现在看看怎么来使用这个库:

首先是添加头文件:

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

然后我们创建一个(1,0,0)的初始坐标vec(齐次坐标):

glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);

怎么对这个坐标产生平移、旋转和缩放等操作呢?
我们可以先创建一个转换矩阵trans,以单位矩阵初始化:

glm::mat4 trans = glm::mat4(1.0f);

然后对它做一个位移(1, 1, 0)的转换:

trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));

然后绕z轴逆时针旋转90°:

trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));

最后0.5倍缩放:

trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));

转换完的矩阵与原坐标相乘即得到转换后的坐标:

vec = trans * vec;

如果要把它应用到顶点着色器中呢?
可以设定一个uniform变量将变换矩阵传入:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

uniform mat4 transform;

void main()
{
    gl_Position = transform * vec4(aPos, 1.0f);
    TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}

然后在程序中设置这个矩阵:

unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));

glUniformMatrix4fv函数的第一个参数是uniform的位置值。第二个参数告诉OpenGL我们将要发送多少个矩阵,这里是1。第三个参数询问我们是否希望对我们的矩阵进行转置(Transpose),也就是说交换我们矩阵的行和列。OpenGL开发者通常使用一种内部矩阵布局,叫做列主序(Column-major Ordering)布局。GLM的默认布局就是列主序,所以并不需要转置矩阵,我们填GL_FALSE。最后一个参数是真正的矩阵数据,但是GLM并不是把它们的矩阵储存为OpenGL所希望接受的那种,因此我们要先用GLM的自带的函数value_ptr来变换这些数据。

我们还可以加上实时旋转效果:

        unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
        //使用着色器程序
        ourShader.use();
        glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
        trans = glm::rotate(trans, timeValue/10000, glm::vec3(0.0f, 0.0f, 1.0f));

效果:
在这里插入图片描述

2. 练习

2.1 使用应用在箱子上的最后一个变换,尝试将其改变为先旋转,后位移。看看发生了什么,试着想想为什么会发生这样的事情

效果:
在这里插入图片描述
在这里插入图片描述

原因:矩阵的乘法不满足交换律

2.2 尝试再次调用glDrawElements画出第二个箱子,只使用变换将其摆放在不同的位置。让这个箱子被摆放在窗口的左上角,并且会不断的缩放(而不是旋转)。(sin函数在这里会很有用,不过注意使用sin函数时应用负值会导致物体被翻转)

重新计算变换矩阵再调用glDrawElements即可(貌似只能在原矩阵变量上修改):

    while (!glfwWindowShouldClose(window))
    {
        // 输入
        processInput(window);
        //调用glClear函数,清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        // 渲染指令
        float timeValue = glfwGetTime();
        float visi = (sin(timeValue) / 2.0f) + 0.5f;
        int vertexColorLocation = glGetUniformLocation(ourShader.ID, "visibility");
        unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
        //使用着色器程序
        ourShader.use();
        glm::mat4 trans = glm::mat4(1.0f);
        trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));
        trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));
        trans = glm::rotate(trans, timeValue, glm::vec3(0.0f, 0.0f, 1.0f));
        glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
        glUniform2f(vertexColorLocation, visi, 1.0f);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture[0]);//绑定纹理,自动把纹理赋值给片段着色器的采样器
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture[1]);//绑定纹理,自动把纹理赋值给片段着色器的采样器
        glBindVertexArray(VAO); // 一般每次使用时再绑定,这里只有一个VAO,所以实际上可以不绑
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        
        trans = glm::mat4(1.0f);
        trans = glm::translate(trans, glm::vec3(-0.5f, 0.5f, 0.0f));
        trans = glm::scale(trans1, glm::vec3(visi, visi, visi));
        glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        //检查并调用事件,交换缓冲
        glfwSwapBuffers(window);//交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上
        glfwPollEvents();//检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数(可以通过回调方法手动设置)
    }

效果:
在这里插入图片描述

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ycr的帐号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值