总要有人来改变世界的,为什么不能是你呢

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,并为其绑定数据(??不是已经绑定数据了么)

 

posted @ 2019-04-06 10:39  桔子桑  阅读(1376)  评论(0编辑  收藏  举报