openGL之着色器程序的使用


  1 #define GLEW_STATIC
  2 #include <GL\glew.h>
  3 #include <GLFW\glfw3.h>
  4 #include<iostream>
  5 using namespace std;
  6 
  7 //函數原型
  8 void key_callback(GLFWwindow* window, int key, int scancode,
  9     int action, int mode);
 10 
 11 //窗口大小
 12 const GLuint WIDTH = 800, HEIGHT = 600;
 13 
 14 const GLchar* vertexShaderSource = "#version 330 core\n"
 15 "layout (location = 0) in vec3 position;\n"
 16 "void main()\n"
 17 "{\n"
 18 "gl_Position = vec4(position.x,position.y,position.z,1.0);\n"
 19 "}\0";
 20 
 21 const GLchar* fragmentShaderSource = "#version 330 core\n"
 22 "out vec4 color;\n"
 23 "void main()\n"
 24 "{\n"
 25 "color = vec4(1.0f,0.5f,0.2f,1.0f);\n"
 26 "}\n\0";
 27 
 28 int main(){
 29     //初始化 GLFW
 30     glfwInit();
 31 
 32     //設置GLFW需要的選項
 33     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
 34     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
 35     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
 36     glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
 37 
 38     //創建一個窗口對象
 39     GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "test2", nullptr, nullptr);
 40     glfwMakeContextCurrent(window);
 41 
 42     //設置徐亞的回調函數
 43     glfwSetKeyCallback(window, key_callback);
 44 
 45     glewExperimental = GL_TRUE;
 46 
 47     glewInit();
 48 
 49     int width, height;
 50     glfwGetFramebufferSize(window, &width, &height);
 51     glViewport(0, 0, width, height);
 52 
 53     //定點着色器
 54     GLuint vertextShader;
 55     vertextShader = glCreateShader(GL_VERTEX_SHADER);
 56     glShaderSource(vertextShader, 1, &vertexShaderSource, NULL);
 57     glCompileShader(vertextShader);
 58 
 59     //用於判斷一個着色器是否編譯成功
 60     GLint success;
 61     GLchar infoLog[512];
 62     glGetShaderiv(vertextShader, GL_COMPILE_STATUS, &success);
 63     if (!success){
 64         glGetShaderInfoLog(vertextShader, 512, NULL, infoLog);
 65         cout << "vertextShader COMPILE FAILED" << endl;
 66     }
 67 
 68     //像素着色器
 69     GLuint fragmentShader;
 70     fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
 71     glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
 72     glCompileShader(fragmentShader);
 73 
 74     //用於判斷一個着色器是否編譯成功
 75     glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
 76     if (!success){
 77         glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
 78         cout << "fragmentShader COMPILE FAILED" << endl;
 79     }
 80 
 81     //創建一個着色器程序對象:多個着色器最后鏈接的版本
 82     GLuint shaderProgram;
 83     shaderProgram = glCreateProgram();
 84     glAttachShader(shaderProgram, vertextShader);
 85     glAttachShader(shaderProgram, fragmentShader);
 86     glLinkProgram(shaderProgram);
 87 
 88     glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
 89 
 90     if (!success){
 91         glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
 92     }
 93     glDeleteShader(vertextShader);
 94     glDeleteShader(fragmentShader);
 95 
 96     //創建定點數據
 97     GLfloat vertices[] = {
 98         -0.5f, -0.5f, 0.0f,
 99         0.5f, -0.5f, 0.0f,
100         0.0f, 0.5f, 0.0f
101     };
102     //創建 VBO 頂點緩沖數據,並把數據賦值到內存中
103     GLuint VBO;
104     glGenBuffers(1, &VBO);
105     //VAO頂點數組對象
106     GLuint VAO;
107     glGenVertexArrays(1, &VAO);
108 
109     //綁定VAO
110     glBindVertexArray(VAO);
111 
112     //復制頂點數據到緩沖中提供給OpenGL使用
113     glBindBuffer(GL_ARRAY_BUFFER, VBO);
114     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
115 
116     //設置頂點屬性指針
117     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid *)0);
118     glEnableVertexAttribArray(0);
119 
120     //解綁VBO
121     glBindBuffer(GL_ARRAY_BUFFER, 0);
122 
123     //解綁VAO
124     glBindVertexArray(0);
125 
126     while (!glfwWindowShouldClose(window)){
127         glfwPollEvents();
128 
129         //釋放顏色緩存
130         glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
131         glClear(GL_COLOR_BUFFER_BIT);
132 
133         //繪制物體
134         //當打算渲染一個物體使用使用着色器程序
135         glUseProgram(shaderProgram);
136         glBindVertexArray(VAO);
137 
138         //繪制函數
139         glDrawArrays(GL_TRIANGLES, 0, 3);
140         glBindVertexArray(0);
141 
142         glfwSwapBuffers(window);
143     }
144 
145     glDeleteVertexArrays(1, &VAO);
146     glDeleteBuffers(1, &VBO);
147 
148     glfwTerminate();
149     return 0;
150 }
151 void key_callback(GLFWwindow* window, int key, int scancode,
152     int action, int mode){
153     if (key == GLFW_KEY_L && action == GLFW_PRESS){
154         glfwSetWindowShouldClose(window, GL_TRUE);
155     }
156 }

