显卡、GPU、显存及OpenGL VBO、VAO、EBO概念及用例 学习

您所在的位置:网站首页 显卡显存只有1mb 显卡、GPU、显存及OpenGL VBO、VAO、EBO概念及用例 学习

显卡、GPU、显存及OpenGL VBO、VAO、EBO概念及用例 学习

2023-11-14 07:17| 来源: 网络整理| 查看: 265

显卡、GPU、显存及OpenGL VBO、VAO、EBO概念及用例 学习 1.0 显卡与GPU与显存简要概述1.1 显卡1.2 GPU1.3 显存 2.0 过时的缓冲对象2.1 最原始顶点设置(glVertex)2.2 显示列表(glCallList)2.3 顶点数组(Vertex Array) 3.0 顶点缓冲对象VBO(Vertex Buffer Object)3.1 VBO简介3.2 VBO的使用 4.0 顶点数组对象VAO(Vertex Array Object)4.1 VAO简介4.2 VAO的使用 5.0 索引缓冲对象EBO(Element Buffer Object)5.1 EBO简介5.2 EBO的使用 6. VBO,VAO使用案例7. EBO使用案例8. 总结 学习参考: https://blog.csdn.net/dcrmg/article/details/53556664 https://www.cnblogs.com/yongfengnice/p/8665426.html https://www.cnblogs.com/BigFeng/p/5117311.html

1.0 显卡与GPU与显存简要概述

在这里插入图片描述 现在的显卡做的比较有科技感,下图是NVIDIA英伟达售价22999的显卡: 在这里插入图片描述

1.1 显卡

显卡(Video card,Graphics card)全称显示接口卡,又称显示适配器,是计算机最基本配置、最重要的配件之一。就像电脑联网需要网卡,主机里的数据要显示在屏幕上就需要显卡。具体来说,显卡接在电脑主板上,它将电脑的数字信号转换成模拟信号让显示器显示出来。原始的显卡一般都是集成在主板上,称作“集成显卡”,只完成最基本的信号输出工作,并不用来处理数据。随着显卡的迅速发展,就出现了GPU的概念,显卡也分为独立显卡和集成显卡。显卡由GPU、显存、电路板,BIOS固件组成。

1.2 GPU

GPU(Graphic Processing Unit)全称图形处理单元,GPU这个概念是由Nvidia公司于1999年提出的。GPU是显卡上的一块芯片,就像CPU是主板上的一块芯片。如果是独立显卡,一般它就焊在显卡的电路板上,位置在显卡的风扇下面。如果是集成显卡,一般GPU就和CPU集成在一起了,这时候它和CPU共用一个风扇和缓存 。 因此GPU实际上就是显卡的核心部件,显卡主要就是靠它来工作的。现在的GPU开发厂家只有2个,一个是AMD(ATI),一个是N’VIDIA英伟达。GPU运算时没有其他CPU那些指令集之类东西干扰,所以专一运算效率更高。GPU本身并不能单独工作,只有配合上附属电路和接口,才能工作。

1.3 显存

显存(Video Memory),也被叫做帧缓存,它的作用是用来存储显卡芯片处理过或者即将提取的渲染数据。如同计算机的内存一样,显存是用来存储要处理的图形信息的部件。如同计算机的内存一样,显存是用来存储要处理的图形信息的部件。在显示屏上看到的画面是由一个个的像素点构成的,而每个像素点都以4至32甚至64位的数据来控制它的亮度和色彩,这些数据必须通过显存来保存,再交由显示芯片和CPU调配,最后把运算结果转化为图形输出到显示器上。

2.0 过时的缓冲对象 2.1 最原始顶点设置(glVertex)

最原始的设置顶点方法,在glBegin和glEnd之间使用。OpenGL3.0已经废弃此方法。每个glVertex与GPU进行一次通信,十分低效

glBegin(GL_TRIANGLES); glVertex(0, 0); glVertex(1, 1); glVertex(2, 2); glEnd(); 2.2 显示列表(glCallList)

每个glVertex调用都与GPU进行一次通信,显示列表是收集好所有的顶点,一次性的发送给GPU。缺点是在绘制之前就要把要传给GPU的顶点准备好,传后就不能修改了。

GLuint glassList; glNewList(glassList, GL_COMPILE); DrawGlass(); glEndList(); glCallList(glassList); //DrawGlass(); 2.3 顶点数组(Vertex Array)

顶点数组也是收集好所有的顶点,一次性发送给GPU。不过数据不是存储于GPU中的,绘制速度上没有显示列表快,优点是可以修改数据。

