OpenGL中glVertex、显示列表(glCallList)、顶点数组(Vertex array)、VBO及VAO区别

1.glVertex

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

glBegin(GL_TRIANGLES);
glVertex(0, 0);
glVertex(1, 1);
glVertex(2, 2);
glEnd();

2.显示列表(glCallList)

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

 GLuint glassList;
glNewList(glassList, GL_COMPILE);
DrawGlass();
glEndList(); glCallList(glassList); //DrawGlass();

3.顶点数组(Vertex Array)

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

显示列表和顶点数组都是过时的东西了,下面的VBO和VAO才是重点!

#define MEDIUM_STARS   40
M3DVector2f vMediumStars[MEDIUM_STARS];
//在这做点vMediumStars的设置//
glVertexPointer(2, GL_FLOAT, 0, vMediumStars);
glDrawArrays(GL_POINTS, 0, MEDIUM_STARS);

4.VBO(Vertex Buffer Object)顶点缓冲区对象

  VBO,全称为Vertex Buffer Object,与FBO,PBO并称,但它实际上老不少。就某种意义来说,他就是VA(Vertex Array)的升级版。VBO出现的背景是人们发现VA和显示列表还有让人不满足的地方。一般,在OpenGL里,提高顶点绘制的办法:

 (1)显示列表:把常规的glBegin()-glEnd()中的代码放到一个显示列表中(通常在初始化阶段完成),然后每遍渲染都调用这个显示列表。

 (2)VA:使用顶点数组,把顶点以及顶点属性数据作为数组,渲染的时候直接用一个或几个函数调动这些数组里的数据进行绘制,形式上是减少函数调用的次数(告别glVertex),提高绘制效率。

  但是,这两种方法都有缺点。VA是在客户端设置的,所以执行这类函数(glDrawArray或glDrawElement)后,客户端还得把得到的顶点数据向服务端传输一次(所谓的“二次处理”),这样一来就有了不必要的动作了,降低了效率——如果我们写的函数能直接把顶点数据发送给服务端就好了——这正是VBO的特性之一。显示列表的缺点在于它的古板,一旦设定就不容许修改,所以它只适合对一些“固定”的东西的绘制进行包装。(我们无办法直接在硬件层改顶点数据,因为这是脱离了流水线的事物)。而VBO直接把顶点数据交到流水线的第一步,与显示列表的效率还是有差距,但它这样就得到了操作数据的弹性——渲染阶段,我们的VBO绘制函数持续把顶点数据交给流水线,在某一刻我们可以把该帧到达了流水线的顶点数据取回客户端修改(Vertex mapping),再提交回流水线(Vertex unmapping),或者用glBufferData或glBufferSubData重新全部或buffer提交修改了的顶点数据,这是VBO的另一个特性。

VBO结合了VA和显示列表这个说法不太妥当,应该说它结合了两者的一些特性,绘制效率在两者之间,且拥有良好的数据更改弹性。这种折衷造就了它一直为目前最高的地位。

//创建VBO及VBO赋值
glGenBuffers(1, &m_nPositionVBO);
glBufferData(GL_ARRAY_BUFFER,
sizeof(posData), posData, GL_STREAM_DRAW); glGenBuffers(1, &m_nTexcoordVBO);
glBufferData(GL_ARRAY_BUFFER,
sizeof(texData), texData, GL_STREAM_DRAW); glGenBuffers(1, &m_nIndexVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof(indexData), indexData, GL_STATIC_DRAW); //代码一,不使用shader VBO已经创建好了
glBindBuffer(GL_ARRAY_BUFFER, m_nPositionVBO);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, NULL); glBindBuffer(GL_ARRAY_BUFFER, m_nTexcoordVBO);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, NULL); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_nIndexVBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, NULL); //代码二,使用shader
glBindBuffer(GL_ARRAY_BUFFER, m_nPositionVBO);
glEnableVertexAttribArray(VAT_POSITION);
glVertexAttribPointer(VAT_POSITION, 2, GL_INT, GL_FALSE, 0, NULL); glBindBuffer(GL_ARRAY_BUFFER, m_nTexcoordVBO);
glEnableVertexAttribArray(VAT_TEXCOORD);
glVertexAttribPointer(VAT_TEXCOORD, 2, GL_INT, GL_FALSE, 0, NULL); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_nIndexVBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL); glDisableVertexAttribArray(VAT_POSITION);
glDisableVertexAttribArray(VAT_TEXCOORD); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);
glBindBuffer(GL_ARRAY_BUFFER, NULL);

5.VAO(Vertex Array Object)顶点数组对象

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

  VAO的全名是Vertex Array Object,首先,它不是Buffer-Object,所以不用作存储数据;其次,它针对“顶点”而言,也就是说它跟“顶点的绘制”息息相关。(VAO和VA没有任何关系)

  VAO记录的是一次绘制中所需要的信息,这包括“数据在哪里glBindBuffer”、“数据的格式是怎么样的glVertexAttribPointer”、shader-attribute的location的启用glEnableVertexAttribArray。

glGenBuffers(1, &m_nQuadPositionVBO);
glBindBuffer(GL_ARRAY_BUFFER, m_nQuadPositionVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(fQuadPos), fQuadPos, GL_STREAM_DRAW); glGenBuffers(1, &m_nQuadTexcoordVBO);
glBindBuffer(GL_ARRAY_BUFFER, m_nQuadTexcoordVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(fQuadTexcoord), fQuadTexcoord, GL_STREAM_DRAW); glGenBuffers(1, &m_nQuadIndexVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_nQuadIndexVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(nQuadIndex), nQuadIndex, GL_STREAM_DRAW); //VAO 初始化部分
glGenVertexArrays(1, &m_nQuadVAO);
glBindVertexArray(m_nQuadVAO); //开始保存状态
glBindBuffer(GL_ARRAY_BUFFER, m_nQuadPositionVBO);
glEnableVertexAttribArray(VAT_POSITION);
glVertexAttribPointer(VAT_POSITION, 2, GL_INT, GL_FALSE, 0, NULL); glBindBuffer(GL_ARRAY_BUFFER, m_nQuadTexcoordVBO);
glEnableVertexAttribArray(VAT_TEXCOORD);
glVertexAttribPointer(VAT_TEXCOORD, 2, GL_INT, GL_FALSE, 0, NULL); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_nQuadIndexVBO);
//保存结束
glBindVertexArray(NULL); glBindBuffer(GL_ARRAY_BUFFER, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);

  以上就是VAO的使用方法了。VAO可以理解为一个状态容器,记录VBO的状态。

参考:

1.学一学,VBO

2.AB是一家,VAO与VBO

3.OpenGL超级宝典(第4版)

4.OpenGL ES 3.0 编程指南

OpenGL中glVertex、显示列表(glCallList)、顶点数组(Vertex array)、VBO及VAO区别的更多相关文章

  1. 【opengl】OpenGL中三维物体显示在二维屏幕上显示的变换过程

    转自:http://blog.sina.com.cn/s/blog_957b9fdb0100zesv.html 为了说明在三维物体到二维图象之间,需要经过什么样的变换,我们引入了相机(Camera)模 ...

  2. Vue使用v-for显示列表时,数组里的item数据更新,视图中列表不同步更新的解决方法

    由于初始化类型错误导致的不更新,代码是这样的: <!DOCTYPE html> <html lang="en"> <head> <meta ...

  3. DelphiXe 中静态数组TByteArray和动态数组TBytes /array of byte 的区别

    在应用中发现静态数组和动态数组是有区别的: procedure TForm1.Button1Click(Sender: TObject);var  RsltStream: TMemoryStream; ...

  4. php中对象(object)与数组(array)之间的相互转换

    /** * 数组 转 对象 * * @param array $arr 数组 * @return object */ function array_to_object($arr) { if (gett ...

  5. openGL 提升渲染性能 之 顶点数组 VBO IBO VAO

    使用openGL图形库绘制,都需要通过openGL接口向图像显卡提交顶点数据,显卡根据提交的数据绘制出相应的图形. openGL绘制方式有:直接模式,显示列表,顶点数组,顶点索引. 直接模式:最简单, ...

  6. OpenGL中VA,VAO,VBO和EBO的区别

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

  7. [转]OpenGL图形渲染管线、VBO、VAO、EBO概念及用例

    直接给出原文链接吧 1.OpenGL图形渲染管线.VBO.VAO.EBO概念及用例 2.OpenGL中glVertex.显示列表(glCallList).顶点数组(Vertex array).VBO及 ...

  8. OpenGL顶点数组

    概述 作为在立即模式(glBegin()与glEnd()之间)下指定单个顶点数据的替代,你可以保存顶点数据在一组列表中,包括顶点位置.法线.纹理坐标与颜色信息.并且你可以通过索引数组解引用数组元素绘制 ...

  9. NeHe OpenGL教程 第十二课:显示列表

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

随机推荐

  1. lintcode 落单的数(位操作)

    题目1 落单的数 给出2*n + 1 个的数字,除其中一个数字之外其他每个数字均出现两次,找到这个数字. 链接:http://www.lintcode.com/zh-cn/problem/single ...

  2. android5.0联系人 sort_key改成phonebook_label

    项目中用到了联系人根据字母排序,在android4.0手机上是可以的,但是在android4.4以上的手机排序是乱的,一般字母排序都是根据sort_key这个拼音进行排序,而android5.0这个字 ...

  3. 应用程序框架实战二十一:DDD分层架构之仓储(介绍篇)

    前面已经介绍过Entity Framework的工作单元和映射层超类型的封装,从本文开始,将逐步介绍仓储以及对查询的扩展支持. 什么是仓储 仓储表示聚合的集合. 仓储所表现出来的集合外观,仅仅是一种模 ...

  4. Android随笔之——用shell脚本模拟用户按键、触摸操作

    之前写过两篇关于Android中模拟用户操作的博客(其实用一篇是转载的),现在就来讲讲用shell脚本来模拟用户按键操作.本次的目标是用shell脚本打开微信并在其搜索框中搜索相关内容. 本文的模拟功 ...

  5. C#中构造函数的作用

    C#中构造函数的作用 共同点: 都是实例化对象,初始化数据的 默认构造是说所有的类都从祖先object那继承了空参的构造方法,你不写与写空参构造都存在,而有参数的构造一般是自己写的,写就有不写就没有, ...

  6. 关于table的一些记录

    HTML有10个表格相关标签 <caption> 表格的大标题,该标记可以出现在<table> 之间的任意位置.它对于搜索引擎的机器人记录信息十分重要.参数有align.val ...

  7. ASP.NET的session操作方法总结

    在开发ASP.NET程序时,需要对相关数据进行缓存,缓存较多的主要是用户的身份信息,现提供几个对session操作较为常用的方法: 1.添加session,对设置对应的时间: /// <summ ...

  8. WCF局域网内使用代理无法访问解决方法

    问题描述 在大部分事业单位上网都是需要使用代理的,前几天带着一个同事写的程序过来部署,部署以后各个客户端通过WCF相互通讯,那么其中一个地方在本地局域网测试是没有问题的. 后发现一部分是原因是由于代理 ...

  9. 利用Angularjs测试引擎Karma进行自动化单元测试

    Karma是Google用于angularjs框架单元测试的js引擎(javascript test runner ), angular1 和angular2项目源码的单元测试都是基于karma和ja ...

  10. Spring Boot文档阅读

    原因之初 最初习惯百度各种博客教程,然后跟着操作,因为觉得跟着别人走过的路走可以少走很多弯路,省时间.然而,很多博客的内容并不够完整,甚至错误,看多了的博客甚至有千篇一律的感觉.此外,博客毕竟是记载博 ...