0评论
OpenGL缓冲区对象之EBO详解
文章来自https://blog.csdn.net/csxiaoshui/article/details/53174510
2019-03-11
33浏览
想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏开发行业精英群711501594
在《OpenGL渲染管线、VAO/VBO/EBO》中简单介绍了EBO,这篇对于EBO的介绍内容要多很多。EBO(Element Buffer Object,也叫IBO:Index Buffer Object)索引缓冲区对象,这个缓冲区主要用来存储顶点的索引信息。
考虑这样一种情况,我们以绘制一个立方体为例:

在指定顶点坐标的时候,可以使用以下的一个数组:
GLfloat vertices[] = { //前 -1,-1,1, //v4 1, -1, 1 //v5 1, 1, 1 //v6 -1, 1, 1 //v7 //左 -1,1,-1 //v0 -1,-1,1 //v4 -1,1,1 //v7 -1,1,-1 //v3 ...... };
可以看到事实上整个立方体只有8个顶点,我们存储顶点坐标的数组里出现了大量重复的顶点。最好的方式应该是每个顶点只需要存储一次,当我们需要这些顶点时,只需要调用顶点的索引来引用的需要的顶点数据

EBO就是用来存储这些索引数据的地方。
使用
1.创建EBO
创建EBO的方式与创建VBO类似,都是使用glGenBuffers
void glGenBuffers( GLsizei n, GLuint * buffers); //n :创建缓冲区数量 //buffers:存放这些ID的数组或者变量指针
GLuint eboID; glGenBuffers(1, &eboID);
2.传入数据
在创建完成EBO之后,需要向EBO中传入索引数据,在传入之前需要绑定将EBO(将eboID设置为当前操作的EBO)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); //绑定EBO glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); //传入索引数据到EBO中
3.绘制几何体
当设置完成之后,可以调用glDrawElements来绘制(如果不使用索引的方式,绘制需要调用的函数是glDrawArrays)
void glDrawElements( GLenum mode, //绘制模式,可以是GL_TRIANGLES、GL_POINTS等 GLsizei count, //绘制顶点的次数 GLenum type, //索引数据的类型 const GLvoid * indices //EBO中的偏移量(如果不使用EBO,那么indices指向的是索引数组的指针) );
示例程序
示例程序中使用EBO的方式绘制一个四边形
#pragma comment(lib, "glew32.lib") #pragma comment(lib, "freeglut.lib") #include <stdio.h> #include <gl/glew.h> #include <gl/glut.h> GLuint eboID; #define USE_EBO GLfloat 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 // 左上角 }; GLuint indices[] = { // 起始于0! 0, 1, 3, // 第一个三角形 1, 2, 3 // 第二个三角形 }; void ChangeSize(int w, int h) { if (h == 0) h = 1; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, w*1.0 / h, 0.01, 1000.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void SetupRC() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glGenBuffers(1, &eboID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } void RenderScene(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0, 0.0, 0.0); glLoadIdentity(); glTranslatef(0, 0, -5.0); //开启VA状态 glEnableClientState(GL_VERTEX_ARRAY); //绑定数据 glVertexPointer(3, GL_FLOAT, 0, vertices); //绘制 #ifdef USE_EBO glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboID); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); #else glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, indices); #endif //关闭VA状态 glDisableClientState(GL_VERTEX_ARRAY); glutSwapBuffers(); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(800, 600); glutCreateWindow("OpenGL"); glutReshapeFunc(ChangeSize); glutDisplayFunc(RenderScene); GLenum err = glewInit(); if (GLEW_OK != err) { fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err)); return 1; } SetupRC(); glutMainLoop(); return 0; }
为了简单,没有使用core profile的方式来使用EBO,代码中如果定义USE_EBO,glDrawElements最后一个参数是EBO中的偏移量,否则就是索引数组的指针。
腾讯游戏学院公众号
