OpenGL图形变换介绍:https://learnopengl-cn.github.io/01%20Getting%20started/07%20Transformations
【OpenGL学习】(八)图形变换
本项目将通过变换矩阵,对【OpenGL学习】(七)纹理单元 中的图形进行缩放,旋转和平移。
项目链接: https://github.com/BinaryAI-1024/OpenGLPorjects/tree/master/transformations
顶点着色器transform.vs:
#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.0); // 坐标变换TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
片段着色器transform.fs:
#version 330 core
out vec4 FragColor;in vec3 ourColor;
in vec2 TexCoord;// texture samplers
uniform sampler2D texSampler1;
uniform sampler2D texSampler2;void main()
{// 在两个纹理之间进行线性插值 (80% container, 20% awesomeface)FragColor = mix(texture(texSampler1, TexCoord), texture(texSampler2, TexCoord), 0.2);
}
transfomations.cpp
#define STB_IMAGE_IMPLEMENTATION
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>#include <filesystem.h>
#include <shader_s.h>#include <iostream>void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;int main()
{// 初始化GLFW并配置glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac OS X需要前向兼容
#endif// 创建窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window); // 设置为当前上下文glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // 注册窗口大小变化回调// 初始化GLAD(加载OpenGL函数指针)if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// 编译着色器程序Shader ourShader("transform.vs", "transform.fs");// 顶点数据和缓冲区设置float vertices[] = {// 位置 // 纹理坐标0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // 右上0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // 右下-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // 左下-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // 左上 };unsigned int indices[] = {0, 1, 3, // 第一个三角形1, 2, 3 // 第二个三角形};// 生成缓冲区对象unsigned int VBO, VAO, EBO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);// 绑定VAOglBindVertexArray(VAO);// 绑定VBO并传输顶点数据glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 绑定EBO并传输索引数据glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);// 设置位置属性指针glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// 设置纹理坐标属性指针glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);// 加载并创建纹理unsigned int texture1, texture2;// 纹理1 - 容器纹理glGenTextures(1, &texture1);glBindTexture(GL_TEXTURE_2D, texture1);// 设置纹理环绕方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);// 设置纹理过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 加载图像数据int width, height, nrChannels;stbi_set_flip_vertically_on_load(true); // 翻转y轴unsigned char* data = stbi_load(FileSystem::getPath("resources/container.jpg").c_str(), &width, &height, &nrChannels, 0);if (data){glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);}else{std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data);// 纹理2 - 笑脸纹理glGenTextures(1, &texture2);glBindTexture(GL_TEXTURE_2D, texture2);// 设置纹理参数(同上)glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 加载图像数据(注意这是PNG有透明通道)data = stbi_load(FileSystem::getPath("resources/awesomeface.png").c_str(), &width, &height, &nrChannels, 0);if (data){glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);}else{std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data);// 设置着色器中的采样器对应的纹理单元ourShader.use();ourShader.setInt("texSampler1", 0); // 纹理单元0ourShader.setInt("texSampler2", 1); // 纹理单元1// 渲染循环while (!glfwWindowShouldClose(window)){// 输入处理processInput(window);// 渲染指令glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// 绑定纹理到对应的纹理单元glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, texture1);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texture2);// ========== 矩阵变换部分 ==========// 1. 创建变换矩阵(初始化为单位矩阵)glm::mat4 transform = glm::mat4(1.0f);// 2. 应用平移变换(向右0.5单位,向下0.5单位)transform = glm::translate(transform, glm::vec3(0.5f, -0.5f, 0.0f));// 3. 应用旋转变换(绕z轴旋转,旋转角度基于当前时间)// glfwGetTime()返回程序运行时间(秒)transform = glm::rotate(transform, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));// 4. 图形每个轴都缩放为0.5倍transform = glm::scale(transform, glm::vec3(0.5, 0.5, 0.5));// 矩阵变换的执行顺序是反向的:// 实际效果是:物体先缩小,再旋转,最后平移// 使用着色器程序并设置变换矩阵uniformourShader.use();unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");// 将矩阵传输给着色器glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));// 渲染四边形glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);// 交换缓冲区并查询IO事件glfwSwapBuffers(window);glfwPollEvents();}// 清理资源glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);// 终止GLFWglfwTerminate();return 0;
}void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height);
}
运行结果: