顶点缓存对象(VBO)【转】
http://www.cnblogs.com/hefee/p/3824300.html
顶点缓存对象(VBO)
GL_ARB_vertex_buffer_object扩展致力于提供顶点数组与显示列表的优势来提升OpenGL效率,同时避免它们实现上的不足。顶点缓存对象(VBO)准许顶点数组数据存放在服务端的高性能显卡内存中,且提供高效数据传输。如果缓存对象用于保存像素数据,就被称为像素缓存对象(PBO)。
使用顶点数组可以降低函数调用次数与降低共享顶点的重复使用。然而,顶点数组的不足之处是顶点数组函数处在客户端状态中,且每次引用都须向服务端重新发送数据。
此外,显示列表为服务端函数,因此,它并不受限于数据传输的开销。不过,一旦显示列表编译完成,显示列表中的数据不能够修改。
顶点缓存对象(VBO)在服务器端高性能内存中为顶点属性创建“缓存对象”,并且提供引用这些数组的访问函数,这些函数与顶点数组中使用的函数相同,如glVertexPointer()、glNormalPointer()、glTexCoordPointer()等。
顶点缓存对象中的内存管理根据用户提示(“target”与“Usage”模式)将缓存对象放置在最合适内存位置。因此,内存管理能够通过在系统、AGP与显卡内存三种内存之间做出平衡的方式优化缓存。
与显示列表不同,可以通过映射缓存到客户端内存空间的方式读取与更新顶点缓存对象中的数据。
VBO的另一个重要优势是就像显示列表与纹理那样可以在多个客户端共享缓存数据。因为VBO处在服务器端,多个客户端可以通过相应的标示符访问同一个缓存。
创建VBO
创建VBO需要3个步骤:
- 使用glGenBuffers()生成新缓存对象。
- 使用glBindBuffer()绑定缓存对象。
- 使用glBufferData()将顶点数据拷贝到缓存对象中。
glGenBuffers()
glGenBuffers()创建缓存对象并且返回缓存对象的标示符。它需要2个参数:第一个为需要创建的缓存数量,第二个为用于存储单一ID或多个ID的GLuint变量或数组的地址。
|
1
|
void glGenBuffers(GLsizei n, GLuint* buffers) |
glBindBuffer()
当缓存对象创建之后,在使用缓存对象之前,我们需要将缓存对象连接到相应的缓存上。glBindBuffer()有2个参数:target与buffer。
|
1
|
void glBindBuffer(GLenum target, GLuint buffer) |
target告诉VBO该缓存对象将保存顶点数组数据还是索引数组数据:GL_ARRAY_BUFFER或GL_ELEMENT_ARRAY。任何顶点属性,如顶点坐标、纹理坐标、法线与颜色分量数组都使用GL_ARRAY_BUFFER。用于glDraw[Range]Elements()的索引数据需要使用GL_ELEMENT_ARRAY绑定。注意,target标志帮助VBO确定缓存对象最有效的位置,如有些系统将索引保存AGP或系统内存中,将顶点保存在显卡内存中。
当第一次调用glBindBuffer(),VBO用0大小的内存缓存初始化该缓存,并且设置VBO的初始状态,如用途与访问属性。
glBufferData()
当缓存初始化之后,你可以使用glBufferData()将数据拷贝到缓存对象。
|
1
|
void glBufferData(GLenum target,GLsizeiptr size, const GLvoid* data, GLenum usage); |
第一个参数target可以为GL_ARRAY_BUFFER或GL_ELEMENT_ARRAY。size为待传递数据字节数量。第三个参数为源数据数组指针,如data为NULL,则VBO仅仅预留给定数据大小的内存空间。最后一个参数usage标志位VBO的另一个性能提示,它提供缓存对象将如何使用:static、dynamic或stream、与read、copy或draw。
VBO为usage标志指定9个枚举值:
|
1
2
3
4
5
6
7
8
9
|
GL_STATIC_DRAWGL_STATIC_READGL_STATIC_COPYGL_DYNAMIC_DRAWGL_DYNAMIC_READGL_DYNAMIC_COPYGL_STREAM_DRAWGL_STREAM_READGL_STREAM_COPY |
”static“表示VBO中的数据将不会被改动(一次指定多次使用),”dynamic“表示数据将会被频繁改动(反复指定与使用),”stream“表示每帧数据都要改变(一次指定一次使用)。”draw“表示数据将被发送到GPU以待绘制(应用程序到GL),”read“表示数据将被客户端程序读取(GL到应用程序),”copy“表示数据可用于绘制与读取(GL到GL)。
注意,仅仅draw标志对VBO有用,copy与read标志对顶点/帧缓存对象(PBO或FBO)更有意义,如GL_STATIC_DRAW与GL_STREAM_DRAW使用显卡内存,GL_DYNAMIC使用AGP内存。_READ_相关缓存更适合在系统内存或AGP内存,因为这样数据更易访问。
glBufferSubData()
|
1
|
void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); |
与glBufferData()类似,glBufferSubData()用于向VBO中拷贝数据,不过它仅仅将从给定offset开始的一定范围的数据替换到现存缓存中。(在使用glBufferSubData()之前,整个缓存必须由glBufferData()指定。)
glDeleteBuffers()
|
1
|
void glDrawBuffers(GLsizei n, const GLenum* bufs); |
在VBO不再使用时,你可以使用glDeleteBuffers()删除一个VBO或多个VBO。在混存对象删除之后,它的内容将丢失。
下列代码是为顶点坐标创建单一VBO的实例。注意,在你拷贝数据到VBO之后,你可以应用程序中为顶点数组分配的内存。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
GLuint vboId; // VBO标示符GLfloat* vertices = new GLfloat[vCount*3]; // 创建顶点数组...// 创建新的VBO并获取相关标示符glGenBuffers(1, &vboId);// 绑定VBO以待使用glBindBuffer(GL_ARRAY_BUFFER_ARB, vboId);// 更新数据到VBOglBufferData(GL_ARRAY_BUFFER_ARB, dataSize, vertices, GL_STATIC_DRAW_ARB);// 在拷贝数据到VBO之后,可以安全删除delete [] vertices;...// 程序终止时删除VBOglDeleteBuffers(1, &vboId); |
绘制VBO
由于VBO基于现有的顶点数组实现之上,渲染VBO与使用顶点数组渲染几乎一致。仅有的不同是顶点数组指针现在作为当前绑定缓存对象的偏移值。因此,绘制VBO时除了glBindBuffer()之外不需别的API。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// 为顶点数组与索引数组绑定VBOglBindBuffer(GL_ARRAY_BUFFER_ARB, vboId1); // 顶点坐标glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, vboId2); // 索引坐标// 除了指针都与顶点数组一致glEnableClientState(GL_VERTEX_ARRAY); // 开启顶点坐标数组glVertexPointer(3, GL_FLOAT, 0, 0); // 最后一个参数为offset,而非ptr// 使用索引数组偏移绘制6个四边形glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, 0);glDisableClientState(GL_VERTEX_ARRAY); // 禁用顶点数组// 用0绑定,因此,切换到标准指针操作glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); |
使用0绑定缓存对象将关闭VBO操作。在使用完VBO之后,最好将之关闭,因此具有绝对指针的顶点数组操作将重新开启。
更新VBO
VBO相对于显示列表的优势在于客户端可以读取与编辑缓存对象数据,而显示列表不能这样做。更新VBO的最简便方法是使用glBufferData()或glBufferSubData()将新数据重新拷贝到绑定的VBO中。这种情况下,你的应用程序需要始终拥有一个有效的顶点数组。也就是说,你必须始终拥有2份顶点数据:一份在应用程序中,另一份在VBO中。
修改缓存对象的另一个方式是将缓存对象映射到客户端内存,客户端可以使用映射缓存的指针更新数据。下文描述如何将VBO映射到客户端内存以及如何访问映射数据。
glMapBuffer()
VBO提供glMapBuffer()以将缓存对象绑定到客户端内存。
|
1
|
void* glMapBuffer(GLenum target, GLenum access); |
如果OpenGL能够将缓存对象映射到客户端地址空间,glMapBuffer()返回指向缓存的指针。否则它返回NULL。
第一个参数target早在glBindBuffer()中涉及,第二个参数access标志指定怎样使用映射数据:读取、改写或两者都。
|
1
2
3
|
GL_READ_ONLYGL_WRITE_ONLYGL_READ_WRITE |
注意,glMapBuffer()引起同步问题。如果GPU任然工作于该缓存对象,glMapBuffer()将一直等待直到GPU结束对应缓存对象上的工作。
为了避免等待,你可以首先使用NULL调用glBufferData(),然后再调用glMapBuffer()。这样,前一个数据将被丢弃且glMapBuffer()立即返回一个新分配的指针,即使GPU任然工作于前一个数据。
然而,由于你丢弃了前一个数据,这种方法只有在你想更新整个数据集的时候才有效。如果你仅仅希望更改部分数据或读取数据,你最好不要释放先前的数据。
glUnmapBuffer()
|
1
|
GLboolean glUnmapBuffer(GLenum target) |
在完成VBO数据的修改之后,必须将缓存对象从客户端内存解除映射。如果成功,glUnmapBuffer()返回GL_TRUE。如返回GL_FALSE,绑定之后的VBO缓存内容是坏的。腐坏现象源自显示器分辨率的改变或窗口系统的特定事件。此种情况,数据必须重发。
下面是使用绑定方式改变VBO的实例代码。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 绑定然后映射该VBOglBindBuffer(GL_ARRAY_BUFFER_ARB, vboId);float* ptr = (float*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);// 如果指针为空(映射后的),更新VBOif (ptr){ updateMyVBO(ptr, ...); // 修改缓存数据 glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); // 使用之后解除映射}// 你可以绘制更新后的VBO... |
实例

该实例程序沿法线防线创建VBO抖动。它映射VBO并且使用指向映射缓存的指针每帧更新一次顶点数据。你可以与传统顶点数组实现方式继进行性能对比。
它使用2个顶点缓存:一个为了顶点坐标与法向量,另一个仅仅保存索引数组。
下载源文件与二进制文件:vbo.zip,vboSimple.zip。
vboSimple是使用VBO与顶点数组绘制立方体的简单例子。你可以很容易看出VBO与VA的相同点与不同点。
顶点缓存对象(VBO)【转】的更多相关文章
- 顶点缓存对象(VBO)
创建VBO 绘制VBO 更新VBO 实例 GL_ARB_vertex_buffer_object扩展致力于提供顶点数组与显示列表的优势来提升OpenGL效率,同时避免它们实现上的不足.顶点缓存对象(V ...
- OpenGL 顶点缓存对象
顶点缓存对象(Vertex Buffer Object,简称 VBO),允许开发者根据情况把顶点数据放到显存中. 如果不用 VBO,用 glVertexPointer / glNormalPointe ...
- OpenGL顶点缓冲区对象(VBO)
转载 http://blog.csdn.net/dreamcs/article/details/7702701 创建VBO GL_ARB_vertex_buffer_object 扩展可 ...
- NeHe OpenGL教程 第四十五课:顶点缓存
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- Direct3D 顶点缓存
今天我们来学习下Direct3D的顶点和顶点缓存,首先我们需要在场景中绘制一些物体,物体都是由多个三角形组成,每一个三角形由三个顶点组成,我们来看下面一个NPC的模型 左图:正常的模型 ...
- 现代3D图形编程学习--opengl使用不同的缓存对象(译者添加)
现代3D图形编程学习系列翻译地址 http://www.cnblogs.com/grass-and-moon/category/920962.html opengl使用不同的缓存对象 在设置颜色一章中 ...
- OpenGL帧缓存对象(FBO:Frame Buffer Object)(转载)
原文地址http://www.songho.ca/opengl/gl_fbo.html 但有改动. OpenGL Frame BufferObject(FBO) Overview: 在OpenGL渲染 ...
- 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D中的顶点缓存和索引缓存
第12章 Direct3D绘制基础 1. 顶点缓存 计算机所描绘的3D图形是通过多边形网格来构成的,网网格勾勒出轮廓,然后在网格轮廓的表面上贴上相应的图片,这样就构成了一个3D模型.三角形网格是构建物 ...
- OpenGL帧缓存对象(FBO:Frame Buffer Object)
http://blog.csdn.net/dreamcs/article/details/7691690 转http://blog.csdn.net/xiajun07061225/article/de ...
随机推荐
- python3,判断,循环练习1
1.使用while循环输出1 2 3 4 5 6 8 9 10 i = 1 while i <= 10: if i == 7: i += 1 print(end=' ') continue pr ...
- ubuntu16.04搭建个人简易DLP
前言 最近一朋友让我帮忙搭建一台服务器,用做公司的服务器,但是该服务器需要满足一些安全要求,于是乎就有了下面的解决过程^_^ 需求 期望普通用户和管理员都能ssh登陆服务器,但禁止scp或者其他方式下 ...
- Python3安装cx_Oracle连接oracle数据库实操总结
弄清版本,最重要!!! 首先安装配置时,必须把握一个点,就是版本一致!包括:系统版本,python版本,oracle客户端的版本,cx_Oracle的版本,然后安装配置就容易了! 如果已经安装Pyth ...
- 获取struts迭代list在页面显示的数据
js代码: function modifyPactMoney(){ var table=$("#pactfee"); var trs=table.find("tr&quo ...
- 理解OCI(Open Container Initiative)及docker的OCI实现(转)
OCI定义了容器运行时标准,runC是Docker按照开放容器格式标准(OCF, Open Container Format)制定的一种具体实现. runC是从Docker的libcontainer中 ...
- [BZOJ4006][JLOI2015]管道连接 状压dp+斯坦纳树
4006: [JLOI2015]管道连接 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1020 Solved: 552[Submit][Statu ...
- hdu5079
这道题的难点在于思考dp表示什么 首先可以令ans[len]表示白色子矩阵边长最大值大于等于len的方案数则ans[len]-ans[len+1]就是beautifulness为len的方案数 白色子 ...
- AC日记——Keywords Search hdu 2222
2222 思路: ac自动机模板题: 代码: #include <cstdio> #include <cstring> #include <iostream> #i ...
- 关于android studio3.0版本后引入资源问题error: failed linking file resources
最近更新阿里短视频的SDK,导入demo项目时,发现两个问题: 1.频繁报错AAPT2 error: file not found.以为直接Sync重新编译就可以,但是仍旧频繁提醒引入资源错误. 查找 ...
- sourceforge的FTP镜像
https://www.mirrorservice.org/sites/ftp.sourceforge.net/