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);
}
運行結果: