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

Posted thefist11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初识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   // 左上角
;

->

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   // 左上角
;

step1. 创建元素缓冲对象:

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

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当作缓冲目标。

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

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

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

参数一: 指定绘制模式
参数二: 绘制顶点的个数,这里填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)绘制的。
线框矩形可以显示出矩形的确是由两个三角形组成的。

线框模式(Wireframe Mode)

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

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

以上是关于初识OpenGL (-)EBO元素缓冲对象的主要内容,如果未能解决你的问题,请参考以下文章

我的OpenGL学习进阶之旅介绍顶点缓冲区对象VBO和元素数组缓冲区对象EBO,并对比使用VBO和不使用VBO绘制三角形的效果

无法使用 VAO 和 EBO (openGL) 绘制多个对象

我的OpenGL学习进阶之旅介绍一下 映射缓冲区对象和复制缓冲区对象

VAO VBO EBO

我的OpenGL学习进阶之旅介绍 顶点数组对象VAO并实战一下

OpenGL Two (Triangle__EBO)