nv文档使用VBOs

译者注:
最近翻找有关于VBO的资料,发现网上很少有这方面的中文资料。现将nvidia官方网站上的一篇文章《Using Vertex Buffer Objects(VBOs)》,特将其翻译出来,以供后人使用J。翻译时间不到一天,匆忙之余,难免有误,敬请指正,欢迎来邮,我是Neil。
联系邮箱:zhuhuazha@yahoo.com.cn
联系blog:Neil`s Blog 
Using VBOs是来自于Nvidia的官方网站上的白皮书。
来源网址: http://developer.nvidia.com/object/using_VBOs.html,如有转载请注明版权。
使  用  VBOs

 

概要:
VBO是一种强大的技术:它允许我们在服务器端的高速缓存上存储一定量的数据。
该要素提供这样一种机制:压缩数据到“缓存对象(buffer objects)”,使得处理这些数据时不必从服务器直接取出来,从而加快数据传输速率。
VBOs可在以下几点上帮助我们:
□ 由客户端或者状态函数指向的任意数据体。最典型的就是我们所讨论的glVertexPointer(),glColorPointer(),glNormalPointer()等等。
□ 画图元集的指示数组(glDraw[Range]Elements())。
该机制的最初想法是提供一些能由标识符获取的内存块(缓存)。就像显示列表和纹理,我们可以通过绑定这样一个缓存来激活它。
该绑定操作将每个客户机/状态函数指针变成一定量的偏移,因为我们将会在内存区域里用到,该区域是相对于当前范围缓存的。换句话说,该扩展将客户机/状态函数变成了服务器/状态函数。
我们都知道客户机/状态函数处理数据的范围仅是对于客户机自身是可访问的。其它的任一个客户机都不可能访问到这些数据。通过在服务器端执行这些函数序列,才可以在不同的客户机上共享使用这些数据。许多客户机能绑定通用的缓存,它们都像纹理和显示列表一样通过标识符来处理。

VAR的问题:
以前解决这类任务的扩展方法是用VAR(Vertex Array Range顶点数组序列)。尽管该扩展仍然可以用,但我们建议您用VBO来代替。
VAR功能上完全够用,但在此不妨列举一下开发人员觉得它不好的地方:
□ 它打破了服务器/客户机的模式,因为客户机部分控制了内存管理(本归于服务器)。
□ 并没有提供一个内部的内存管理,VAR所提供的唯一功能就是在服务器的内存上定位一大块内存区域。
□ 当给VAR定位缓存时,开发者需要描述哪里要用到AGP、系统、或者显卡缓存,而这些工作显得麻烦而棘手。
□ 开发人员仍然需要为VAR在本地创建自己的内存定位以优化它们借来的缓存块。
□ 高效的内存管理必须是像旗语一样的防卫系统。
为了简化问题,我们可以说VBO能像VAR样处理问题,并且能为你管理内存(图1)。


内存管理
OpenGL有着与Direct3D为顶点数组提供的AGP/视频内存(显存)管理似的同一层次功能。OpenGL里的工作方式也十分相似。它有映射到内存缓存的能力,从而定义各缓存的利用,映射和取消映射(在D3D中是Lock/Unlock)。
内部内存管理能为我们选择最佳的内存类型(系统、视频卡或者AGP),这取决于我们所用的缓存。
VBO提供了不同的方式与缓存对象进行交互:
□ 绑定缓存(glBindBuffer):该操作允许客户机/状态函数直接在缓存区域工作,而不必在客户机的绝对(物理)内存上。绑定0号缓存则切断VBO,这样就可以用绝对指针回到原有客户机的状态模式。
□ 利用VBO的API加载数据到这些缓存对象上(glBufferData、glBufferSubData、glGetBufferSubData):这些函数让你在客户机区域和服务器的缓存对象作一个复制)。
□ 利用缓存映射技术(glMapBuffer 和glUnmapBuffer):这个类似于D3D的Lock与UnLock。你可以得到一个临时指针作为缓存开始的入口,意味着缓存是映射到了客户机内存上。OpenGL负责如何映射到客户机上。由于这一点,映射必须作为一个短的操作,并且指针不能存储给以后的应用。

对象
VBO与以下两种对象一起工作:
□ 数组缓存(ARRAY_BUFFER_ARB):这些缓存包含顶点属性,例如顶点坐标、纹理坐标数据、各顶点着色数据和法向信息。你可以插入该数据(利用stride参数),或者在另一数组后再写入一个数组(比如先写1000个顶点,再写1000个法向量,等等)。GlVertexPointer glNormalPOinter(等等)必须有正确的指向偏移量。
□ 图元数组缓存(ELEMENT_ARRAY_BUFFER_ARB):该类型缓存主要在glDraw[Range]Element()中用于图元指针。它可能仅包含图元的指示符。
这两种目标平行同步建立,因为图元数组在glDraw[Range]Element()函数中必须与数组缓存同时获取。
用这两种对象的一个有意思的地方是,当保存同一顶点数组缓存时,交换各种图元缓存的能力。我们可以实施LOD,或者当我们工作于同一顶点数据库时改变图元表所产生的其它任何效果。
关于PBO的几句话
建议给VBO增加更多的对象的另一扩展是ARB_pixel_buffer_object(PBO,象素缓存对象)。
尽管它在我们的50.XX版本驱动里还没有(译者注:此为nividia的图形驱动),该扩展允许我们通过增加两个新的对象在纹理、帧缓存、离屏缓存里工作。
换句话说,它会对顶点、法向、图元等等提供同样的机制,但是对于字节数组却不同。
新的两种对象是:
□ PIXEL_PACK_BUFFER:该对象给各种读操作提供缓存,例如glReadPixels和glGetTexImage。这些命令将会把它们的数据写到当前范围缓存对象中。
□ PIXEL_UNPACK_BUFFER:该对象给各种写操作提供缓存,例如glBitmap,glDrawPixels和glTexImage2D。这些命令将会从缓存对象中读取数据。
在VBOs与PBOs混合时会有一些很有意思的优化措施(图2):
□ 渲染到顶点数组:如果我们打算在第一个通道创建一个特殊的顶点数组(用于贴图、移位等等),我们可以避免作为一个顶点程序的输入而在客户机端复制p缓存(pBuffer),并放回到服务器端。VBO/PBO会保持所有数据流都在服务器端。
□ 流纹理:该操作类似于我们操作PDR(Pixel Data Range象素数据范围);我们用MapBuffer/UnMapBuffer来改变纹理数据,基于视频流,然后调用TexSubImage来更新纹理。
 


图2 VBO/PBO结合实例

新的步骤、功能函数和符号标志
使用标志:
□ STREAM_DRAW_ARB
□ STREAM_READ_ARB
□ STREAM_COPY_ARB
□ STATIC_DRAW_ARB
□ STATIC_READ_ARB
□ STATIC_COPY_ARB
□ DYNAMIC_DRAW_ARB
□ DYNAMIC_READ_ARB
□ DYNAMIC_COPY_ARB
访问标志:
□ READ_ONLY_ARB
□ WRITE_ONLY_ARB
□ READ_WRITE_ARB
对象:
□ ARRAY_BUFFER_ARB
□ ELEMENT_BUFFER_ARB
void BindBufferARB(enum target, uint buffer):
BindBufferARB函数用于绑定对象ID作为使用的实际缓存。如果ID为0就关闭了缓存使用。
void *MapBufferARB( enum target, enum access);
boolean UnmapBufferARB(enum target);
MapBufferARB函数提供一个指针指向当前缓存对象的映射区域,UnmapBufferARB则解除映射。
void BufferDataARB(enum target, sizeiptrARB size, const void *data, enum usage);
BufferDataARB有以下两种用法:
□ 当数据集置为NULL时简化当前缓存对象的内存装载和使用量。这样,你后来就可以通过映射缓存来装载数据。
□ 定位缓存,设置usage, 复制一些数据;特别用于处理静态内存模型。
void BufferSubDataARB( enum target, intptrARB offset, sizeiptrARB size, const void*data)
该函数用于在缓存对象的特定区域内复制数据。
void GetBufferSubDataARB(enum target, intptrARB offset, sizeiptrARB size, void *data);
该函数用于在当前缓存的特定区域获取数据。
void DeleteBufferARB(sizei n, const uint *buffers);
void GenBufferARB(sizei n, uint *buffers);
boolean IsBufferARB(uint buffer);
这三组函数类似于显示列表/纹理标识符;它们能缓存对象定位、释放或者查询一些标识符。
void GetBufferParameterivARB(enum target, enum pname, int *params);
该函数返回关于当前缓存对象的各种参数,pname可能是:
□ BUFFER_SIZE_ARB:返回缓存对象的大小。
□ BUFFER_USAGE_ARB:返回缓存对象的用法。
□ BUFFER_ACCESS_ARB:返回缓存对象的可访问标志。
□ BUFFER_MAPPED_ARB:告诉你我们是否已经映射了该缓存。
void GetBufferPointervARB(enum target, enum pname, void **params);
该函数返回缓存的实际指针,如果该缓存已经被映射了的话(MapBufferARB)。Pname这次只能是BUFFER_MAP_POINTER_ARB。
Get{Boolean, Integer, Float, Double}v的标签
缓存对象ID0是保留的,当0缓存对象与所给出的对象外时,该绑定缓存所影响的命令才能正常起作用。当非0缓存出界了,指针就表示一个偏移,并且将会超出VBO的管理。
你可以使用以下标签来得知哪个缓存是作为VBO偏移的:
□ ARRAY_BUFFER_BINDING_ARB
□ ELEMENT_ARRAY_BUFFER_BINDING_ARB
□ VERTEX_ ARRAY_BUFFER_BINDING_ARB
□ NORMAL_ ARRAY_BUFFER_BINDING_ARB
□ COLOR_ ARRAY_BUFFER_BINDING_ARB
□ INDEX_ ARRAY_BUFFER_BINDING_ARB
□ TEXTURE_COORD_ ARRAY_BUFFER_BINDING_ARB
□ EDGE_FLAG_ ARRAY_BUFFER_BINDING_ARB
□ SECONDAR_COLOR_ ARRAY_BUFFER_BINDING_ARB
□ FOG_COORDINATE_ ARRAY_BUFFER_BINDING_ARB
□ WEIGTH_ ARRAY_BUFFER_BINDING_ARB
GetVertexAttribivARB的标签:
当使用VBO和顶点程序工作时,一些属性会有一些任意的意思:例如一个法向数组可能不仅仅是用于存储法向信息。替代前一节使用标签的方法是:你可以使用属性的索引。该标签允许你通过偏移系统利用VBO来查询使用了哪个属性码。
□ VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB

 [实例] VBO的创建、初始化和销毁
CODE:
GLuint nBufferID;
//获得一个空闲的 buffer ID:
glGenBuffersARB(1, &nBufferID);
//绑定 buffer ID:
glBindBufferARB(GL_ARRAY_ BUFFER_ARB, nBufferID);
//初始化VBO:
glBufferDataARB(GL_ARRAY_ BUFFER_ARB, 200, NULL, DYNAMIC_DRAW_ARB);
....
//销毁VBO:
glDeleteBuffersARB(1, &nBufferID);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值