夏天/isummer

Sun of my life !Talk is cheap, Show me the code! 追风赶月莫停留,平芜尽处是春山~

博客园 首页 新随笔 联系 管理

     glDrawArrays直接从顶点缓冲对象(VBO)中读取顶点数据,而glDrawElements使用一个元素缓冲对象(EBO)来指定顶点的索引

 

问题产生原因

  常规的方通过Opengl逐个点,法向量的方式来拼凑绘制模型,在render实时渲染中,会有大量的点用户CPU和GPU之间通信交互,造成绘制的效率地下。

  因此有两种方法来提高效率。

  一种时:glDrawArray :使用连续的一组顶点来定义几何图形。

  另一种时:glDrawElements:使用索引数组来定义几何图形。

 

对比:

  • glDrawArrays:

    • 适用于简单的绘制场景,特别是当顶点数据不需要重用时。
    • 适合绘制简单的几何体,如点、线和三角形。

      

  • glDrawElements:

    • 适用于复杂的场景,特别是当多个图形共享相同的顶点数据时。
    • 适合绘制复杂的模型和场景,能够有效减少内存使用。

 

1. glDrawArray 方法绘制,函数简介

    glDrawArrays 函数是 OpenGL ES 中的一个函数,用于根据指定的顶点数组绘制图形。它会按照给定的模式和顶点数目从当前绑定的缓冲区对象中读取数据,并将这些数据传递给 OpenGL ES 渲染管线进行处理。

函数原型如下:

/*
*描述:用于根据指定的顶点数组绘制图形
*
*参数讲解:
* mode:表示要绘制哪种类型的图元,可以是 GL_POINTS、GL_LINES、GL_LINE_STRIP、GL_TRIANGLES 等等。
* first:表示从哪个位置开始读取顶点数据,通常为0。顶点序号的开始。
* count:表示要使用多少个顶点来绘制图形。//使用顶点的数量
*
*返回值:无
*/
void glDrawArrays(GLenum mode, GLint first, GLsizei count);

 

 应用举例子:

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);  //重新绑定(后面需要使用:该VBO)将顶点缓冲对象绑定到OpenGL的顶点缓冲区(GL_ARRAY_BUFFER)
    //下面是定义:顶点属性,告诉GPU如何使用VBO,这里没有使用VAO。此处,只有位置属性。
glEnableVertexAttribArray(positionLocation); //启用位置属性索引为positionLocation的顶点属性数组 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4, 0); //定义位置属性 glDrawArrays(GL_TRIANGLES, 0, 3); //执行绘制操作。该函数指定了绘制的模式、起始顶点索引和顶点数量。从顶点索引的0开始,绘制3个顶点。 glBindBuffer(GL_ARRAY_BUFFER, 0); //解绑, 放置误操作顶点缓冲对象 }

 

2. glDrawElements函数简介

  函数原型:

/*
*描述:用于根据指定的顶点数组绘制图形
*
*参数讲解:
* mode:指定渲染模式,接受的参数有:GL_TRIANGLES(三角形)、GL_TRIANGLE_STRIP(三角形带)、GL_TRIANGLE_FAN(三角形扇形)等。
* count:表示要从索引缓冲区中读取多少个元素来进行绘制(指定绘制的顶点个数)。
* type:表示索引缓冲区中元素的数据类型,例如GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT或者GL_UNSIGNED_INT。
* indices:表示指向存储在显存中的索引缓冲区对象(IBO)数据起始位置的指针.注意:如果使用EBO,则传递0,表示使用当前绑定的VBO
*
*返回值:无
*/
void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);

  在使用 glDrawElements 函数时,需要先创建并绑定一个索引缓冲区对象(IBO)【和EBO一样,等效使用,将索引数组的数据存储在该缓冲区对象中,然后使用 glVertexAttribPointer 函数指定顶点属性,使用 glEnableVertexAttribArray 函数启用顶点属性,最后调用 glDrawElements 函数进行绘制。这些索引指定了顶点在顶点缓冲对象中的顺序,从而确定了绘制的顺序。通过使用索引,我们可以共享顶点数据,减少存储空间和数据传输量,并允许更复杂的图形绘制

  需要注意的是,在使用 glDrawElements 函数时,索引数组中的值表示的是顶点数组中的索引位置信息,而不是实际的三维顶点值。

    使用glDrawElements相比于glDrawArrays的主要优势在于它允许更高效地绘制具有共享顶点的复杂图形。

 不过,也有说明,可以使用 (元素缓冲对象(EBO))
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 }; //完成VBO的创建-绑定-开辟空间并初始化-解绑,放置误操作。 glGenBuffers(1, &vbo); //需要1个VBO,把vbo写入到显卡进去,供后续操作 glBindBuffer(GL_ARRAY_BUFFER, vbo); //绑定,表示后面操作是对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); //解绑,放置误操作。卡槽重新绑定,防止误操作
  //使用到索引数组-定义了三角面片的组合方式,数组的值是VBO中顶点的索引值index。 unsigned
int indices[] = { 0, 1, 2, // 第一个三角形 }; //完成EBO的创建-绑定-初始化-解绑 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传输到GPU glBindBuffer(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变量 //...
  //重新绑定VBO-定义顶点属性-解绑VBO,放置误操作。 glBindBuffer(GL_ARRAY_BUFFER, vbo);
//将顶点缓冲对象绑定到OpenGL的顶点缓冲区(GL_ARRAY_BUFFER) //此处需要给定顶点属性,告诉GPU如何使用vbo中的位置属性
glEnableVertexAttribArray(positionLocation); //启用位置属性索引为positionLocation的顶点属性数组 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float)*4, 0); //定义位置属性 glBindBuffer(GL_ARRAY_BUFFER, 0); //解绑顶点缓冲对象
//重新绑定EBO(或者IBO), 直接绘制,解绑EBO,防止误操作 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glDrawElements(GL_TRIANGLES,
3, GL_UNSIGNED_INT, nullptr);//默认操作的是当前绑定的EBO数组,或者0 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); }

 

endl;

posted on 2025-07-10 18:54  夏天/isummer  阅读(348)  评论(0)    收藏  举报