惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
Know Your Adversary
Know Your Adversary
S
Schneier on Security
K
Kaspersky official blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google DeepMind News
Google DeepMind News
Project Zero
Project Zero
Recorded Future
Recorded Future
T
The Blog of Author Tim Ferriss
P
Palo Alto Networks Blog
Engineering at Meta
Engineering at Meta
MyScale Blog
MyScale Blog
L
LINUX DO - 热门话题
The Register - Security
The Register - Security
B
Blog
V
Vulnerabilities – Threatpost
M
MIT News - Artificial intelligence
P
Proofpoint News Feed
Cyberwarzone
Cyberwarzone
Latest news
Latest news
Webroot Blog
Webroot Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
L
LINUX DO - 最新话题
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
B
Blog RSS Feed
aimingoo的专栏
aimingoo的专栏
The GitHub Blog
The GitHub Blog
D
Docker
G
Google Developers Blog
T
Threatpost
F
Full Disclosure
Attack and Defense Labs
Attack and Defense Labs
L
Lohrmann on Cybersecurity
Application and Cybersecurity Blog
Application and Cybersecurity Blog
月光博客
月光博客
D
DataBreaches.Net
WordPress大学
WordPress大学
F
Fortinet All Blogs
S
Secure Thoughts
Y
Y Combinator Blog
博客园 - Franky
Scott Helme
Scott Helme
Apple Machine Learning Research
Apple Machine Learning Research
Hacker News: Ask HN
Hacker News: Ask HN
酷 壳 – CoolShell
酷 壳 – CoolShell
Cloudbric
Cloudbric
N
News | PayPal Newsroom

博客园 - 夏天/isummer

vcpkg的安装,配置vs2022, 全局使用,清单使用 wsGLCanvas中的OnPaint和OnSize的调用顺序 Visual Studio 2022中配置Eigen.Natvis文件,实现Debug查看:Eigen库查看矩阵与向量的值 “模型法线到视图法线”的变换矩阵(normal matrix)的计算和作用 python 用control库绘制自动控制原理中的根轨迹: C++ 无法从“const char [ ]”转换为“char *” 根据文件内存字节数,返回文件占用内存大小:单位:T,G,M,K,B 泛洪算法(Flood fill Algorithm):符号洪水填充算法 opengl中的VBO,IBO,VAO,EBO总结: OpenGL着色器Shader小结 VS2022 在编译大型项目出现:c/c++ intellance 操作-优化VS2022,提高Intellance速度 用VS2022创建空桌面程序【Empty】运行wxWidgets应用,报错:MSVCRTD.lib(exe_main.obj) : error LNK2019: 无法解析的外部符号 main VS下使用全局配置的方式使用VCPKG vcpkg 安装过程中install的参数: ApriTags应用 【/MT、/MTd、/MD、/MDd】C++ 出现异常“.... \debug_heap.cpp Line:980 Expression:__acrt_first_block==header"【已解决】 - 夏天/isummer QString的tostdstring问题-提示堆栈内存溢出(2024.12) vsftpd和FileZiler配置:本地登录,支持上传-下载-删除文件和目录-添加文件和目录 PyQt开发-mkvirtualenv虚拟环境 线程池ThreadPool, C++ github 命令git下载失败: Failed to connect to github.com port 443 解决方案,解决CMAKE中下载其他库失败的问题
opengl中的glDrawElements 用法和glDrawArray
夏天/isummer · 2025-07-10 · via 博客园 - 夏天/isummer

     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); //解绑, 放置误操作顶点缓冲对象 }

  函数原型:

/*
*描述:用于根据指定的顶点数组绘制图形
*
*参数讲解:
* 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;