1. 程式人生 > >OpenGL基礎 通過矩陣操作,將影象進行移動旋轉

OpenGL基礎 通過矩陣操作,將影象進行移動旋轉

main.cpp

#define STB_IMAGE_IMPLEMENTATION

#include <glad/glad.h>
#include <glad/glad.c>

#include <GLFW/glfw3.h>
#include <stb_image.h>
#include <iostream>

#include "shader.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#pragma comment (lib, "glfw3.lib") void framebuffer_size_callback(GLFWwindow* pWnd, int width, int height); void processInput(GLFWwindow *pWnd); const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600; int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3
); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); GLFWwindow* pWnd = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); if (pWnd == NULL) { std::cout << "Failed to create GLFW pWnd" << std::endl; glfwTerminate(); return
-1; } glfwMakeContextCurrent(pWnd); glfwSetFramebufferSizeCallback(pWnd, framebuffer_size_callback); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } glEnable(GL_DEPTH_TEST); // 開啟深度測試 Shader ourShader("coordinate_systems.vs", "coordinate_systems.fs"); float vertices[] = { // 模型位置座標3 紋理座標3 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f }; // 為每個立方體定義一個位移向量來指定它在世界空間的位置 glm::vec3 cubePositions[] = { glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(2.0f, 5.0f, -15.0f), glm::vec3(-1.5f, -2.2f, -2.5f), glm::vec3(-3.8f, -2.0f, -12.3f), glm::vec3(2.4f, -0.4f, -3.5f), glm::vec3(-1.7f, 3.0f, -7.5f), glm::vec3(1.3f, -2.0f, -2.5f), glm::vec3(1.5f, 2.0f, -2.5f), glm::vec3(1.5f, 0.2f, -1.5f), glm::vec3(-1.3f, 1.0f, -1.5f) }; unsigned int VBO, VAO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // position attribute -> layout 0 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // texture coord attribute -> layout 1 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); // 影象1 unsigned int texture1; glGenTextures(1, &texture1); // 建立一個空的紋理物件 glBindTexture(GL_TEXTURE_2D, texture1);// 繫結後,接下來對紋理的操作均在此ID上進行 // set the texture wrapping parameters 設定紋理環繞方式:均為重複 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // set texture filtering parameters 過濾方式:縮小放大均為線性 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); // 翻轉影象 unsigned char *data = stbi_load("../res/container.jpg", &width, &height, &nrChannels, 0); if (data) { // 用紋理圖片資料生成一個2D紋理,即將空的紋理物件填入資料 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 unsigned int texture2; glGenTextures(1, &texture2); // 建立一個空的紋理物件 glBindTexture(GL_TEXTURE_2D, texture2);// 繫結後,接下來對紋理的操作均在此ID上進行 // set the texture wrapping parameters 設定紋理環繞方式:均為重複 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // set texture filtering parameters 過濾方式:縮小放大均為線性 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); data = stbi_load("../res/Sloth.jpg", &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); // 釋放圖片資源 // 紋理分別對應不同的取樣器 ourShader.useShaderProgram(); ourShader.setInt("texture1", 0); ourShader.setInt("texture2", 1); while (!glfwWindowShouldClose(pWnd)) { processInput(pWnd); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // also clear the depth buffer now! glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture1); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture2); ourShader.useShaderProgram(); // create transformations glm::mat4 viewMat; glm::mat4 projectionMat; projectionMat = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); viewMat = glm::translate(viewMat, glm::vec3(0.0f, 0.0f, -3.0f)); // pass transformation matrices to the shader ourShader.setMat4("projection", projectionMat); ourShader.setMat4("view", viewMat); // render boxes glBindVertexArray(VAO); for (unsigned int i = 0; i < 10; i++) { // calculate the model matrix for each object and pass it to shader before drawing // 模型變換 -> 世界座標 // 偏移 glm::mat4 model; model = glm::translate(model, cubePositions[i]); // 旋轉 float angle = 20.0f * i; model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); ourShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); } glfwSwapBuffers(pWnd); glfwPollEvents(); } glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glfwTerminate(); return 0; } void processInput(GLFWwindow *pWnd) { if (glfwGetKey(pWnd, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(pWnd, true); } void framebuffer_size_callback(GLFWwindow* pWnd, int width, int height) { glViewport(0, 0, width, height); }

shader.h

#ifndef SHADER_H
#define SHADER_H

#include <glad/glad.h>; // 包含glad來獲取所有的必須OpenGL標頭檔案

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

class Shader
{
public:
    // 程式ID
    unsigned int m_ID;

    // 構造器讀取並構建著色器
    Shader(const GLchar* vertexPath, const GLchar* fragmentPath);

