• 初识OpenGL (-)EBO元素缓冲对象


    1. EBO元素缓冲对象(Element Buffer Object)

    EBO是一个缓冲区,就像一个顶点缓冲区对象一样,它存储 OpenGL 用来决定要绘制哪些顶点的索引。

    1.1 索引绘制(Indexed Drawing)

    索引缓冲对象(Index Buffer Object,IBO)

    eg. 假设我们不再绘制一个三角形而是绘制一个矩形。我们可以绘制两个三角形来组成一个矩形(OpenGL主要处理三角形)。

    //顶点数据一致,导致浪费
    float vertices[] = {
        // 第一个三角形
        0.5f, 0.5f, 0.0f,   // 右上角
        0.5f, -0.5f, 0.0f,  // 右下角
        -0.5f, 0.5f, 0.0f,  // 左上角
        // 第二个三角形
        0.5f, -0.5f, 0.0f,  // 右下角
        -0.5f, -0.5f, 0.0f, // 左下角
        -0.5f, 0.5f, 0.0f   // 左上角
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ->

    float vertices[] = {
        // 注意索引从0开始! 
        0.5f, 0.5f, 0.0f,   // 右上角
        0.5f, -0.5f, 0.0f,  // 右下角
        -0.5f, -0.5f, 0.0f, // 左下角
        -0.5f, 0.5f, 0.0f   // 左上角
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    step1. 创建元素缓冲对象:

    unsigned int EBO;
    glGenBuffers(1, &EBO);
    
    • 1
    • 2

    step2. 绑定EBO,用glBufferData把索引复制到缓冲里。同样,和VBO类似,我们会把这些函数调用放在绑定和解绑函数调用之间,缓冲的类型为GL_ELEMENT_ARRAY_BUFFER。

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    注意:我们传递了GL_ELEMENT_ARRAY_BUFFER当作缓冲目标。
    
    • 1
    • 2
    • 3

    step3. 用glDrawElements来替换glDrawArrays函数,表示我们要从索引缓冲区渲染三角形。

    使用当前绑定的索引缓冲对象中的索引进行绘制:

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    
    • 1
    • 2

    参数一: 指定绘制模式
    参数二: 绘制顶点的个数,这里填6,也就是说我们一共需要绘制6个顶点。
    参数三: 索引的类型,这里是GL_UNSIGNED_INT。
    参数四: 指定EBO中的偏移量(或者传递一个索引数组,当不在使用索引缓冲对象的时候),但是我们会在这里填写0。

    glDrawElements函数从当前绑定到GL_ELEMENT_ARRAY_BUFFER目标的EBO中获取其索引。这意味着我们每次想要使用索引渲染对象时都必须绑定相应的EBO,这又有点麻烦。碰巧顶点数组对象也跟踪元素缓冲区对象绑定。在绑定VAO时,绑定的最后一个元素缓冲区对象存储为VAO的元素缓冲区对象。然后,绑定到VAO也会自动绑定该EBO。

    当目标是GL_ELEMENT_ARRAY_BUFFER的时候,VAO会储存glBindBuffer的函数调用。这也意味着它也会储存解绑调用,所以确保没有在解绑VAO之前解绑索引数组缓冲,否则它就没有这个EBO配置了。

    step5. 代码

    // ..:: 初始化代码 :: ..
    // 1. 绑定顶点数组对象
    glBindVertexArray(VAO);
    // 2. 把我们的顶点数组复制到一个顶点缓冲中,供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 3. 复制我们的索引数组到一个索引缓冲中,供OpenGL使用
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    // 4. 设定顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    [...]
    
    // ..:: 绘制代码(渲染循环中) :: ..
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
    运行程序会获得下面这样的图片的结果。左侧图片看应该起来很熟悉,而右侧的则是使用线框模式(Wireframe Mode)绘制的。
    线框矩形可以显示出矩形的确是由两个三角形组成的。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    线框模式(Wireframe Mode)

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)函数配置OpenGL如何绘制图元。
    参数一: 表示打算将其应用到所有的三角形的正面和背面
    参数二:用线来绘制。

    之后的绘制调用会一直以线框模式绘制三角形,直到我们用glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)将其设置回默认模式。

  • 相关阅读:
    自动保存恢复tmux会话 关机重启再也不怕
    【commons-lang3专题】004- NumberUtils 专题
    Unity 之 发布字节抖音小游戏
    Matlab之查询子字符串在字符串中的起始位置函数strfind
    【小嘟陪你刷题06】合并两个有序链表、链表分割、删除链表重复节点、链表的回文结构
    862. 和至少为 K 的最短子数组(难度:困难)
    Vue 项目前端响应式布局及框架搭建
    java计算机毕业设计课堂考勤系统源码+mysql数据库+系统+lw文档+部署
    业务架构·应用架构·数据架构实战~TOGAF理论全景解读
    自动控制原理 - 2 控制系统的数学模型 节2.4-2.6
  • 原文地址:https://blog.csdn.net/thefist11cc/article/details/126684158