OpenGL之shader着色器的應用,三色漸變的三角形


學習自:

https://learnopengl-cn.github.io/01%20Getting%20started/05%20Shaders/#_7

首先放一張效果圖:

 

本次教程,將着色器單獨定義了一個類,方便代碼閱讀與編寫。

1,首先新建要給shader類:shader_s.h

(1)shader_s.h

 1 #ifndef SHADER_H
 2 #define SHADER_H
 3 
 4 #include <glad/glad.h> // 包含glad來獲取所有的必須OpenGL頭文件
 5 
 6 #include <string>
 7 #include <fstream>
 8 #include <sstream>
 9 #include <iostream>
10 
11 
12 class Shader
13 {
14 public:
15     // 程序ID
16     unsigned int ID;
17 
18     // 構造器讀取並構建着色器
19     Shader(const GLchar* vertexPath, const GLchar* fragmentPath);
20     // 使用/激活程序
21     void use();
22     // uniform工具函數
23     void setBool(const std::string &name, bool value) const;
24     void setInt(const std::string &name, int value) const;
25     void setFloat(const std::string &name, float value) const;
26 private:
27     void checkCompileErrors(unsigned int shader, std::string type);
28 };
29 
30 #endif

(2)將頭文件中的方法逐一實現

注意的是,我們類的寫法,與鏈接中的寫法有不同之處。

#include "shader_s.h"

Shader::Shader(const GLchar * vertexPath, const GLchar * fragmentPath)
{
    // 1. 從文件路徑中獲取頂點/片段着色器
    std::string vertexCode;
    std::string fragmentCode;
    std::ifstream vShaderFile;
    std::ifstream fShaderFile;
    // 保證ifstream對象可以拋出異常:
    vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    try
    {
        // 打開文件
        vShaderFile.open(vertexPath);
        fShaderFile.open(fragmentPath);
        std::stringstream vShaderStream, fShaderStream;
        // 讀取文件的緩沖內容到數據流中
        vShaderStream << vShaderFile.rdbuf();
        fShaderStream << fShaderFile.rdbuf();
        // 關閉文件處理器
        vShaderFile.close();
        fShaderFile.close();
        // 轉換數據流到string
        vertexCode = vShaderStream.str();
        fragmentCode = fShaderStream.str();
    }
    catch (std::ifstream::failure e)
    {
        std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
    }
    const char* vShaderCode = vertexCode.c_str();
    const char * fShaderCode = fragmentCode.c_str();
    // 2. 編譯着色器
    unsigned int vertex, fragment;
    // 頂點着色器    vs
    vertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex, 1, &vShaderCode, NULL);
    glCompileShader(vertex);
    checkCompileErrors(vertex, "VERTEX");
    // 片段着色器    fs
    fragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment, 1, &fShaderCode, NULL);
    glCompileShader(fragment);
    checkCompileErrors(fragment, "FRAGMENT");
    // 着色器程序
    ID = glCreateProgram();
    glAttachShader(ID, vertex);
    glAttachShader(ID, fragment);
    glLinkProgram(ID);
    checkCompileErrors(ID, "PROGRAM");
    // 刪除着色器,它們已經鏈接到我們的程序中了,已經不再需要了    glDeleteShader(vertex);
    glDeleteShader(fragment);
}

void Shader::use()
{
    glUseProgram(ID);
}

void Shader::setBool(const std::string & name, bool value) const
{
    glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}

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

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

void Shader::checkCompileErrors(unsigned int shader, std::string type)
{
    int success;
    char infoLog[1024];
    if (type != "PROGRAM")
    {
        glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
        if (!success)
        {
            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, &success);
        if (!success)
        {
            glGetProgramInfoLog(shader, 1024, NULL, infoLog);
            std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
        }
    }
}

2,主程序的使用

注意,我們的50行,在使用類的構造方法時候,傳入的兩個字符串表示的是我們的兩個本地文件地址,這兩個文件,表示的是,我們的兩個shader腳本,需要我們的手動創建,並且加入代碼。

兩個腳本在最后給出。

 (1)主程序TestShader.cpp

有一點需要注意的是,在vs中,我們自定義的類,如果要引用,用的是雙引號 “”