    // 使用/啟用程式
    void useShaderProgram();

    // uniform工具函式
    void setBool(const std::string &name, bool value) const;
    void setInt(const std::string &name, int value) const;
    void setFloat(const std::string &name, float value) const;
    void setMat4(const std::string &name, glm::mat4 mat) const;

private:
    void checkCompileErrors(unsigned int shader, std::string type);
};

#endif

shader.cpp

#include "shader.h"


Shader::Shader(const char* vertexPath, const char* fragmentPath)
{
    // 1. retrieve the vertex/fragment source code from filePath
    // 載入讀取Shader檔案
    std::string strVertexCode;
    std::string strFragmentCode;
    std::ifstream vShaderFile;
    std::ifstream fShaderFile;
    // ensure ifstream objects can throw exceptions:
    vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    try
    {
        // open files
        vShaderFile.open(vertexPath);
        fShaderFile.open(fragmentPath);
        std::stringstream vShaderStream, fShaderStream;
        // read file's buffer contents into streams
        vShaderStream << vShaderFile.rdbuf();
        fShaderStream << fShaderFile.rdbuf();
        // close file handlers
        vShaderFile.close();
        fShaderFile.close();
        // convert stream into string
        strVertexCode = vShaderStream.str();
        strFragmentCode = fShaderStream.str();
    }
    catch (std::ifstream::failure e)
    {
        std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
    }
    const char* vShaderCode = strVertexCode.c_str();
    const char * fShaderCode = strFragmentCode.c_str();

    // 2. compile shaders 編譯
    unsigned int nVertex, nFragment;
    int nSuccess = 0;
    char infoLog[512];
    // vertex shader
    nVertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(nVertex, 1, &vShaderCode, NULL);
    glCompileShader(nVertex);
    checkCompileErrors(nVertex, "VERTEX");
    // fragment Shader
    nFragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(nFragment, 1, &fShaderCode, NULL);
    glCompileShader(nFragment);
    checkCompileErrors(nFragment, "FRAGMENT");
    // shader Program
    m_ID = glCreateProgram();
    glAttachShader(m_ID, nVertex);
    glAttachShader(m_ID, nFragment);
    glLinkProgram(m_ID);
    checkCompileErrors(m_ID, "PROGRAM");
    // delete the shaders as they're linked into our program now and no longer necessary
    glDeleteShader(nVertex);
    glDeleteShader(nFragment);
}


// activate the shader
// ------------------------------------------------------------------------
void Shader::useShaderProgram()
{
    glUseProgram(m_ID);
}

// utility uniform functions
// ------------------------------------------------------------------------
void Shader::setBool(const std::string &name, bool value) const
{
    glUniform1i(glGetUniformLocation(m_ID, name.c_str()), (int)value);
}

// ------------------------------------------------------------------------
void Shader::setInt(const std::string &name, int value) const
{
    glUniform1i(glGetUniformLocation(m_ID, name.c_str()), value);
}

// ------------------------------------------------------------------------
void Shader::setFloat(const std::string &name, float value) const
{
    glUniform1f(glGetUniformLocation(m_ID, name.c_str()), value);
}

void Shader::setMat4(const std::string &name, glm::mat4 mat) const
{
    glUniformMatrix4fv(glGetUniformLocation(m_ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}

// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void Shader::checkCompileErrors(unsigned int shader, std::string type)
{
    int nSuccess = 0;
    char infoLog[1024];
    if (type != "PROGRAM")
    {
        glGetShaderiv(shader, GL_COMPILE_STATUS, &nSuccess);
        if (!nSuccess)
        {
            glGetShaderInfoLog(shader, 1024, NULL, infoLog);
            std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
        }
    }
    else
    {
        glGetProgramiv(shader, GL_LINK_STATUS, &nSuccess);
        if (!nSuccess)
        {
            glGetProgramInfoLog(shader, 1024, NULL, infoLog);
            std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
        }
    }
}

coordinate_systems.vs

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

layout (location = 1) in vec2 texturePos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out vec2 TexCoord;

void main()
{
    // 注意乘法要從右向左讀
    gl_Position = projection * view * model * vec4(aPos, 1.0);

    TexCoord = vec2(texturePos.x, 1.0 - texturePos.y);
}

coordinate_systems.fs

#version 330 core  // 版本宣告
out vec4 FragColor; // 輸出繪製

in vec2 TexCoord; // 從vs中傳進

uniform sampler2D texture1;  // 紋理取樣器
uniform sampler2D texture2;  // 紋理取樣器

void main()
{
    // 兩個紋理進行混合
    FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.5);
}

執行結果

程式碼截圖