#define MEDIUM_STARS 40 M3DVector2f vMediumStars[MEDIUM_STARS]; //在这做点vMediumStars的设置 glVertexPointer(2, GL_FLOAT, 0, vMediumStars); glDrawArrays(GL_POINTS, 0, MEDIUM_STARS); 3.0 顶点缓冲对象VBO(Vertex Buffer Object) 3.1 VBO简介

VBO是在显卡存储空间(显存)中开辟出的一块内存缓存区,用于存储顶点的各类属性信息,如顶点坐标,顶点法向量,顶点颜色数据等。在渲染时,可以直接从VBO中取出顶点的各类属性数据,由于VBO在显存而不是在内存中,不需要从CPU传输数据,处理效率更高。它会在显存储存大量顶点。使用VBO的好处是我们可以一次性的发送一大批数据到显卡上,而不是每个顶点发送一次。

可以开辟很多个VBO,每个VBO在OpenGL中有它的唯一标识ID,这个ID对应着具体的VBO的显存地址,通过这个ID可以对特定的VBO内的数据进行存取操作。

3.2 VBO的使用

创建VBO的第一步需要开辟显存空间并分配VBO的ID:

//创建vertex buffer object对象 GLuint vboId; glGenBuffers(1, &vboId);

创建的VBO可用来保存不同类型的顶点数据,创建之后需要通过分配的ID绑定VBO,对于同一类型的顶点数据一次只能绑定一个VBO。绑定操作通过glBindBuffer来实现,第一个参数指定绑定的数据类型,如下:

//GL_ARRAY_BUFFER //GL_ELEMENT_ARRAY_BUFFER //GL_PIXEL_PACK_BUFFER //GL_PIXEL_UNPACK_BUFFER glBindBuffer(GL_ARRAY_BUFFER, vboId);

调用glBufferData把用户定义的数据传输到当前绑定的显存缓冲区中:

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

调用glVertexAttribPointer通知OpenGL如何解释这些顶点数据,这个接口默认是关闭状态,需要使用glEnableVertexAttribArray进行打开:

glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

参数说明:

顶点属性位置,与顶点着色器中layout(location=0)对应。顶点属性大小顶点属性是一个vec4,它由4个值组成,所以大小是4。数据类型,这里是GL_FLOAT(GLSL中vec*都是由浮点数值组成的)。定义是否希望数据被标准化。如果我们设置为GL_TRUE,所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间。我们把它设置为GL_FALSE。步长(Stride),指定在连续的顶点属性之间的间隔。它告诉我们在连续的顶点属性组之间的间隔(多少字节数)。例如知道步长间隔12个字节,可以把步长设置为3 * sizeof(float)。要注意的是由于我们知道这个数组是紧密排列的(在两个顶点属性之间没有空隙)我们也可以设置为0来让OpenGL决定具体步长是多少(只有当数值是紧密排列时才可用)。一旦我们有更多的顶点属性,我们就必须更小心地定义每个顶点属性之间的间隔。表示我们的位置数据在缓冲区起始位置的偏移量。参数的类型是void*。 图解: 在这里插入图片描述 4.0 顶点数组对象VAO(Vertex Array Object) 4.1 VAO简介

VAO是一个保存了所有顶点数据属性的状态结合,它存储了顶点数据的格式以及顶点数据所需的VBO对象的引用。VAO本身并没有存储顶点的相关属性数据,这些信息是存储在VBO中的,VAO相当于是对很多个VBO的引用,把一些VBO组合在一起作为一个对象统一管理。当一个VAO被创建绑定之后,任何随后的顶点属性调用都会储存在这个VAO中。

VBO将顶点信息放到显存中,GPU在渲染时去缓存中取数据,二者中间的桥梁是GL-Context。GL-Context整个程序一般只有一个,所以如果一个渲染流程里有两份不同的绘制代码,GL-context就负责在他们之间进行切换。这也是为什么要在渲染过程中,在每份绘制代码之中会有glBindbuffer、glEnableVertexAttribArray、glVertexAttribPointer。那么优化的方法来了,把这些都放到初始化时候完成吧!VAO记录该次绘制所需要的所有VBO所需信息,把它保存到VBO特定位置,绘制的时候直接在这个位置取信息绘制。

VAO缓存glVertexAttribPointer()函数的结果。这样的好处就是,当配置顶点属性指针时,你只需要将那些调用执行一次,之后再绘制物体的时候只需要绑定相应的VAO就行了。

VAO记录的是一次绘制中所需要的信息,这包括:

glBindBuffer:数据位置glVertexAttribPointer:OpenGL怎样解释数据格式glEnableVertexAttribArray:shader-attribute的location的启用 在这里插入图片描述 4.2 VAO的使用

