最原始的设置顶点方法,在glBegin和glEnd之间使用。OpenGL3.0已经废弃此方法。每一个glVertex与GPU进行一次通讯,十分低效。html
glBegin(GL_TRIANGLES); glVertex(0, 0); glVertex(1, 1); glVertex(2, 2); glEnd();
每一个glVertex调用都与GPU进行一次通讯,显示列表是收集好全部的顶点,一次性的发送给GPU。缺点是在绘制以前就要把要传给GPU的顶点准备好,传后就不能修改了。编程
1 GLuint glassList; 2 glNewList(glassList, GL_COMPILE); 3 DrawGlass(); 4 glEndList(); 5 6 glCallList(glassList); //DrawGlass();
顶点数组也是收集好全部的顶点,一次性发送给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);
VBO,全称为Vertex Buffer Object,与FBO,PBO并称,但它实际上老很多。就某种意义来讲,他就是VA(Vertex Array)的升级版。VBO出现的背景是人们发现VA和显示列表还有让人不知足的地方。通常,在OpenGL里,提升顶点绘制的办法:app
(1)显示列表:把常规的glBegin()-glEnd()中的代码放到一个显示列表中(一般在初始化阶段完成),而后每遍渲染都调用这个显示列表。函数
(2)VA:使用顶点数组,把顶点以及顶点属性数据做为数组,渲染的时候直接用一个或几个函数调动这些数组里的数据进行绘制,形式上是减小函数调用的次数(告别glVertex),提升绘制效率。优化
可是,这两种方法都有缺点。VA是在客户端设置的,因此执行这类函数(glDrawArray或glDrawElement)后,客户端还得把获得的顶点数据向服务端传输一次(所谓的“二次处理”),这样一来就有了没必要要的动做了,下降了效率——若是咱们写的函数能直接把顶点数据发送给服务端就行了——这正是VBO的特性之一。显示列表的缺点在于它的古板,一旦设定就不允许修改,因此它只适合对一些“固定”的东西的绘制进行包装。(咱们无办法直接在硬件层改顶点数据,由于这是脱离了流水线的事物)。而VBO直接把顶点数据交到流水线的第一步,与显示列表的效率仍是有差距,但它这样就获得了操做数据的弹性——渲染阶段,咱们的VBO绘制函数持续把顶点数据交给流水线,在某一刻咱们能够把该帧到达了流水线的顶点数据取回客户端修改(Vertex mapping),再提交回流水线(Vertex unmapping),或者用glBufferData或glBufferSubData从新所有或buffer提交修改了的顶点数据,这是VBO的另外一个特性。ui
VBO结合了VA和显示列表这个说法不太稳当,应该说它结合了二者的一些特性,绘制效率在二者之间,且拥有良好的数据更改弹性。这种折衷造就了它一直为目前最高的地位。spa
//建立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);
VBO将顶点信息放到GPU中,GPU在渲染时去缓存中取数据,两者中间的桥梁是GL-Context。GL-Context整个程序通常只有一个,因此若是一个渲染流程里有两份不一样的绘制代码,GL-context就负责在他们之间进行切换。这也是为何要在渲染过程当中,在每份绘制代码之中会有glBindbuffer、glEnableVertexAttribArray、glVertexAttribPointer。那么优化的方法来了,把这些都放到初始化时候完成吧!VAO记录该次绘制所须要的全部VBO所需信息,把它保存到VBO特定位置,绘制的时候直接在这个位置取信息绘制。code
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
3.OpenGL超级宝典(第4版)
4.OpenGL ES 3.0 编程指南