glDrawArrays直接从顶点缓冲对象(VBO)中读取顶点数据,而glDrawElements使用一个元素缓冲对象(EBO)来指定顶点的索引。那么什么是EBO呢?
1.ElementArrayBufferObject
ElementArrayBufferObject,简称EBO,用来节省内存开销。
在渲染3D场景时,通常需要绘制许多三角形或其他类型的图元,这时候存在顶点数据公用的现象,为了减少数据的重复,可以使用索引数组来定义顶点的顺序,这使得顶点可以在多个图元中共享。ElementArrayBufferObject就是用来存储这些索引数据的。
通常情况下,我们使用一个顶点缓冲对象(VertexBufferObject)存储顶点数据,然后使用一个元素数组缓冲对象(ElementArrayBufferObject)存储顶点的索引。
2.举个例子
(1)使用glDrawArrays
glDrawArrays是WebGL中的一个绘制函数,用于绘制几何图形。它从当前的顶点缓冲对象中读取顶点数据,并按照指定的参数进行绘制。这个函数绘制的图形是由顶点数据直接确定的,没有使用到顶点索引。
void Init()
{float data[] = {-0.2f,-0.2f,-0.6f,1.0f,0.2f,-0.2f,-0.6f,1.0f,-0.2f,0.2f,-0.6f,1.0f};glGenBuffers(1, &vbo); //需要1个VBO,把vbo写入到显卡进去,供后续操作glBindBuffer(GL_ARRAY_BUFFER, vbo); //把vbo设置到卡槽上//glBufferData(GL_ARRAY_BUFFER,sizeof(float)*12, nullptr,GL_STATIC_DRAW);//只在GPU上开辟内存不传数据glBufferData(GL_ARRAY_BUFFER,sizeof(float)*12,data,GL_STATIC_DRAW); //将数据从cpu传到Gpu,此后data数据可删除。glBindBuffer(GL_ARRAY_BUFFER, 0); //卡槽重新绑定,防止误操作//读取shader源码到GPU程序//...//读取shader变量//...
}
void Draw()
{glClearColor(0.0f, 1.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//设置Uniform变量//...glBindBuffer(GL_ARRAY_BUFFER, vbo); //将顶点缓冲对象绑定到OpenGL的顶点缓冲区(GL_ARRAY_BUFFER)glEnableVertexAttribArray(positionLocation); //启用位置属性索引为positionLocation的顶点属性数组glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4, 0); //定义位置属性glDrawArrays(GL_TRIANGLES, 0, 3); //执行绘制操作。该函数指定了绘制的模式、起始顶点索引和顶点数量。glBindBuffer(GL_ARRAY_BUFFER, 0); //解绑顶点缓冲对象
}
(2)使用glDrawElements
使用glDrawElements时,我们需要事先创建一个元素缓冲对象(EBO),并将顶点索引数据存储在其中。这些索引指定了顶点在顶点缓冲对象中的顺序,从而确定了绘制的顺序。通过使用索引,我们可以共享顶点数据,减少存储空间和数据传输量,并允许更复杂的图形绘制。
使用glDrawElements相比于glDrawArrays的主要优势在于它允许更高效地绘制具有共享顶点的复杂图形。
void Init()
{float data[] = {-0.2f,-0.2f,-0.6f,1.0f,0.2f,-0.2f,-0.6f,1.0f,-0.2f,0.2f,-0.6f,1.0f};glGenBuffers(1, &vbo); //需要1个VBO,把vbo写入到显卡进去,供后续操作glBindBuffer(GL_ARRAY_BUFFER, vbo); //把vbo设置到卡槽上//glBufferData(GL_ARRAY_BUFFER,sizeof(float)*12, nullptr,GL_STATIC_DRAW);//只在GPU上开辟内存不传数据glBufferData(GL_ARRAY_BUFFER,sizeof(float)*12,data,GL_STATIC_DRAW); //将数据从cpu传到Gpu,此后data数据可删除。glBindBuffer(GL_ARRAY_BUFFER, 0); //卡槽重新绑定,防止误操作unsigned int indices[] = { 0, 1, 2, // 第一个三角形 };glGenBuffers(1, &ebo); //创建1个EBO,并将标识符存储在ebo变量中glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); //将EBO绑定到GL_ELEMENT_ARRAY_BUFFER目标glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, indices, GL_STATIC_DRAW); //将索引数据从CPU传输到GPUglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //将索引数据从CPU传输到GPU//读取shader源码到GPU程序//...//读取shader变量//...
}
void Draw()
{glClearColor(0.0f, 1.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//设置Uniform变量//...glBindBuffer(GL_ARRAY_BUFFER, vbo); //将顶点缓冲对象绑定到OpenGL的顶点缓冲区(GL_ARRAY_BUFFER)glEnableVertexAttribArray(positionLocation); //启用位置属性索引为positionLocation的顶点属性数组glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4, 0); //定义位置属性glBindBuffer(GL_ARRAY_BUFFER, 0); //解绑顶点缓冲对象glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}