OpenGL中的变换

1. 矩阵变换

在opengl中矩阵变换使用的为齐次坐标;使用齐次坐标有几点好处:它允许我们在3D向量上进行位移,同时也方便使用透视投影操作。本篇文章主要偏向于实现,不深究理论的知识。

1.1 缩放

为向量(x,y,z)定义一个缩放矩阵
在这里插入图片描述

1.2 平移

为向量(x,y,z)定义一个平移矩阵
在这里插入图片描述

1.3 旋转

旋转过程涉及到弧度与角度的转化

  • 弧度转角度:角度 = 弧度 * (180.0f / PI)
  • 角度转弧度:弧度 = 角度 * (PI / 180.0f)
    opengl中使用的是角度制

为向量(x,y,z)定义一个旋转矩阵
在这里插入图片描述

1.4 矩阵组合

假设我们有一个顶点(x, y, z),我们希望将其缩放2倍,然后位移(1, 2, 3)个单位。变换矩阵可以描述为:
在这里插入图片描述
注意:最右边的矩阵是第一个与向量相乘的,所以应该从右向左读这个乘法,即先缩放后平移。

2. 案例实现

在OpenGL中使用矩阵变化,首先需要包含矩阵库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);//坐标(1.0f, 0.0f, 0.0f)
// 下面是矩阵初始化的一个例子,如果使用的是0.9.9及以上版本
// 下面这行代码就需要改为:
// glm::mat4 trans = glm::mat4(1.0f)
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;

若是输出结果为(2,1,0)说明配置成功

在做变换之前需要修改下顶点着色器,在着色器中添加与变换矩阵相关的内容

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

out vec2 TexCoord;

uniform mat4 transform;//GLSL中的mat4类型

void main()
{
    
    
//修改顶点着色器让其接收一个mat4的uniform变量,然后再用矩阵uniform乘以位置向量
	gl_Position = transform * vec4(aPos, 1.0);
	TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}

其余的部分代码保持不变,仅需要修改渲染循环中的代码:

[transformLoc 矩阵一系列变换....]
unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
  • 第一个参数你现在应该很熟悉了,它是uniform的位置值。
  • 第二个参数告诉OpenGL我们将要发送多少个矩阵,这里是1。
  • 第三个参数询问我们是否希望对我们的矩阵进行转置(Transpose),也就是说交换我们矩阵的行和列。OpenGL开发者通常使用一种内部矩阵布局,叫做列主序(Column-major Ordering)布局。GLM的默认布局就是列主序,所以并不需要转置矩阵,我们填GL_FALSE。
  • 最后一个参数是真正的矩阵数据,但是GLM并不是把它们的矩阵储存为OpenGL所希望接受的那种,因此我们要先用GLM的自带的函数value_ptr来变换这些数据

先看看原图:

  glm::mat4 transform = glm::mat4(1.0f); //单位阵
  ourShader.use();
  unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
 glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

在这里插入图片描述

2.1 缩放:

2.1.1 等比缩放

 glm::mat4 transform = glm::mat4(1.0f); 
 transform = glm::scale(transform, glm::vec3(2.0f, 2.0f, 2.0f));//z值可以不管
 ourShader.use();
 unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

在这里插入图片描述

2.1.2 不等比缩放

 glm::mat4 transform = glm::mat4(1.0f); 
 transform = glm::scale(transform, glm::vec3(1.3f, 1.0f, 1.0f));//z值可以不管
 ourShader.use();
 unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

在这里插入图片描述

2.1.3 镜像X方向

 glm::mat4 transform = glm::mat4(1.0f); 
 transform = glm::scale(transform, glm::vec3(-1.3f, 1.0f, 1.0f));//z值可以不管
 ourShader.use();
 unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

在这里插入图片描述

2.1.4 镜像Y方向

 glm::mat4 transform = glm::mat4(1.0f); 
 transform = glm::scale(transform, glm::vec3(1.3f, -1.0f, 1.0f));//z值可以不管
 ourShader.use();
 unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

在这里插入图片描述

2.2 平移

 glm::mat4 transform = glm::mat4({
    
    }1.0f); 
transform = glm::translate(transform, glm::vec3(0.5f, -0.5f, 0.0f));
 ourShader.use();
 unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

在这里插入图片描述

2.2.1 动态平移

 glm::mat4 transform = glm::mat4(1.0f); 
transform = glm::translate(transform, glm::vec3(0.5f*sin((float)glfwGetTime()), 0.5f * cos((float)glfwGetTime()), 0.0f));//画圆
 ourShader.use();
 unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

请添加图片描述

2.3 旋转

glm::radians(90.0f)表示旋转角度,逆时针为正,glm::vec3(0.0f, 0.0f, 1.0f)表示绕着Z轴

 glm::mat4 transform = glm::mat4(1.0f); 
transform = glm::rotate(transform, glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
 ourShader.use();
 unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

在这里插入图片描述

2.3.1 动态旋转

 glm::mat4 transform = glm::mat4(1.0f); 
 transform = glm::rotate(transform, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
 ourShader.use();
 unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

请添加图片描述

2.4 组合变换

先来看看先平移后缩放和先缩放后平移的效果,注意谁先就离顶点向量近(后写)
先平移后缩放代码

transform = glm::scale(transform, glm::vec3(0.5f, 0.5f, 1.0f));
transform = glm::translate(transform, glm::vec3(0.5f, -0.5f , 0.0f));

先缩放后平移代码

transform = glm::translate(transform, glm::vec3(0.5f, -0.5f , 0.0f));
transform = glm::scale(transform, glm::vec3(0.5f, 0.5f, 1.0f));

实现的结果还是相差很多的,所以在写的时候得特别注意!
在这里插入图片描述

2.4.1 复杂的组合变换

让我们在试一试更复杂的组合变换

 transform = glm::translate(transform, glm::vec3(0.5f * sin((float)glfwGetTime()), 0.5f * cos((float)glfwGetTime()), 0.0f));
 transform = glm::rotate(transform, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));  
 transform = glm::scale(transform, glm::vec3(0.8f * sin(0.5*(float)glfwGetTime()), 0.8f * sin(0.5*(float)glfwGetTime()), 1.0f));

请添加图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44478077/article/details/124083856