Vertex Buffer Object
|
关于GL_ARB_vertex_buffer_object扩展<转> 没有这个扩展的时候,偶们用vertex array时,用glVertexPointer / glNormalPointer 来指定顶点数据,这时顶点数据是放在系统内存中的,每次渲染时,都要把数据从系统内存拷贝到显存,消耗不少时间。 实际上很多拷贝都是不必要的,比如静态对象的顶点数据是不变的,如果能把它们放到显存里面,那么每次渲染时都不需要拷贝操作,可以节约不少时间。 另外现在的显卡大多数是AGP的,系统会在系统内存中开辟一块区域作为AGP内存,显卡可以通过DMA来直接访问AGP内存,把数据传到显卡,速度很快,并且在传数据时不需要CPU干涉,显卡可以和CPU并行运算。我们可以把一些动态对象的顶点数据放在AGP内存中,更新对象顶点数据后能利用AGP的快速传输能力,把数据传到显卡,这样比从系统内存传到显存要快。 GL_ARB_vertex_buffer_object的使用很简单,和纹理的用法有点相近,下面几个函数和纹理的函数很相近: 值得注意的是glBufferDataARB的最后一个参数usage,它有如下取值: glBindBufferARB GL_STREAM_DRAW_ARB 其中: STREAM表示只赋一次值,只用一次或很少的几次,这部种数据很可能放在系统内存中 STATIC表示只赋一次值,重复使用很多次,这种数据很可能放在显存中 DYNAMIC表示多次赋值,重复使用,这种数据很可能放在AGP内存中 DRAW 表示赋给buffer object的数据来自用户程序,buffer object作为绘制函数的数据源 COPY 表示赋给buffer object的数据来自OpenGL,buffer object作为绘制函数的数据源 READ 表示赋给buffer object的数据来自OpenGL,buffer object作为用户程序的数据源 目前只有DRAW有意义。 驱动程序会以usage为参考,根据多种条件决定是把数据放在显存、AGP内存还是系统内存中。比如如果还有足够的空余显存,usage指定为GL_STATIC_DRAW_ARB时,数据会被放在显存中,而如果空间不够,就会被放到AGP或系统内存中。 一种是通过glBufferDataARB/glBufferSubDataARB函数指定数据 另一种是通过glMapBufferARB获得修改数据的指针,通过指针修改数据,修改完成后通过glUnmapBufferARB来提交数据 Vertex arrays using a mapped buffer object for array data and an // Create system memory buffer for indices // Fill system memory buffer with 100 indices // GL_ELEMENT_ARRAY_BUFFER_ARB // Define arrays (and create buffer object in first pass) // Enable arrays // Initialize data store of buffer object // Map the buffer object // 用指针p修改顶点和颜色数据 // Unmap buffer object and draw arrays // Disable arrays // Other rendering commands… // Delete buffer objects 演示程序(vbo.zip,40.8KB) 程序是针对32M显存的,程序中一个buffer object大概占1M字节,如果是更大的显存,可以把MAX_BUFFER改大。 |
补充:来自opengl programming guide 6th Edition
利用这项技术,可以将一些固定的数据存放在 opengl 的 server 端(我觉得可以理解为显存),这样就不用在每次调用时将数据从 client 端(可以理解为内存)传到 server 端。 Opengl 被设计为 client-server 的调用模式。在 1.5 以前的版本中,数据一般都存放在 client 端,在需要时才从 client 端拷贝到 server 端。 Buffer objects 是在 1.5 版本中被加入到 opengl 的标准中。
Buffer objects 的创建与纹理对象比较类似 .
首先是调用函数: glGenBuffers (GLsizei n, GLuint* buffers); 该函数的作用是让 opengl 来自动返回 n 个未被使用的 buffer objects 名字,名字是正整数,存放在缓存 buffers 中。 0 是默认的被保留的名字,不会被返回。
然后需要调用函数: glBindBuffer(GLenum target, GLuint buffer) 来激活某个 buffers objects 。和纹理对象类似,该函数也可以做三件事情。当 buffer 对应的名字第一次被绑定时,该函数就会生成一个新的 buffer objects 。如果不是第一次调用,那么就激活名字对应的对象。如果是名字是 0 ,那么就停止使用 buffer objects 。 Target 的取值可以是下面的某个:
GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER 。
接着就要调用函数: glBufferData(GLenum target, GLsizeipter size, const GLvoid* data, GLenum usage) 来存储数据。 Target 指定 buffer object 对应的目标,取值和上面一致。 Size 是在 server 端分配的存储空间的大小(一般以 byte 为基准), data 是 client 端的数据指针,如果为 NULL ,那么就不进行初始化,后续动态的进行更新。 Usage 表示该存储块如何被使用和更新。
Buffer objet 的更新方法:
1 、调用函数: glBufferSubData(GLenum target, GLintpter offset, GLsizeipter size, const void* data) 。该函数用 data[offset-1] - data[offset+size-1] 这段数据来对绑定到 target 上的 buffer object 进行更新。
2 、调用函数: GLvoid* glMapBuffer(GLenum target, GLenum access) 。该函数可以返回一个指针,指针和 target 的数据块对应,对指针对应的地址进行操作就可以修改 target 数据,进而修改绑定到 target 的 buffer object 。这种方法更加的灵活。
标签:OpenGL, Vertex Buffer Object相关日志
If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.
