好记性不如铅笔头

C && C++, cocos2dx, 编程

【转】OpenGL ES使用VBO:顶点缓存

本文转自【 http://www.cnblogs.com/kesalin/archive/2012/12/20/vbo.html 】,有删改。

CONTENTS

VBO简介

在前面几篇的示例中,都是通过类似如下代码直接从 CPU 主存中传递顶点数据到 GPU 中去进行运算与渲染的。

glVertexAttrib4f(_colorSlot, color[0], color[1], color[2], color[3]);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices );
glEnableVertexAttribArray(_positionSlot);   
glDrawElements(GL_LINES, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);

在上面的代码中 vertices 和 indices 都是在主存中分配的内存空间,当需要进行渲染时,这些数据便通过 glDrawElements 或 glDrawArrays 从 CPU 主存中拷贝到 GPU 中去进行运算与渲染。这种做法需要频繁地在 CPU 与 GPU 之间传递数据,效率低下,因此出现了 VBO (Vertex Buffer object),即顶点缓存,它直接在 GPU 中开辟一个缓存区域来存储顶点数据,因为它是用来缓存储顶点数据,因此被称之为顶点缓存。我们只会在初始化缓冲区,以及在顶点数据有变化时才需要对该缓冲区进行写操作。使用顶点缓存能够大大较少了CPU-GPU 之间的数据拷贝开销,因此显著地提升了程序运行的效率。

API介绍

创建顶点缓存对象
void glGenBuffers (GLsizei n, GLuint* buffers);
参数 n : 表示需要创建顶点缓存对象的个数;
参数 buffers :用于存储创建好的顶点缓存对象句柄;

将顶点缓存对象设置为(或曰绑定到)当前数组缓存对象或元素缓存对象
void glBindBuffer (GLenum target, GLuint buffer);
参数 target :指定绑定的目标,取值为 GL_ARRAY_BUFFER(用于顶点数据) 或 GL_ELEMENT_ARRAY_BUFFER(用于索引数据);
参数 buffer :顶点缓存对象句柄;

为顶点缓存对象分配空间
void glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
参数 target:与 glBindBuffer 中的参数 target 相同;
参数 size :指定顶点缓存区的大小,以字节为单位计数;
data :用于初始化顶点缓存区的数据,可以为 NULL,表示只分配空间,之后再由 glBufferSubData 进行初始化;
usage :表示该缓存区域将会被如何使用,它的主要目的是用于提示OpenGL该对该缓存区域做何种程度的优化。其参数为以下三个之一:
GL_STATIC_DRAW:表示该缓存区不会被修改;
GL_DyNAMIC_DRAW:表示该缓存区会被周期性更改;
GL_STREAM_DRAW:表示该缓存区会被频繁更改;

如果顶点数据一经初始化就不会被修改,那么就应该尽量使用 GL_STATIC_DRAW,这样能获得更好的性能。

更新顶点缓冲区数据
void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
参数 :offset 表示需要更新的数据的起始偏移量;
参数 :size 表示需要更新的数据的个数,也是以字节为计数单位;
data :用于更新的数据;

释放顶点缓存
void glDeleteBuffers (GLsizei n, const GLuint* buffers);
参数与 glGenBuffers 类似,就不再累述,该函数用于删除顶点缓存对象,释放顶点缓存。

多面手:glVertexAttribPointer 和 glDrawElements

在介绍如何使用 VBO 进行渲染之前,我们先来回顾一下之前使用顶点数组进行渲染用到的函数:
void glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
参数 index :为顶点数据(如顶点,颜色,法线,纹理或点精灵大小)在着色器程序中的槽位;
参数 size :指定每一种数据的组成大小,比如顶点由 x, y, z 3个组成部分,纹理由 u, v 2个组成部分;
参数 type :表示每一个组成部分的数据格式;
参数 normalized : 表示当数据为法线数据时,是否需要将法线规范化为单位长度,对于其他顶点数据设置为 GL_FALSE 即可。如果法线向量已经为单位长度设置为 GL_FALSE 即可,这样可免去不必要的计算,提升效率;
stride : 表示上一个数据到下一个数据之间的间隔(同样是以字节为单位),OpenGL ES根据该间隔来从由多个顶点数据混合而成的数据块中跳跃地读取相应的顶点数据;
ptr :值得注意,这个参数是个多面手。如果没有使用 VBO,它指向 CPU 内存中的顶点数据数组;如果使用 VBO 绑定到 GL_ARRAY_BUFFER,那么它表示该种类型顶点数据在顶点缓存中的起始偏移量。
那 GL_ELEMENT_ARRAY_BUFFER 表示的索引数据呢?那是由以下函数使用的:
void glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
参数 mode :表示描绘的图元类型,如:GL_TRIANGLES,GL_LINES,GL_POINTS;
参数 count : 表示索引数据的个数;
参数 type : 表示索引数据的格式,必须是无符号整形值;
indices :这个参数也是个多面手,如果没有使用 VBO,它指向 CPU 内存中的索引数据数组;如果使用 VBO 绑定到 GL_ELEMENT_ARRAY_BUFFER,那么它表示索引数据在 VBO 中的偏移量。

发表评论

2 × 4 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据