AKever

导航

OpenGL ES 3.0 VBO

OpenGL ES 3.0 VBO

 

创建VBO需要3个步骤:

1.使用glGenBuffers()生成新缓存对象。
2.使用glBindBuffer()绑定缓存对象。
3.使用glBufferData()将顶点数据拷贝到缓存对象中。
1. void glGenBuffers(GLsizei n, GLuint* buffers)
glGenBuffers()创建缓存对象并且返回缓存对象的标示符。它需要2个参数:第一个为需要创建的缓存数量,第二个为用于存储单一ID或多个ID的GLuint变量或数组的地址。

  2.void glBindBuffer(GLenum target, GLuint buffer)

a> target告诉VBO该缓存对象将保存顶点数组数据还是索引数组数据:GL_ARRAY_BUFFER或GL_ELEMENT_ARRAY。
b> 任何顶点属性,如顶点坐标、纹理坐标、法线与颜色分量数组都使用GL_ARRAY_BUFFER。
c> 用于glDraw[Range]Elements()的索引数据需要使用GL_ELEMENT_ARRAY绑定。
d> 注意,target标志帮助VBO确定缓存对象最有效的位置,如有些系统将索引保存AGP或系统内存中,将顶点保存在显卡内存中。

  3.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个枚举值:
  GL_STATIC_DRAW
  GL_STATIC_READ
  GL_STATIC_COPY
  GL_DYNAMIC_DRAW
  GL_DYNAMIC_READ
  GL_DYNAMIC_COPY
  GL_STREAM_DRAW
  GL_STREAM_READ
  GL_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内存,因为这样数据更易访问。

 4.void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);

与glBufferData()类似,glBufferSubData()用于向VBO中拷贝数据,不过它仅仅将从给定offset开始的一定范围的数据替换到现存缓存中。(在使用glBufferSubData()之前,整个缓存必须由glBufferData()指定。)

 5.void glDrawBuffers(GLsizei n, const GLenum* bufs);

在VBO不再使用时,你可以使用glDeleteBuffers()删除一个VBO或多个VBO。在混存对象删除之后,它的内容将丢失。

=======================================================

下列代码是为顶点坐标创建单一VBO的实例。

GLuint vboId;                              // VBO标示符
GLfloat* vertices = new GLfloat[vCount*3]; // 创建顶点数组
...

// 创建新的VBO并获取相关标示符
glGenBuffers(1, &vboId);

// 绑定VBO以待使用
glBindBuffer(GL_ARRAY_BUFFER_ARB, vboId);

// 更新数据到VBO
glBufferData(GL_ARRAY_BUFFER_ARB, dataSize, vertices, GL_STATIC_DRAW_ARB);

// 在拷贝数据到VBO之后,可以安全删除
delete [] vertices;
...

// 程序终止时删除VBO
glDeleteBuffers(1, &vboId);

绘制VBO

由于VBO基于现有的顶点数组实现之上,渲染VBO与使用顶点数组渲染几乎一致。仅有的不同是顶点数组指针现在作为当前绑定缓存对象的偏移值。因此,绘制VBO时除了glBindBuffer()之外不需别的API。

// 为顶点数组与索引数组绑定VBO
glBindBuffer(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);

更新VBO

VBO相对于显示列表的优势在于客户端可以读取与编辑缓存对象数据,而显示列表不能这样做。更新VBO的最简便方法是使用glBufferData()或glBufferSubData()将新数据重新拷贝到绑定的VBO中。这种情况下,你的应用程序需要始终拥有一个有效的顶点数组。也就是说,你必须始终拥有2份顶点数据:一份在应用程序中,另一份在VBO中。

修改缓存对象的另一个方式是将缓存对象映射到客户端内存,客户端可以使用映射缓存的指针更新数据。下文描述如何将VBO映射到客户端内存以及如何访问映射数据。

glMapBuffer()

VBO提供glMapBuffer()以将缓存对象绑定到客户端内存。

void* glMapBuffer(GLenum target, GLenum access);

如果OpenGL能够将缓存对象映射到客户端地址空间,glMapBuffer()返回指向缓存的指针。否则它返回NULL。

第一个参数target早在glBindBuffer()中涉及,第二个参数access标志指定怎样使用映射数据:读取、改写或两者都。

GL_READ_ONLY
GL_WRITE_ONLY
GL_READ_WRITE

原文:http://www.tuicool.com/articles/jMbyqyb

----- THE END!!

 

posted on 2015-09-24 00:15  AKever  阅读(431)  评论(0)    收藏  举报