生成一个VAO对象并绑定:

GLuint vaoId; glGenVertexArrays(1, &vaoId);// 创建 glBindVertexArray(vaoId);// 绑定激活

OpenGL中所有的图形都是通过分解成三角形的方式进行绘制,glDrawArrays函数负责把模型绘制出来,它使用当前激活的着色器,当前VAO对象中的VBO顶点数据和属性配置来绘制出来基本图形。

glDrawArrays (GLenum mode, GLint first, GLsizei count);

参数说明:

第一个参数 GL_TRIANGLES:每三个顶之间绘制三角形,之间不连接GL_TRIANGLE_FAN:以V0V1V2,V0V2V3,V0V3V4,……的形式绘制三角形GL_TRIANGLE_STRIP:顺序在每三个顶点之间均绘制三角形。这个方法可以保证从相同的方向上所有三角形均被绘制。以V0V1V2,V1V2V3,V2V3V4……的形式绘制三角形 第二个参数 定义从缓存中的哪一位开始绘制,一般定义为0第三个参数 定义绘制的顶点数量 5.0 索引缓冲对象EBO(Element Buffer Object) 5.1 EBO简介

EBO也是一个缓冲,它专门储存索引,索引的意义在于减少重复数据,OpenGL调用这些顶点的索引来决定该绘制哪个顶点。EBO也不是必须的,如果使用EBO,绘制过程将更清晰简单,EBO需配合VBO使用,索引必须指定索引的对象。

使用EBO绘图是使用GLDrawElements()函数,这个函数是要通过索引到相应的顶点缓冲区内去拿数据,如果绑定了VAO就到VAO里拿数据。那EBO要不要每次绘制的时候都重新绑定,这个就要看顶点数据部分如何处理的了。如果你没有使用VAO,那么就要每次都重新绑定相应的EBO,然后先读取索引,再根据索引去到绑定的VBO里寻找数据。如果已经绑定了VAO,要注意一点:VAO绑定时正在绑定的索引缓冲对象会被保存为VAO的元素缓冲对象,绑定VAO的同时也会自动绑定EBO。看下面这张图,索引缓冲对象会成为VAO的一个元素。 在这里插入图片描述

5.2 EBO的使用

创建EBO并绑定,用glBufferData(以GL_ELEMENT_ARRAY_BUFFER为参数)把索引存储到EBO中:

