转载
http://blog.csdn.net/dreamcs/article/details/7702701
创建VBO
GL_ARB_vertex_buffer_object 扩展可以提升OpenGL的性能。它提供了顶点数组和显示列表,这避免了低效实现这些功能。Vertex buffer object (VBO) 允许顶点数据储存在高性能显卡上,即服务端的内存中,改善数据传输效率。如果缓冲区对象保存了像素数据,它就被称做Pixel Buffer Object (PBO)。
使用顶点数据可以减少函数调用次数及复用共享顶点,然而,顶点数组的缺点是顶点函数及顶点数据在客户端(me:对于OpenGL来说,显卡为服务端,其它为客户端),每次引用顶点数组时,都必须将顶点数据从客户端(me:内存)发送到服务端(显卡)。另一方面,显示列表是服务端的函数,它不会再重头传送数据。但是,一旦显示列表被编译了,显示列表中的数据就不能修改了。
Vertex buffer object (VBO) 为顶点创建创建了一个缓冲区对象。缓冲区对象在服务端的高性能内存中,并提供了相同的函数,引用这些数组,如glVertexPointer(), glNormalPointer(), glTexCoordPointer(), 等等.顶点缓冲区内存管理器将缓冲区对象放在储存器中最佳的位置。这依赖了用户输入的模式:"target"模式和"usage"模式。因此,储存管理器可以优化缓冲区,平衡三种内存:system ,AGP, video memory。与显示列表不同的是,在顶点缓冲区对象中的数据可以读也可以将它映射到服务端的内存空间中,然后更新它的数据。
VBO另一个重要的优点是,可以在许多客户端*享缓冲区对象,就像显示列表和纹理那样。由于VBO在服务端,多个客户端可以通过对应的标识符访问同一个缓冲区。
创建VBO
创建VBO的三个步骤:
1.使用glGenBuffersARB()得到一个新的缓冲区对象。
2.Bind the buffer object with 使用glBindBufferARB()绑定一个缓冲区对象。
3.使用glBufferDataARB()复制顶点数据到缓冲区对象。
glGenBuffersARB()
glGenBuffersARB()创建缓冲区对象并返回缓冲区对象的标识符。它需要两个参数:第一个参数是要创建缓冲区的个数,第二个参数是一个GLuint变量的地址或保存ID的数组地址。void glGenBuffersARB(GLsizei n, GLuint* ids)
glBindBufferARB()
一旦缓冲区对象被创建,我们要在使用缓冲区对象前将缓冲区对象与绑定ID。glBindBufferARB()有两个参数:target和ID.void glBindBufferARB(GLenum target, GLuint id)
Targe告诉VBO是将储存顶点数组(me:顶点数组的种类有顶点坐标数组,顶点法向量数组,顶点纹理数组,顶点颜色数组等)还是索引数组。储存顶点数组时Targe为GL_ARRAY_BUFFER_ARB,索引数组时为GL_ELEMENT_ARRAY_BUFFER_ARB. 任何一种顶点属性,如顶点坐标,纹理坐标,法向量和颜色数组将使用GL_ARRAY_BUFFER_ARB.索引数组用于glDraw[Range]Elements()函数,它将使用GL_ELEMENT_ARRAY_BUFFER_ARB参数.注意target标识帮助VBO决定缓冲区对象的最佳位置。如在一些系统中,索引数组在AGP或系统内存中可能更佳,顶点数组在显卡上可能更好。
一旦glBindBufferARB()被首次调用后,VBO初始化缓冲区对象,设置VBO的状态,如使用和访问属性,但缓冲区对象的内存大小为0。
glBufferDataARB()
在初始化时,可使用glBufferDataARB函数,复制数据到缓冲区对象中。
void glBufferDataARB(GLenum target, GLsizei size, const void* data, GLenum usage)
第一个参数,target可以是GL_ARRAY_BUFFER_ARB或者是GL_ELEMENT_ARRAY_BUFFER_ARB.
Size是将被传送的数据的字节数。
第三个参数是源数据数组的指针。如果data是NULL指针,那么VBO按数据大小分配储存空间。
最后一个参数,"usage"标志是一个可以提升性能的参数。VBO通过它知道缓冲区对象的使用策略:static,dynamic或stream,和 read,copy或draw.
VBO指定了这个标志的9个枚举值
GL_STATIC_DRAW_ARB
GL_STATIC_READ_ARB
GL_STATIC_COPY_ARB
GL_DYNAMIC_DRAW_ARB
GL_DYNAMIC_READ_ARB
GL_DYNAMIC_COPY_ARB
GL_STREAM_DRAW_ARB
GL_STREAM_READ_ARB
GL_STREAM_COPY_ARB
static表明在VBO中的数据不会改变了。(指定一次数据,使用多次)
dynamic表明数据将被频繁改变
stream表明数据将在每一帧中被改变(指定一次,使用一次)
draw表明数据将被发送到GPU用于绘制图形(程序到GL) read表明数据被客户端读取(GL到程序)
copy表明数据即可用于drawing也可用于(GL到GL)
注意只用draw标签用于VBO。copy和read标签只用于pixel/frame buffer object (PBO or FBO).VBO内存管理器将基于usage标志为缓冲区对象选择最佳的内存位置。例如,GL_STATIC_DRAW_ARB和GL_STREAM_DRAW_ARB 可能在显卡上,GL_DYNAMIC_DRAW_ARB可能使用AGP内存。任何与_READ_有关的缓冲区都是有益的,因为这样做,访问数组更容易。
glBufferSubDataARB()
void glBufferSubDataARB(GLenum target, GLint offset, GLsizei size, void* data).与glBufferDataARB()相似,glBufferSubDataARB()复制数据到VBO中。但它只代替指定范围内的在缓冲区中的数据。指定范围由给出的偏移值开始。 (在使用glBufferSubDataARB前,必须先使用glBufferDataARB()设置缓冲区对象的大小。
glDeleteBuffersARB()
void glDeleteBuffersARB(GLsizei n, const GLuint* ids)
你可以使用glDeleteBuffersARB删除一个或多个VBO,如果它们不再被使用了。当缓冲区对象被删除后,它其中的内容就没了。下面的代码给出了这样一个例子:创建一个顶点坐标VBO。注意在你复制程序中的顶点数组到VBO后,你可以释放顶点数组的内存。
GLuint vboId; // ID of VBO
GLfloat* vertices = new GLfloat[vCount*]; // create vertex array
... // generate a new VBO and get the associated ID
glGenBuffersARB(, &vboId); // bind VBO in order to use
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId); // upload data to VBO
glBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, vertices, GL_STATIC_DRAW_ARB); // it is safe to delete after copying data to VBO
delete [] vertices;
... // delete VBO when program terminated
glDeleteBuffersARB(, &vboId);
<me>
glGenBuffersARB 作用是得到一个没有使用的缓冲区对象的ID。
glBindBufferARB 相当于声明ID对应的对象的数据类型。相当于c++中数据类型声明。
glBufferDataARB 相当于分对象分配内存。此内存应该是显卡中。
</me>
绘制VBO
由于VBO是基于以实现了的vertex array方法,渲染VBO的方法几乎于渲染vertex array的方法相同。唯一不同的是,原来指向顶点数组的指针,现在是一个偏移值(me:此值最为关键,将n个顶点buffer合并成一个大buffer,这个偏移值指定了第i个buffer在大buffer中的起始位置). 因此,除了调用glBindBufferARB()函数外,绘制VBO不需要额外的API。
// bind VBOs for vertex array and index array
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId1); // for vertex coordinates
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vboId2); // for indices // do same as vertex array except pointer
glEnableClientState(GL_VERTEX_ARRAY); // activate vertex coords array
glVertexPointer(, GL_FLOAT, , ); // last param is offset, not ptr // draw 6 quads using offset of index array
glDrawElements(GL_QUADS, , GL_UNSIGNED_BYTE, ); glDisableClientState(GL_VERTEX_ARRAY); // deactivate vertex array // bind with 0, so, switch back to normal pointer operation
glBindBufferARB(GL_ARRAY_BUFFER_ARB, );
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, );
以0绑定一个缓冲区对象,即关闭了VBO操作。在使用VBO后,关闭VBO是一个好主意。so normal vertex array operations with absolute pointers will be re-activated.
更新VBO
VBO胜于显示列表的一个优点是,用户可以读取和修改缓冲区对象中的数据,但显示列表却不能。更新VBO最简单的方法是使用。在此例中,你的程序有一个在任何时候都有效的顶点数组。即你必须总是有两份顶点数据:一份在你的程序中,另一份在VBO中。另一个方法是映射一个缓冲区对象到客户端的内存中(me:即程序使用的系统内存)。缓冲区对象映射到了一个数组指针上,客户端使用此指针更新数据,近而更新了缓冲区对象中的数据。下面描述了如何映射VBO到客户端的内存上,以及如休访问被映射的数据。
glMapBufferARB()
VBO提供glMapBufferARB()函数,映射一个缓冲区对象到客户端内存中。
void* glMapBufferARB(GLenum target, GLenum access)
如果OpenGL映射一个缓冲区对象到客户端的地址空间中,那么glMapBufferARB()返回一个指针,指向此缓冲区对象。否则返回NULL。
第一个参数targe与先前提到的glBindBufferARB()的第一个参数相同,第二个参数,是一个访问标识。指定如何操作映射到的数据:读、写或者是读写
GL_READ_ONLY_ARB
GL_WRITE_ONLY_ARB
GL_READ_WRITE_ARB
注意glMapBufferARB()会引发一个同步操作。如果GPU仍旧使用此缓冲区对象,glMapBufferARB()不会返回,直到GPU完成在此缓冲区上的工作。
为了避免等待,你可以首先调用glBufferDataARB并传入空指针,然后调用glMapBufferARB()。此例中,先前的数据将被清除,glMapBufferARB()返回一个新分配的指针,即使GPU仍旧使用先前的数据。然而,此方法只在你想全部更新数据时有效,因为你要清除先前的数据。如果你想部分改变数据或读数据,你最后是别清除以前的数据(-_-清除了还怎么部分改变)
glUnmapBufferARB()
GLboolean glUnmapBufferARB(GLenum target)
在修改VBO中的数据之后,必须要解除在客户内存中映射的缓冲区对象。如果glUnmapBufferARB()调用成功,返回GL_TRUE。当返回GL_FALSE时,VBO中的内容corrupted当缓冲区对象被映射后。 The corruption results from screen resolution change or window system specific events. 在此例中,数据必须重新提交。
下面的代码,简单地使用了映射方法来修改VBO中的数据。
// bind then map the VBO
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId);
float* ptr = (float*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); // if the pointer is valid(mapped), update VBO
if(ptr)
{
updateMyVBO(ptr, ...); // modify buffer data
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); // unmap it after use
} // you can draw the updated VBO
...
例子
这个例子创建了一个VBO。并摆动其法向量。映射了一个VBO并在每一帧使用映射到缓冲区对象的指针,更新顶点,你可以与传统vertex array对比其性能。它使用了两个顶点缓冲区:一个储存了顶点坐标及法向量,另一个只储存索引。
下载源码及exe: vbo.zip, vboSimple.zip.
vboSimple是一个很简单的例子。它使用VBO和Vertex Array画出一个立方体。从中你可以轻松看出VBO和VA之间的相同及不同之处。
OpenGL顶点缓冲区对象(VBO)的更多相关文章
-
OpenGL顶点缓冲区对象
[OpenGL顶点缓冲区对象] 显示列表可以快速简单地优化立即模式(glBegin/glEnd)的代码.在最坏的情况下,显示列表的命令被预编译存到命令缓冲区中,然后发送给图形硬件.在最好的情况下,是编 ...
-
[译]OpenGL像素缓冲区对象
目录概述创建PBO映射PBO例子:Streaming Texture Uploads with PBO例子:Asynchronous Readback with PBO 概述 OpenGL ARB_p ...
-
OpenGL 顶点缓存对象
顶点缓存对象(Vertex Buffer Object,简称 VBO),允许开发者根据情况把顶点数据放到显存中. 如果不用 VBO,用 glVertexPointer / glNormalPointe ...
-
OpenGL中VA,VAO,VBO和EBO的区别
1,顶点数组(Vertex Array) VA,顶点数组也是收集好所有的顶点,一次性发送给GPU.不过数据不是存储于GPU中的,绘制速度上没有显示列表快,优点是可以修改数据. 4.VBO(Vertex ...
-
OpenGL图形渲染管线、VBO、VAO、EBO概念及用例
图形渲染管线(Pipeline) 图形渲染管线指的是对一些原始数据经过一系列的处理变换并最终把这些数据输出到屏幕上的整个过程. 图形渲染管线的整个处理流程可以被划分为几个阶段,上一个阶段的输出数据作为 ...
-
顶点缓存对象(VBO)
创建VBO 绘制VBO 更新VBO 实例 GL_ARB_vertex_buffer_object扩展致力于提供顶点数组与显示列表的优势来提升OpenGL效率,同时避免它们实现上的不足.顶点缓存对象(V ...
-
OpenGL学习笔记3——缓冲区对象
在GL中特别提出了缓冲区对象这一概念,是针对提高绘图效率的一个手段.由于GL的架构是基于客户——服务器模型建立的,因此默认所有的绘图数据均是存储在本地客户端,通过GL内核渲染处理以后再将数据发往GPU ...
-
OPenGL中的缓冲区对象
引自:http://blog.csdn.net/mzyang272/article/details/7655464 在许多OpenGL操作中,我们都向OpenGL发送一大块数据,例如向它传递需要处理的 ...
-
OpenGL ES 3.0 帧缓冲区对象基础知识
最近在帧缓冲区对象这里卡了一下,不过前面已经了解了相关的OpenGL ES的知识,现在再去了解就感觉轻松多了.现在就进行总结. 基础知识 我们知道,在应用程序调用任何的OpenGL ES命令之前,需要 ...
随机推荐
-
Codeforce - Runtime Error
Bahosain was trying to solve this simple problem, but he got a Runtime Error on one of the test case ...
-
java nio 网络框架实现
maven项目 https://github.com/solq360/common 链式编/解码 链路层链式处理 管道管理socket 多协议处理非常方便 仿netty NioEventLoop 单线 ...
-
QT设置标签字体大小和颜色
ui.label是QLabel ui.label_4->setText("some text"); //设置字号 QFont ft; ft.setPointSize(12); ...
-
再看ADO对象模型
在敲学生管理系统之前,我们就学习过ADO的有关知识.但是昨天被问到ADO的几个对象,顿时无言!为什么会出现这样的结果呢,明明是学习过了,而且也实践过(红皮书的五个例子).这充分说明了,在以往的学习过程 ...
-
mysql免安装版配置与使用方法
mysql免安装版配置与使用方法 以mysql-noinstall-5.1.6(win32)为例 1>把压缩文件mysql-noinstall-5.1.6-alpha-win32.zi ...
-
8个超炫酷的jQuery相册插件欣赏
在网页中,相册应用十分常见,如果你经常逛一些社交网站,那么你应该会注意到很多各式各样的网页相册应用.今天我们要来分享一些最新收集的jQuery相册插件,这些精美的jQuery相册插件可以帮助你快速搭建 ...
-
译注(3): NULL-计算机科学上最糟糕的失误
原文:the worst mistake of computer science 注释:有些术语不知道怎么翻译,根据自己理解的意思翻译了,如有不妥,敬请提出:) 致谢: @vertextao @fra ...
-
06-Nodejs介绍
06-Nodejs介绍 打开Nodejs英文网:https://nodejs.org/en/ 中文网:http://nodejs.cn/ 我们会发现这样一句话: 翻译成中文如下: Node.js 是一 ...
-
OpenStack实践系列⑧可视化服务Horizon之Dashboard演示
OpenStack实践系列⑧可视化服务Horizon之Dashboard演示 七.可视化服务Horizon之Dashboard演示 仪表板依赖于功能核心服务,包括身份,图像服务,计算和网络两种(neu ...
-
PHP设计模式之观察者模式(转)
开篇还是从名字说起,“观察者模式”的观察者三个字信息量很大.玩过很多网络游戏的童鞋们应该知道,即便是斗地主,除了玩家,还有一个角色叫“观察者".在我们今天他谈论的模式设计中,观察者也是如此. ...