[TOC]
3. Vertex Buffer Objects
通过顶点数组声明的顶底数据储存在客户端内存中,当一次绘制命令被调用时,这些数据必须从客户端内存拷贝到图形内存中。如果能够在图形内存中缓存这些数据而不是每次都进行拷贝,无疑会提高很多效率。顶点缓冲对象,就是用来在图形内存中缓存数据,然后进行渲染的。
OpenGL ES支持两种缓冲对象:
- array buffer objects : 通过GL_ARRAY_BUFFER指明,用来储存顶点数据
- element array buffer objects : 通过GL_ELEMENT_ARRAY_BUFFER指明,用来储存图元索引。
OpenGL ES 3.0中其它的缓冲对象:
- uniform buffers (第四章介绍)
- transform feedback buffers(第八章)
- pixel unpack buffers (第九章)
- pixel pack buffers (第十一章)
- copy buffers (第六章)
在我们用缓冲对象进行渲染之前,我们先要创建缓冲物体并且加载顶点数据和图元索引,以下是一个简单示例:
void initVertexBufferObject (vertex_t * vertexBuffer, GLushort * indices, GLuint numVertices, GLuint numIndices, GLuint * vboIds)
{
glGenBuffers (2, vboIds);
glBindBuffer (GL_ARRAY_BUFFER, vboIds[0]);
glBufferData (GL_ARRAY_BUFFER, numVertices * sizeof(vertex_t), vertexBuffer, GL_STATIC_DRAW);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, vboIds[1]);
glBufferData (GL_ELEMEMT_ARRAY_BUFFER, numIndices * sizeof(GLushort), indices, GL_STATIC_DRAW);
}
在上面的例子中,首先通过glGenBuffers获得了两个未被使用的缓冲对象,然后这两个缓冲对象被用来创建一个数组缓冲对象和一个元素数组缓冲对象,其中数组缓冲对象用来储存顶点属性数据,元素数组缓冲对象用来储存图元的顶点索引。
生成缓冲对象:
void glGenBuffers (GLsizei n, GLuint * buffers)
- n : 要创建的缓冲对象的数量
- buffers : 指向用于保存新创建的缓冲对象的数组
- glGenBuffers分配n个缓冲对象名称,并且在buffers中返回他们。缓冲对象名称是除0以外的无符号整数。0值由OpenGL保留,不表示缓冲对象。
绑定缓冲对象:
void glBindBuffer (GLenum target, GLuint buffer )
- target : 可取值为
GL_ARRAY_BUFFER
GL_ELEMENT_ARRAY_BUFFER
GL_COPY_READ_BUFFER
GL_COPY_WRITE_BUFFER
GL_PIXEL_PACK_BUFFER
GL_PIXEL_UNPACK_BUFFER
GL_TRANSFORM_FEEDBACK_BUFFER
GL_UNIFORM_BUFFER- buffer : 缓冲对象
注意,并不一定非要使用glGenBuffers来分配缓冲对象然后才能使用,你也可以直接使用未使用过的缓冲对象,也就是手动记录管理,但是推荐使用glGenBuffers来自动分配管理。
和缓冲对象相关的状态可分为两类:
- GL_BUFFER_SIZE :表示缓冲对象数据的大小,初始值是0
- GL_BUFFER_USAGE : 对应用程序怎样使用缓冲对象数据的提示(hint,具体依赖于实现,也就是说即使使用了GL_STATIC_DRAW,也可能频繁的修改),初始值是GL_STATIC_DRAW,具体见下表:
Buffer Usage Enum | 描述 |
---|---|
GL_STATIC_DRAW | 缓冲对象数据只会修改一次,使用多次,用来绘制图元或图像 |
GL_STATIC_READ | 修改一次,使用多次,用来从OpenGL ES读回数据,读回的数据将会由应用程序查询 |
GL_STATIC_COPY | 修改一次,使用多次,用来从OpenGL ES读回数据,读回的数据直接被用来作为绘制图元或图像的数据源 |
GL_DYNAMIC_DRAW | 缓冲对象数据将会被重复修改,并且使用多次来绘制图元或图像 |
GL_DYNAMIC_READ | 缓冲对象数据将会被重复修改,使用多次,用来从OpenGL ES读回数据,读回的数据将会由应用程序查询 |
GL_DYNAMIC_COPY | 缓冲对象数据将会被重复修改,使用多次,用来从OpenGL ES读回数据,读回的数据直接被用来作为绘制图元或图像的数据源 |
GL_STREAM_DRAW | 缓冲对象数据只会修改一次,只会使用少数几次,用来绘制图元或图像 |
GL_STREAM_READ | 修改一次,只会使用少数几次,用来从OpenGL ES读回数据,读回的数据将会由应用程序查询 |
GL_STREAM_COPY | 修改一次,只会使用少数几次,用来从OpenGL ES读回数据,读回的数据直接被用来作为绘制图元或图像的数据源 |
加载缓冲对象数据:
void glBufferData (GLenum target, GLsizeiptr size, const void * data, GLenum usage)
- target : 可取值为
GL_ARRAY_BUFFER
GL_ELEMENT_ARRAY_BUFFER
GL_COPY_READ_BUFFER
GL_COPY_WRITE_BUFFER
GL_PIXEL_PACK_BUFFER
GL_PIXEL_UNPACK_BUFFER
GL_TRANSFORM_FEEDBACK_BUFFER
GL_UNIFORM_BUFFER- size : 缓冲区数据储存大小,以字节数表示
- data : 要加载的数据
- usage : 对应用程序怎样使用缓冲对象数据的提示(上面介绍的GL_BUFFER_USAGE)
glBufferData根据size的值分配适合的数据储存区,如果data是一个有效的指针,则其指向的内容会被复制到分配的数据储存区中,如果data是一个NULL值,表示分配好的数据储存区不进行初始化。可以通过glBufferSubData进行数据初始化或者数据更新:
void glBufferSubData ()
- target : 可取值为
GL_ARRAY_BUFFER
GL_ELEMENT_ARRAY_BUFFER
GL_COPY_READ_BUFFER
GL_COPY_WRITE_BUFFER
GL_PIXEL_PACK_BUFFER
GL_PIXEL_UNPACK_BUFFER
GL_TRANSFORM_FEEDBACK_BUFFER
GL_UNIFORM_BUFFER- offset : 缓冲区数据储存的偏移
- size : 要修改的缓冲区数据储存大小,以字节数表示
- data : 要加载的数据
在使用glBufferData或glBufferSubData初始化或者更新缓冲对象数据后,客户端数据就不再需要了,可以释放。
缓冲对象使用完后,可以删除它们:
void glDeleteBuffers (GLsizei n, const GLuint * buffers)
- n : 要删除的缓冲对象的数量
- buffers : 指向包含要删除的缓冲对象的数组
一个缓冲对象被删除后,还可以作为一个新的缓冲对象储存新的数据重新使用。
网友评论