GLuint ebo; glGenBuffers(1, &ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

当用EBO绑定顶点索引的方式绘制模型时,需要使用glDrawElements而不是glDrawArrays:

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

参数说明:

绘制模式指定要绘制的顶点个数索引的数据类型可选的EBO中偏移量设定 6. VBO,VAO使用案例 //使用VAO VBO绘制矩形 #include #include void userInit(); //自定义初始化 void reshape(int w, int h); //重绘 void display(void); void keyboardAction(unsigned char key, int x, int y); //键盘退出事件 GLuint vboId;//vertex buffer object句柄 GLuint vaoId;//vertext array object句柄 GLuint programId;//shader program 句柄 int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutInitWindowPosition(100, 100); glutInitWindowSize(512, 512); glutCreateWindow("Rectangle demo"); //使用glew,需要执行glewInit,不然运行过程会报错 //glewInit要放在glut完成了基本的初始化之后执行 glewInit(); //自定义初始化,生成VAO,VBO对象 userInit(); //重绘函数 glutReshapeFunc(reshape); glutDisplayFunc(display); //注册键盘按键退出事件 glutKeyboardFunc(keyboardAction); glutMainLoop(); return 0; } //自定义初始化函数 void userInit() { glClearColor(0.0, 0.0, 0.0, 0.0); //创建顶点数据 const GLfloat vertices[] = { -0.5f,-0.5f,0.0f,1.0f, 0.5f,-0.5f,0.0f,1.0f, 0.5f,0.5f,0.0f,1.0f, -0.5f,0.5f,0.0f,1.0f, }; //创建VAO对象 glGenVertexArrays(1, &vaoId); glBindVertexArray(vaoId); //创建VBO对象 glGenBuffers(1, &vboId); glBindBuffer(GL_ARRAY_BUFFER, vboId); //传入VBO数据 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //解除VBO绑定 glBindBuffer(GL_ARRAY_BUFFER, 0); } //调整窗口大小回调函数 void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); } //绘制回调函数 void display(void) { glClear(GL_COLOR_BUFFER_BIT); //绑定VBO glBindBuffer(GL_ARRAY_BUFFER, vboId); glEnableVertexAttribArray(0); //解释顶点数据方式 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); //绘制模型 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableVertexAttribArray(0); glutSwapBuffers(); } //键盘按键回调函数 void keyboardAction(unsigned char key, int x, int y) { switch (key) { case 033: // Escape key exit(EXIT_SUCCESS); break; } }

执行效果: 在这里插入图片描述

7. EBO使用案例

使用EBO绘制两个三角形,组成同样的矩形图形:

//使用EBO绘制矩形(两个三角形) #include #include void userInit(); //自定义初始化 void reshape(int w, int h); //重绘 void display(void); void keyboardAction(unsigned char key, int x, int y); //键盘退出事件 GLuint eboId;//element buffer object句柄 GLuint vboId;//vertext buffer object句柄 GLuint vaoId;//vertext array object句柄 int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutInitWindowPosition(100, 100); glutInitWindowSize(512, 512); glutCreateWindow("Rectangle demo"); //使用glew,需要执行glewInit,不然运行过程会报错 //glewInit要放在glut完成了基本的初始化之后执行 glewInit(); //自定义初始化,生成VAO,VBO,EBO userInit(); //重绘函数 glutReshapeFunc(reshape); glutDisplayFunc(display); //注册键盘按键退出事件 glutKeyboardFunc(keyboardAction); glutMainLoop(); return 0; } //自定义初始化函数 void userInit() { glClearColor(0.0, 0.0, 0.0, 0.0); //创建顶点数据 const GLfloat vertices[] = { -0.5f,-0.5f,0.0f,1.0f, 0.5f,-0.5f,0.0f,1.0f, 0.5f,0.5f,0.0f,1.0f, -0.5f,0.5f,0.0f,1.0f, }; // 索引数据 GLshort indices[] = { 0, 1, 3, // 第一个三角形 1, 2, 3 // 第二个三角形 }; //创建VAO对象 glGenVertexArrays(1, &vaoId); glBindVertexArray(vaoId); //创建VBO对象,把顶点数组复制到一个顶点缓冲中,供OpenGL使用 glGenBuffers(1, &vboId); glBindBuffer(GL_ARRAY_BUFFER, vboId); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //创建EBO对象 glGenBuffers(1, &eboId); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId); //传入EBO数据 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); //解释顶点数据方式 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); //解绑VAO glBindVertexArray(0); //解绑EBO glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //解绑VBO glBindBuffer(GL_ARRAY_BUFFER, 0); } //调整窗口大小回调函数 void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); } //绘制回调函数 void display(void) { glClear(GL_COLOR_BUFFER_BIT); //绑定VAO glBindVertexArray(vaoId); //绘制模型 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL); glutSwapBuffers(); } //键盘按键回调函数 void keyboardAction(unsigned char key, int x, int y) { switch (key) { case 033: // Escape key exit(EXIT_SUCCESS); break; } }

效果一样: 在这里插入图片描述

8. 总结

从程序传入的数据都是要放入缓冲对象的,也就是Buffer Object,像VBO和EBO,而VAO则可以看作是把这些数据进行了分类整合,根据缓冲对象里的数据进行自由配置,从而得到自己需要的数据,然后放入一个对象里。比如我从一堆顶点缓冲和索引缓冲里拿出一部分数据组成正方体,然后给它一个VAO的名字,下次用的时候直接取出来就行,我还可以拿出一些数据组成四面体,然后再给它一个名字。这样看来,VBO和EBO里的数据就好像是可以重复使用的原材料,VAO则是使用这些原材料进行加工好了的对象。

VBO:CPU把顶点数据存储到VBO,然后每次调用的时候从VBO集中发送到GPU,能够大大降低cpu到gpu的交互次数。EBO:主要是为了减少VBO中的重复数据,但是它不能减少数据的传输,如果一个正方体有36个顶点,用索引的话就要有36个索引值,但是不同的索引可能索引到同一个顶点。

VAO:VAO则是用来保存顶点数据和配置的,没有VAO的时候,我们需要不停地把配置从CPU传到GPU,以此让GPU来知道怎么取顶点,而有了VAO(VAO是放在显存里的),我们通过绑定的VAO可以很快拿到配置,而不用从CPU程序中传入。

数据传递流程:我们定义了顶点数组以后,需要将数据载入缓存对象也就是VBO中,同时我们必须告诉OpenGL如何配置这些数据,这就需要我们绑定一个VAO,这里面存储着相应的配置,同时VAO也与相应的顶点数组做了间接绑定,所以一般来说;一个顶点数组可以对应着多个VAO,但是一个VAO一般对应一个顶点数组。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3