• openGL之着色器程序的使用


      1 #define GLEW_STATIC
      2 #include <GLglew.h>
      3 #include <GLFWglfw3.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
    "
     15 "layout (location = 0) in vec3 position;
    "
     16 "void main()
    "
     17 "{
    "
     18 "gl_Position = vec4(position.x,position.y,position.z,1.0);
    "
     19 "}";
     20 
     21 const GLchar* fragmentShaderSource = "#version 330 core
    "
     22 "out vec4 color;
    "
     23 "void main()
    "
     24 "{
    "
     25 "color = vec4(1.0f,0.5f,0.2f,1.0f);
    "
     26 "}
    ";
     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
    "
    "layout (location = 0) in vec3 position;
    "
    "void main()
    "
    "{
    "
    "gl_Position = vec4(position.x,position.y,position.z,1.0);
    "
    "}";
    
    const GLchar* fragmentShaderSource = "#version 330 core
    "
    "out vec4 color;
    "
    "void main()
    "
    "{
    "
    "color = vec4(1.0f,0.5f,0.2f,1.0f);
    "
    "}
    ";

    首先第一个是顶点着色器(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,并为其绑定数据(??不是已经绑定数据了么)

  • 相关阅读:
    Java之hashCode的作用和equals方法的重构规则
    Java-IO流之File操作和Properties操作
    Java-IO流之转换流的使用和编码与解码原理
    Java-IO 字节流的使用和效率比较
    Java-IO流之BufferedReader 和BufferedWriter的使用和原理
    二分查找
    leetcode530 二叉搜索树的最小绝对差
    leetcode94 二叉树的中序遍历
    leetcode17电话号码字母组合
    leetcode26 删除排序数组中的重复项
  • 原文地址:https://www.cnblogs.com/eco-just/p/10661035.html
Copyright © 2020-2023  润新知