OpenGL学习(六)变换
参考官方文档https://learnopengl-cn.github.io/
那么现在有意思的来了。首先关于矩阵运算就不用多做介绍了。直接进入实战部分。先下载GLM。这个直接百度可以找到:https://github.com/g-truc/glm。(官方文档中给出的链接打不开,只能百度)下载解压。刚开始我以为需要用cMake,后面发现不用cMake,只需要在你当前的项目的属性中添加包含目录就行了。需要用到的大多数功能都可以在下面3个头文件中找到。
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
例如:
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include<iostream>
int main() {
glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);//创建向量
glm::mat4 trans = glm::mat4(1.0f);//创建一个4*4的单位矩阵
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+1,0+1,0+0=>2,1,0
}
输出结果为:
210
C:\Users\xhh\Source\Repos\glmTest\x64\Debug\glmTest.exe (进程 58428)已退出,代码为 0。
按任意键关闭此窗口. . .
下面我们将再我们前面的窗口的基础上,运用glm的矩阵来操作窗口的绘图。
顶点着色器shader.vs
#version 330 core
layout(location=0) in vec3 aPos;
layout(location=1) in vec3 aColor;
layout(location=2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 transform;
void main(){
gl_Position=transform*vec4(aPos.x,aPos.y,aPos.z,1.0);
ourColor=aColor;
TexCoord=vec2(aTexCoord.x,1.0-aTexCoord.y);
}
主程序中main.cpp
...;
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
...;
int main(){
...;
glm::mat4 trans;
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));
...;
while(...){
...;
unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
...;
}
...;
}
这样对我们的图案旋转90度并缩小为原来的二分之一。像这样
或者再渲染循环中将举证创建为:
glm::mat4 trans = glm::mat4(1.0f);
trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));
trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
最终运行时会发现窗口中的图片会不断的旋转:
练习:
- 使用应用在箱子上的最后一个变换,尝试将其改变为先旋转,后位移。看看发生了什么,试着想想为什么会发生这样的事情
改为:
trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));
这时它会绕窗口的中心旋转而不是箱子的中心旋转,
为什么这两个操作的顺序反过来结果会差别这么大呢?
这个问题学过量子力学的应该很好理解。其实很简单的一个问题,前面的代码是平移在前而旋转在后,两个操作平移记为T,旋转记为R,作用到向量X上,TRX
,所以实际上是先绕窗口中心旋转然后再平移到右下角。而现在就是反过来,先平移到右下角然后再绕中心旋转。旋转角度是随时间增大的,所以实际上就变成这样了。
- 尝试再次调用glDrawElements画出第二个箱子,只使用变换将其摆放在不同的位置。让这个箱子被摆放在窗口的左上角,并且会不断的缩放(而不是旋转)。(
sin
函数在这里会很有用,不过注意使用sin
函数时应用负值会导致物体被翻转)
第二个箱子,再渲染循环中接着前面的glDrawElements来,代码如下:
//第二个箱子
trans = glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, 0.5f, 0.0f));
trans = glm::scale(trans, glm::vec3(abs(sin((float)(glfwGetTime()))),abs(sin((float)glfwGetTime())), 1.0f));
transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
ourShader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
很顺利的得到了想要的结果了,它会随时间缩小幅度变化: