• OpenGL中的Shader


    http://blog.csdn.net/huangcanjun187/article/details/52474365

    学习总结自:http://learnopengl.com/#!Getting-started/Hello-Triangle 
    http://learnopengl.com/#!Getting-started/Shaders 
    继上篇文章中提到,OpenGL是为了在GPU上同时跑成千上万个程序,在GPU上跑的这些小程序,称为Shader。

    准备

    我们在运行GPU程序前,得准备几样东西:1)输入数据。2)数据缓冲区。3)Shader程序。4)GLSL(OpenGL Shade Language)主程序。 
    以画一个三角形为例, 
    1)输入数据包括:a. 三点顶点的坐标。b. 三个顶点的颜色。

      GLfloat vertices[] = {
            // 坐标        // 颜色
             0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  // 右下角
            -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  // 左下角
             0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f   // 顶点 
        };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2)数据缓存区包括:a. 数据怎么识别。哪一块是坐标数据?哪一块是颜色数据? b. 哪一块数据是第一个三角形的数据?哪一块数据是第二个三角形的数据?

     GLuint VBO, VAO;
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        glBindVertexArray(VAO);// 首先绑定VAO结构。一个VAO对应一个形状对象,包含了一个形状的所有属性,包括颜色、坐标等等。用shader程序调用VAO这个结构,可以画出对应的图像来。
    
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//在绑定VAO之后,绑定VBO结构。**这样VBO就属于之前被绑定VAO的一部分。**里面包含了预先定义好的数组vertices,vertices就是一个浮点数组,包含具体的坐标、颜色值。
    
    
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
        glEnableVertexAttribArray(0);// 坐标属性。让Vertex Shader将这部分数据作为坐标导入。
    
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
        glEnableVertexAttribArray(1);// 颜色属性。让Vertex Shader将这部分数据作为坐标颜色值导入。
    
        glBindVertexArray(0); // Unbind VAO
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3)Shader 程序。将导入GPU的数据,为对应的坐标点画上对应的颜色。

    // Shaders
    const GLchar* vertexShaderSource = "#version 330 core
    "
        "layout (location = 0) in vec3 position;
    "//location = 0,与之前绑定VAO步骤中的函数glEnableVertexAttribArray(0)对应,把坐标数据导入到 vec3 position 这个shader中的坐标变量。
        "layout (location = 1) in vec3 color;
    "//location = 1,与之前绑定VAO步骤中的函数glEnableVertexAttribArray(1)对应,把坐标数据导入到 vec3 color这个shader中的颜色变量。
        "out vec3 ourColor;
    "
        "void main()
    "
        "{
    "
        "gl_Position = vec4(position, 1.0);
    "
        "ourColor = color;
    "//将颜色值直接赋值给输出的变量ourColor,在Fragment Shader中也有一个同名的变量,所有最终像素的颜色就是此颜色值。
        "}";
    const GLchar* fragmentShaderSource = "#version 330 core
    "
        "in vec3 ourColor;
    " //OpenGL Shader程序会直接将同名的变量联系到一起,这个ourColor就是vertex shader中的输出的ourColor
        "out vec4 color;
    "
        "void main()
    "
        "{
    "
        "color = vec4(ourColor, 1.0f);
    "
        "}
    ";
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4)GLSL 主程序

     GLuint shaderProgram = glCreateProgram(); //创建一个GLSL主程序
        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram, fragmentShader);//将两个shader挂载到主程序上
        glLinkProgram(shaderProgram);//链接shader程序。编译shader的步骤在此之前。接下来会详细介绍
    • 1
    • 2
    • 3
    • 4
    • 1
    • 2
    • 3
    • 4

    步骤

    为何要将1)输入数据。2)数据缓冲区。3)Shader程序。4)GLSL(OpenGL Shade Language)主程序。这个几个模块分开介绍呢? 
    因为这几块相互独立,这是OpenGL比较明显的特点。详细说,就是GLSL主程序可以链接任意一个编译好的shader程序,编译好的shader程序可以装载不同的VAO(Vertext Array Object,它是VBO的老大,Shader 调用的时候是直接调VAO,VBO包含了数据,VAO包含了VBO以及如何让Shader识别这些VBO数据的一些属性),VAO又可以用不同的方式装载不同的数据。 
    以这段代码为例,只粘贴了比较关键的代码,完整源码请参考: 
    http://learnopengl.com/code_viewer.php?code=getting-started/shaders-interpolated 
    程序的结果就是对三角形的三个顶点画上红、绿、蓝三种颜色,三角形中间区域的颜色OpenGL会自动插值出来,这是OpenGL的神奇之处(我也还没懂原理)。 
    这里写图片描述

    //--------------这不是完整源码,着重介绍重要的几个步骤------------------//
    
    //---------编写shader 程序----------//
    const GLchar* vertexShaderSource = "#version 330 core
    "
        "layout (location = 0) in vec3 position;
    "
        "layout (location = 1) in vec3 color;
    "
        "out vec3 ourColor;
    "
        "void main()
    "
        "{
    "
        "gl_Position = vec4(position, 1.0);
    "
        "ourColor = color;
    "
        "}"; 
    const GLchar* fragmentShaderSource = "#version 330 core
    "
        "in vec3 ourColor;
    "
        "out vec4 color;
    "
        "void main()
    "
        "{
    "
        "color = vec4(ourColor, 1.0f);
    "
        "}
    ";//简单易懂的Shader源码
    
    //---------编译和链接shader程序----------//
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        glCompileShader(vertexShader); //因为shader程序是在GPU上跑,所以不是和CPP文件一起编译。Shader程序如果有BUG,在编译CPP的时候不会出错,而是在运行CPP工程的时候报错。
    
     GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
        glCompileShader(fragmentShader);
    
     GLuint shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram, fragmentShader);
        glLinkProgram(shaderProgram); //将shader程序与GLSL主程序链接到一起
    
    //---------编写VAO,VBO以及具体导入的数据----------//
     GLfloat vertices[] = {
            // Positions         // Colors
             0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  // Bottom Right
            -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  // Bottom Left
             0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f   // Top 
        };//三个顶点的坐标和颜色值
    
        GLuint VBO, VAO;
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);//可以生成多个VAO和多个VBO。一个只能对应一个VBO。画多个图形,就得用不同的VAO包含不同的VBO
        glBindVertexArray(VAO);//绑定VAO之后,接下来的所有操作都被记录到此VAO当中,直到这个VAO被解除绑定为止。VAO就是画一个图形所需要的所有属性。绑定完这个VAO之后,可以接着绑定其它的VAO。
    
        glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定VBO到当前VAO中,注意GL_ARRAY_BUFFER这个类型只能绑定一个VBO
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//绑定数据到VBO对象当中
        // Position attribute
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);//坐标位置在vertices数组中起始点为0,步长为6个FLOAT数据的长度
        glEnableVertexAttribArray(0);//用vertex shader中的Location0来导入数据,Location0就是坐标数据
        // Color attribute
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));//坐标位置在vertices数组中起始点为3,步长为6个FLOAT数据的长度
        glEnableVertexAttribArray(1);//用vertex shader中的Location1来导入数据,Location0就是颜色标数据
    
        glBindVertexArray(0); // 解除绑定VAO,对这个VAO的所有操作到此为止,之前的操作被全部保存
     // 循环画图
        while (!glfwWindowShouldClose(window))
        {
            // 检测是否有键盘触发事件
            glfwPollEvents();
    
            // Render
            // Clear the colorbuffer
            glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//设置背景颜色
            glClear(GL_COLOR_BUFFER_BIT);
    
            // Draw the triangle
            glUseProgram(shaderProgram);//导入一个GLSL主程序
            glBindVertexArray(VAO);//导入其中一个VAO,一个主程序可以链接多个VAO,在画完这个VAO之后,可以接着画另外一个VAO代表的图形。这是OpenGL比较明显的特征
            glDrawArrays(GL_TRIANGLES, 0, 3);//画三角形
            glBindVertexArray(0); //glBindVertexArray()将VAO属性复位,也就是不绑定任意一个VAO
    
            // Swap the screen buffers
            glfwSwapBuffers(window);
        }
  • 相关阅读:
    ## 密码学常识思考
    解决 Oracle10g安装过程中"无法确定主机的IP地址时产生该异常错误"
    去掉ViewState提高网站的性能
    vs2008在vs中编辑生成dll和exe方法
    [Django] 数据库驱动
    Sharepoint2010 BCS 外部列表2000行限制的解决办法
    解决The content of element type "webapp" must match报错
    使用HttpServlet时报错A child container failed during start
    SpringMVC中请求中文乱码问题
    spring cloud gateway 二次开发之 动态路由注意事项
  • 原文地址:https://www.cnblogs.com/jukan/p/6999890.html
Copyright © 2020-2023  润新知