• OpenGL(3)-三角形


    写在前面

    从这节开始,会接触到很多基本概念,原书我也是读了很多遍,一遍一遍去理解其中的意思,以及他们之间的关系。

    概念

    顶点数组对象:VAO

    顶点缓冲对象:VBO

    索引缓冲对象:EBO|IBO

    OpenGL是一个3D空间,而屏幕和窗口是2D的,所以OpenGL的大部分工作是将3D坐标转换为2D像素

    转换的过程就是由图形渲染管线管理的。

    图像渲染管线分为两部分:1.把3D坐标转换为2D坐标。2.把2D坐标转变为有颜色的像素

    渲染的几个阶段:

    顶点数据->顶点着色器->图元装配->几何着色器->光栅化->片段着色器->测试与混合

    渲染的每一个阶段都有自己的程序,该程序是使用OpenGL着色器语言进行编写的,这些小程序叫做着色器(shader)

    顶点着色器:把3D坐标转换为另一种3d坐标,同时对顶点属性进行一些基本处理

    图元装配:将所有的点装配成指定的图元形状

    几何着色器:通过产生新的点和新的图元来生成形状

    光栅化:将图元映射为最终屏幕上相应的像素,生成片段着色器使用的片段,并裁切吊超过视图以外的像素

    片段着色器:计算一个像素的最终颜色

    测试与混合:检测片段对应的深度值,用来判断这个像素是其它物体的前面还是后面,决定是否丢弃

    代码创建

    首先,我们声明出来下面需要使用的着色器源码。

    通过上述概念我们知道着色器,是运行在图像渲染管线上的小程序,代码风格类似c语言

     1 // 顶点着色器源码
     2 const char *vertexShaderSource =
     3 "#version 330 core
    "
     4 "layout (location = 0) in vec3 aPos;
    "
     5 "void main(){
    "
     6 "gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);
    "
     7 "}
    ";
     8 
     9 //片段着色器源码
    10 const char *fragmentShaderSource =
    11 "#version 330 core
    "
    12 "out vec4 FragColor;
    "
    13 "void main(){
    "
    14 "FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    "
    15 "}
    ";

    下边我们使用上述两个着色器,构建一个可以渲染的渲染管线

        //创建顶点着色器
        int vertexShader = glCreateShader(GL_VERTEX_SHADER);
        // 第一个参数着色器对象,第二个参数传递的源码字符串,第三个参数顶点着色器的源码
        glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        glCompileShader(vertexShader);
        // 判断编译是否成功
        int sucess;
        char infoLog[512];
        glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &sucess);
        if(!sucess){
            glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
            std::cout<< "ERROR::SHADER::VERTEX::COMPILATION_FAILED
    "<< infoLog << std::endl;
        }
        // 片段着色器,创建并编译
        int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
        glCompileShader(fragmentShader);
        glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, & sucess);
        if(!sucess){
            glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
            std::cout<<"ERROR::SHADER::FRAGMENT::COMPILATION_FAILED
    "<< infoLog<<std::endl;
        }

    两个着色器创建,且编译之后,需要进行连接

    //链接两个着色器对象到用来渲染的着色器程序中
        // 创建着色器程序
        int shaderProgram = glCreateProgram();
        //链接
        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram, fragmentShader);
        glLinkProgram(shaderProgram);
        glGetShaderiv(shaderProgram, GL_COMPILE_STATUS, & sucess);
        if(!sucess){
            glGetShaderInfoLog(shaderProgram, 512, NULL, infoLog);
            std::cout<<"ERROR::SHADER::PROGRAM::COMPILATION_FAILED
    "<< infoLog<<std::endl;
        }

    链接两个着色器到我们刚创建的着色器程序中,且进行了编译,这个时候,我们上面的两个着色器,已经在shaderProgram中了。

    1 //删除无用的顶点着色器以及片段着色器 
    2 glDeleteShader(vertexShader);
    3  glDeleteShader(fragmentShader);

    我们知道,渲染的几个阶段,那么现在我们只需要创建顶点数据,然后使用上述着色器程序进行渲染

    1     // 定义三个顶点
    2     float vertices[] = {
    3         -0.5f, -0.5f, 0.0f,
    4         0.5f, -0.5f, 0.0f,
    5         0.0f,  0.5f, 0.0f
    6     };

    对于顶点的管理,我们使用顶点缓冲对象以及顶点数组对象进行管理。文章开头已经讲解了基本的概念

    // 使用顶点缓冲对象进行缓存
        unsigned int VBO, VAO;
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        // 缓冲对象进行绑定
        glBindVertexArray(VAO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);

    缓冲对象的使用

     1     // 将定义的顶点数据复制到缓冲内存中
     2     // 第一个参数,缓冲类型,第二个参数数据大小,第三个参数发送的数据,第四个参数,显卡如何管理给定的数据
     3     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
     4     
     5     // 解析顶点数据
     6     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
     7     // 启动顶点数据
     8     glEnableVertexAttribArray(0);
     9     
    10     glBindBuffer(GL_ARRAY_BUFFER, 0);
    11     glBindVertexArray(0);
    12     
    13     glDrawArrays(GL_TRIANGLES,0,3);

    现在我们的顶点数组对象已经在内存中了

    下面就是调用着色器程序进行启动

    1         //启用三角形
    2         glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    3         glClear(GL_COLOR_BUFFER_BIT);
    4         // 激活程序
    5         glUseProgram(shaderProgram);
    6         glBindVertexArray(VAO);
    7         glDrawArrays(GL_TRIANGLES, 0, 3);
    8         glfwSwapBuffers(window);

    最后,不要忘了清楚我们使用的vao以及vbo对象

    //清除对象
        glDeleteVertexArrays(1, &VAO);
        glDeleteBuffers(1, &VBO);

    总结

    通过上述的流程,应该是可以跑起来一个三角形的。OpenGL之路漫漫长,我们继续加油

  • 相关阅读:
    知乎 : 有什么你认为很简单的问题实际的证明却很复杂?
    民科吧 的 一题 : ∂ f / ∂ x =
    知乎: Lurie 的 derived algebraic geometry 有多重要?
    说说 网友 专业证伪 的 那道 几何题
    在 《数学问题,连接两个点的曲线旋转所成曲面中,面积最小的曲线是什么?》 里 的 讨论
    证明 夹逼定理 和 洛必达法则
    一道数学题 : 数列 { bn } 收敛, 证明 { an } 也收敛
    一道数学题 : f ( 2^x ) + f ( 3^x ) = x , 求 f ( x )
    网友 lzmsunny96 的 一个 分数 分解题
    我 搞了一个 尺规作图 不能 实现 三等分角 的 证明
  • 原文地址:https://www.cnblogs.com/Jack7/p/9515930.html
Copyright © 2020-2023  润新知