也就是 #include "shader_s.h" 跟鏈接中的也有區別

  1 #include <glad/glad.h>
  2 #include <GLFW/glfw3.h>
  3 
  4 #include "shader_s.h"
  5 
  6 #include <iostream>
  7 
  8 void framebuffer_size_callback(GLFWwindow* window, int width, int height);
  9 void processInput(GLFWwindow *window);
 10 
 11 // settings
 12 const unsigned int SCR_WIDTH = 800;
 13 const unsigned int SCR_HEIGHT = 600;
 14 
 15 int main()
 16 {
 17     // glfw: initialize and configure
 18     // ------------------------------
 19     glfwInit();
 20     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
 21     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
 22     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
 23 
 24 #ifdef __APPLE__
 25     glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
 26 #endif
 27 
 28     // glfw window creation
 29     // --------------------
 30     GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
 31     if (window == NULL)
 32     {
 33         std::cout << "Failed to create GLFW window" << std::endl;
 34         glfwTerminate();
 35         return -1;
 36     }
 37     glfwMakeContextCurrent(window);
 38     glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
 39 
 40     // glad: load all OpenGL function pointers
 41     // ---------------------------------------
 42     if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
 43     {
 44         std::cout << "Failed to initialize GLAD" << std::endl;
 45         return -1;
 46     }
 47 
 48     // build and compile our shader program
 49     // ------------------------------------
 50     Shader ourShader("../res/shader.vs", "../res/shader.fs"); // you can name your shader files however you like
 51 
 52     // set up vertex data (and buffer(s)) and configure vertex attributes
 53     // ------------------------------------------------------------------
 54     float vertices[] = {
 55         // 位置信息         // 顏色信息
 56          0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  // 右下
 57         -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  // 左下
 58          0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f   // 頂部 
 59     };
 60 
 61     unsigned int VBO, VAO;
 62     glGenVertexArrays(1, &VAO);
 63     glGenBuffers(1, &VBO);
 64     //首先綁定頂點數組對象,然后綁定並設置頂點緩沖區,然后配置頂點屬性。    
 65     glBindVertexArray(VAO);
 66 
 67     glBindBuffer(GL_ARRAY_BUFFER, VBO);
 68     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
 69 
 70     // 位置屬性
 71     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
 72     glEnableVertexAttribArray(0);
 73     // 顏色屬性
 74     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
 75     glEnableVertexAttribArray(1);
 76     /*
 77     glVertexAttribPointer 指定了渲染時索引值為 index 的頂點屬性數組的數據格式和位置。
 78     void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,const GLvoid * pointer);
 79     參數:
 80     (1)index
 81     指定要修改的頂點屬性的索引值
 82     (2)size
 83     指定每個頂點屬性的組件數量。必須為1、2、3或者4。初始值為4。(如position是由3個(x,y,z)組成,而顏色是4個(r,g,b,a))
 84     (4)type
 85     指定數組中每個組件的數據類型。可用的符號常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值為GL_FLOAT。
 86     (5)normalized
 87     指定當被訪問時,固定點數據值是否應該被歸一化(GL_TRUE)或者直接轉換為固定點值(GL_FALSE)。
 88     (6)stride
 89     指定連續頂點屬性之間的偏移量。如果為0,那么頂點屬性會被理解為:它們是緊密排列在一起的。初始值為0。
 90     (7)pointer
 91     指定第一個組件在數組的第一個頂點屬性中的偏移量。該數組與GL_ARRAY_BUFFER綁定,儲存於緩沖區中。初始值為0;
 92     */
 93 
 94     // 循環渲染
 95     while (!glfwWindowShouldClose(window))
 96     {
 97         // input
 98         // -----
 99         processInput(window);
100 
101         // render
102         // ------
103         glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
104         glClear(GL_COLOR_BUFFER_BIT);
105 
106         // render the triangle
107         ourShader.use();
108         glBindVertexArray(VAO);
109         glDrawArrays(GL_TRIANGLES, 0, 3);
110 
111         // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
112         // -------------------------------------------------------------------------------
113         glfwSwapBuffers(window);
114         glfwPollEvents();
115     }
116 
117     // optional: de-allocate all resources once they've outlived their purpose:
118     // ------------------------------------------------------------------------
119     glDeleteVertexArrays(1, &VAO);
120     glDeleteBuffers(1, &VBO);
121 
122     // glfw: terminate, clearing all previously allocated GLFW resources.
123     // ------------------------------------------------------------------
124     glfwTerminate();
125     return 0;
126 }
127 
128 // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
129 // ---------------------------------------------------------------------------------------------------------
130 void processInput(GLFWwindow *window)
131 {
132     if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
133         glfwSetWindowShouldClose(window, true);
134 }
135 
136 // glfw: whenever the window size changed (by OS or user resize) this callback function executes
137 // ---------------------------------------------------------------------------------------------
138 void framebuffer_size_callback(GLFWwindow* window, int width, int height)
139 {
140     // make sure the viewport matches the new window dimensions; note that width and 
141     // height will be significantly larger than specified on retina displays.
142     glViewport(0, 0, width, height);
143 }

(2) 腳本編寫

TestShader是我的項目名,然后新建文件夾res,存放我們的腳本,然后創建兩個腳本,名字自己取就好,主程序中對應好就好了。

 

a)頂點着色器(Vetex Shader)shader.vs

#version 330 core
layout (location = 0) in vec3 aPos;   // 位置變量的屬性位置值為 0 
layout (location = 1) in vec3 aColor; // 顏色變量的屬性位置值為 1

out vec3 ourColor; // 向片段着色器輸出一個顏色

void main()
{
    gl_Position = vec4(aPos, 1.0);
    ourColor = aColor; // 將ourColor設置為我們從頂點數據那里得到的輸入顏色
}

b)片段着色器(fragment Shader)shader.fs

1 #version 330 core
2 out vec4 FragColor;  
3 in vec3 ourColor;
4 
5 void main()
6 {
7     FragColor = vec4(ourColor, 1.0);
8 }

3,最后運行我們的程序,就可以得到下面的效果圖:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM