上接:https://blog.csdn.net/weixin_44506615/article/details/149981077?spm=1001.2014.3001.5501
完整代码:https://gitee.com/Duo1J/learn-open-gl
一、变换
首先我们先来快速了解三种变换矩阵,分别是缩放、旋转和位移矩阵
如果对线性代数印象较浅了的话,可以先看看原文的简单介绍
1. 缩放矩阵
对于一个4x4的单位矩阵,我们修改对角线前三项1,就可以得到一个缩放矩阵,如下图 (图片来自于LearnOpenGL)
这里的S1、S2、S3即为缩放因子,这个矩阵会对我们的向量(x, y, z, 1)进行缩放操作
大家可能注意到矩阵和向量的最后都补了1,在之后的变换中,我们都会使用这样的矩阵和向量进行计算,这里的w分量称为齐次坐标,在接下来位移矩阵中会解释为何需要
2. 位移矩阵
位移矩阵如下图所示 (图片来自于LearnOpenGL)
我们在矩阵的第4列设置了Tx,Ty,Tz三个常数来表示位移,经过矩阵运算后,三个常数都会乘到向量的w分量上,最后加到原坐标值中,这就是为什么我们需要使用齐次坐标的原因
3. 旋转矩阵
旋转矩阵的推导过程比较复杂,大家有兴趣的话可以去看看GAMES101的第四节Transformation中的16min左右的位置
旋转矩阵如下图所示 (图片来自于LearnOpenGL)
4. 矩阵的组合
使用矩阵有一个方便的点是,我们可以将多个矩阵通过矩阵乘法组合起来,随后可以对一系列的向量进行变换,如下图所示 (图片来自于LearnOpenGL)
不过需要注意的是,矩阵的乘法是不遵守交换率的,所以我们需要注意顺序,当矩阵相乘时、在最右边的矩阵会是第一个和向量相乘的,我们应该先做缩放、然后是旋转,最后是位移,否则他们之间会互相造成影响
例如先进行位移再缩放,那么我们位移的这段距离也会被一起缩放
5. 变换我们的矩形
接下来我们来尝试变换一下我们之前绘制的矩形,在这之前我们还需要引入一个数学库来辅助我们计算
GLM (OpenGL Mathematics) 是一个只有头文件的数学库,专门为OpenGL量身定做,可以在Github这个链接上拉取,然后将头文件复制到我们的项目中,或是像glfw一样在VC++包含目录中配置头文件的路径
接下来来对我们的图形进行变换操作
首先引入接下来需要的头文件
// 根据你的引入方式,可能需要在前方带上glm文件夹
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>
接下来创建一个变换矩阵
我们先沿着x正方形位移0.3
接着逆时针旋转90度
最后缩放至原大小的0.5倍
glm::mat4 trans = glm::mat4(1.0f);
trans = glm::translate(trans, glm::vec3(0.3, 0, 0));
// 弧度制
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));
矩阵创建好之后,我们就需要将它传递给顶点着色器来对顶点进行变换
修改顶点着色器,添加4x4矩阵uniform变量
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 vertexColor;
out vec2 texCoord;
// 变换矩阵
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(aPos, 1.0);
vertexColor = aColor;
texCoord = aTexCoord;
}
然后为我们的Shader类扩展一个矩阵uniform设置接口
// Shader.h
/**
* 设置mat4类型uniform值
*/
void SetMat4(const std::string& name, float* value) const;
// Shader.cpp
void Shader::SetMat4(const std::string& name, float* value) const
{
// 参数2:矩阵数量
// 参数3:是否转置
glUniformMatrix4fv(glGetUniformLocation(ProgramID, name.c_str()), 1, GL_FALSE, value);
}
最后,传递矩阵给uniform变量
shader.Use();
// 这里需要通过value_ptr将矩阵对象转换为float*
shader.SetMat4("transform", glm::value_ptr(trans));
编译运行,顺利的话可以看见以下图像
并且我们可以通过glfwGetTime()来做一个简单的变换动画,这里就不赘述了
本节完成之后,下节我们就可以开始进行3D物体的绘制了
完整代码请见开头的git仓库