首先,在發該貼的時候,這個程序依舊沒有跑起來,因為GLFW、GLEW等庫的原因,鑒於GLUT是上個時代的產物,所以學到后面看到的一些案例都是用的GLEW、GLFW、GLAD等庫,一時半會兒沒有配置成功,但是,這並不能影響我們根據其中的代碼來理解着色器程序(shader)。

下面,我們主要來看一下其中的着色器代碼部分:

一、兩個着色器程序

const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x,position.y,position.z,1.0);\n"
"}\0";

const GLchar* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(1.0f,0.5f,0.2f,1.0f);\n"
"}\n\0";

首先第一個是頂點着色器(vertexShader):

頂點着色器用於讀取頂點(坐標)數據,所以這個position參數是從外部數據源讀取的,在main方法中將外部讀取的頂點數據轉化為四維坐標(x,y,z,w),並且賦值給全局變量:gl_Position。

第二個是片元着色器(fragmentShader):

這里注意了,片元着色器隱式地對所有的gl_Position中的坐標點進行着色並且將顏色輸出。所以這個color參數是輸出的,可能你也看到了,輸出的顏色是個vec4,分別代表RGBA,最后一個1.0f表示alpha通道值為1.0f(浮點型)

二、着色器程序的編譯

//定點着色器
    GLuint vertextShader;
    vertextShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertextShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertextShader);

    //用於判斷一個着色器是否編譯成功
    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vertextShader, GL_COMPILE_STATUS, &success);
    if (!success){
        glGetShaderInfoLog(vertextShader, 512, NULL, infoLog);
        cout << "vertextShader COMPILE FAILED" << endl;
    }

    //片元着色器
    GLuint fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    //用於判斷一個着色器是否編譯成功
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success){
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        cout << "fragmentShader COMPILE FAILED" << endl;
    }

這一塊也不難理解:

1st,定義一個着色器(頂點着色器或者片元着色器);

2nd,為這個着色器對象加載着色器程序片段;

3rd,編譯這個着色器;

當然,案例程序還加了一段編譯成功與否的判斷,這是有必要的,方便調試。

三、多個着色器連接

//創建一個着色器程序對象:多個着色器最后鏈接的版本
    GLuint shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertextShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);

    if (!success){
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
    }
    glDeleteShader(vertextShader);
    glDeleteShader(fragmentShader);

這塊也不難理解,新建一個shaderProgram,並且通過glAttachShader() API將之前的兩個着色器進行連接,這樣頂點着色器輸出的四維坐標就能供片元着色器使用了。

兩個着色器進行連接之后,對之前的着色器進行刪除。

四、將外部頂點數據進行綁定(用戶自定義數據)

//創建定點數據
    GLfloat vertices[] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f, 0.5f, 0.0f
    };
    //創建 VBO 頂點緩沖數據,並把數據賦值到內存中
    GLuint VBO;
    glGenBuffers(1, &VBO);
    //VAO頂點數組對象
    GLuint VAO;
    glGenVertexArrays(1, &VAO);

    //綁定VAO
    glBindVertexArray(VAO);

    //復制頂點數據到緩沖中提供給OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //設置頂點屬性指針
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid *)0);
    glEnableVertexAttribArray(0);

    //解綁VBO
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    //解綁VAO
    glBindVertexArray(0);

不難看出,用戶自定義頂點數據為三個頂點(-0.5,-0.5,0)(0.5,-0.5,0)和(0,0.5,0);

新建VAO、VBO對象並將其放到內存中;

將用戶自定義數據賦值到VBO中;

后面的VAO相關操作沒有看懂,這一塊不是直接用VBO(頂點緩存對象)么,並沒有用到VAO啊???

glVertexAttribPointer()我的理解就是為這些頂點(坐標)設置相應的指針好讓程序知道如何操作。

五、渲染

//釋放顏色緩存
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        //繪制物體
        //當打算渲染一個物體使用使用着色器程序
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);

        //繪制函數
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glBindVertexArray(0);

        glfwSwapBuffers(window);

首先,清空屏幕;

然后調用之前的shaderProgram,並為其綁定數據(??不是已經綁定數據了么)

 


免責聲明!

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



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