VAO VBO EBO(3)
本篇写一下EBO(element buffer object, 又称index buffer object IBO,索引缓冲对象)。
在明白了VBO,VAO的相关概念之后,EBO理解起来就简单了很多。
假设现在我们需要绘制一个矩形,首先我们想到的是给出四个点,然后让OpenGL处理。但是限制出现了,OpenGL主要处理三角形,这个时候我们就会想着给出两个三角形来组成一个矩形(事实上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 // 左上角 };
上面我们可以看到,有几个点叠加了,本来只要四个点的矩形变成了6个点,也就是增加了50%的开销,这显然不合理(很糟糕)。
更好的解决方案是只储存不同的顶点,并设定绘制这些顶点的顺序。这样子我们只要储存4个顶点就能绘制矩形了,之后只要指定绘制的顺序就行了。于是,EBO应运而生。EBO存储的是顶点位置的索引,它和VBO类似,也是在显存中的一个缓冲对象(都是xBO嘛)。
于是就有了下面这个东东:
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 // 左上角 }; unsigned int indices[] = { // 注意索引从0开始! 0, 1, 3, // 第一个三角形 1, 2, 3 // 第二个三角形 };
接下来是EBO的定义以及用法:
unsigned int eboID; glGenBuffers(1, &eboID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
需要注意的是要用glDrawElements()替换掉之前用VAO&VBO时候的glDrawArrays(),来指明我们从索引缓冲渲染(rendering)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); //第一个参数指定我们绘制的模式 //第二个参数是打算绘制的顶点数目 //第三个参数是索引的数据类型 //第四个参数可以指定EBO的偏移量(offset)
同样,绑定VAO的同时也会绑定EBO。
整个代码就是这样:
// ..:: 初始化代码 :: .. // 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);
PS:在解绑VAO之前先解绑EBO,否则它就没有这个EBO配置了。
给出一些我参考的博客,以及教程
[1] 你好,三角形
原来人类的悲欢并不相通, 我只觉得他们吵闹。