OpenGL vertex buffer object (VBO)
Related Topics:
Vertex array, display list,
Pixel Buffer object
Download:Vbo.zip,
Vbosimple.zip
- Creating VBO
- Drawing VBO
- Updating VBO
- Example
Gl_arb_vertex_buffer_objectExtension is intended to enhance the performance of OpenGL by providing the benefits
Vertex array and
Display list, while avoiding downsides of their implementations. vertex buffer object (VBO) allows vertex array data to be stored in high-performance graphics memory on the server side and promotes efficient data transfer. if the buffer object is used
Store pixel data, it is called
Pixel Buffer object (PBO ).
Using Vertex array can reduce the number of function CILS and redundant usage of the shared vertices. however, the disadvantage of vertex array is that vertex array functions are in the client state and the data in the arrays must be re-sent to the server
Each time when it is referenced.
On the other hand, display list is server side function, so it does not suffer from overhead of data transfer. but, once a display list is compiled, the data in the display list cannot be modified.
Vertex buffer object (VBO) creates"Buffer objects"For vertex attributes in high-performance memory on the server side and provides same access functions to reference the arrays, which are used in vertex arrays, such as glvertexpointer (), glnormalpointer (),
Gltexcoordpointer (), etc.
The memory manager in vertex buffer object will put the buffer objects into the best place of memory based on user's hints:
"Target"And"Usage"Mode. Therefore, the memory manager can optimize the buffers by balancing between 3 kinds of memory: system, AGP and video memory.
Unlike display lists, the data in vertex buffer object can be read and updated by mapping the buffer into client's memory space.
Another important advantage of VBO is sharing the buffer objects with specified clients, like display lists and textures. since VBO is on the server's side, multiple clients will be able to access the same buffer with the corresponding identifier.
Creating VBO
Creating a VBO requires 3 steps;
- Generate a new buffer objectGlgenbuffersarb ().
- Bind the buffer objectGlbindbufferarb ().
- Copy vertex data to the buffer objectGlbufferdataarb ().
Glgenbuffersarb ()
Glgenbuffersarb () creates buffer objects and returns the identifiers of the buffer objects. it requires 2 parameters: the first one is the number of buffer objects to create, and the second parameter is the address of a gluint variable
Or array to store a single ID or multiple IDs.
void glGenBuffersARB(GLsizei n, GLuint* ids)
Glbindbufferarb ()
Once the buffer object has been created, we need to hook the buffer object with the corresponding ID before using the buffer object. glbindbufferarb () takes 2 parameters:
TargetAndID.
void glBindBufferARB(GLenum target, GLuint id)
TargetIs a hint to tell VBO whether this buffer object will store vertex array data or index array data: gl_array_buffer_arb, or vertex. Any vertex attributes, such as vertex coordinates, texture coordinates,
Normals and color component arrays shocould use gl_array_buffer_arb. index array which is used for gldraw [range] elements () shocould be tied with gl_element_array_buffer_arb. Note that this
TargetFlag assists VBO to decide the most efficient locations of buffer objects, for example, some systems may prefer indices in AGP or system memory, and vertices in video memory.
Once glbindbufferarb () is first called, VBO initializes the buffer with a zero-sized memory buffer and set the initial VBO states, such as usage and access properties.
Glbufferdataarb ()
You can copy the data into the buffer object with glbufferdataarb () when the buffer has been initialized.
void glBufferDataARB(GLenum target, GLsizei size, const void* data, GLenum usage)
Again, the first parameter,TargetWocould be gl_array_buffer_arb or gl_element_array_buffer_arb.
SizeIs the number of bytes of data to transfer. The third parameter is the pointer to the array of source data. If
DataIs null pointer, then VBO reserves only memory space with the given data size. The last parameter,
"Usage"Flag is another performance hint for VBO to provide how the buffer object is going to be used:
Static,DynamicOrStream, AndRead,CopyOr
Draw.
VBO specifies 9 enumerated valuesUsageFlags;
GL_STATIC_DRAW_ARBGL_STATIC_READ_ARBGL_STATIC_COPY_ARBGL_DYNAMIC_DRAW_ARBGL_DYNAMIC_READ_ARBGL_DYNAMIC_COPY_ARBGL_STREAM_DRAW_ARBGL_STREAM_READ_ARBGL_STREAM_COPY_ARB
"Static"Means the data in VBO will not be changed (specified once and used same times ),
"Dynamic"Means the data will be changed frequently (specified and used repeatedly), and
"Stream"Means the data will be changed every frame (specified once and used once ).
"Draw"Means the data will be sent to GPU in order to draw (application to GL ),
"Read"Means the data will be read by the client's application (GL to application), and
"Copy"Means the data will be used both drawing and reading (GL to GL ).
Note that onlyDrawToken is useful for VBO, and
CopyAndReadToken will be become meaningful only for Pixel/Frame Buffer object (PBO or
FBO ).
VBO Memory Manager will choose the best memory places for the buffer object based on these usage flags, for example, memory and gl_stream_draw_arb may use video memory, and gl_dynamic_draw_arb may use AGP memory. Any
_ Read _ related buffers wocould be fine in system or AGP memory because the data shocould be easy to access.
Glbuffersubdataarb ()
void glBufferSubDataARB(GLenum target, GLint offset, GLsizei size, void* data)
Like glbufferdataarb (), glbuffersubdataarb () is used to copy data into VBO, but it only replaces a range of data
The existing buffer, Starting from the given offset. (The total size of the buffer must be set by glbufferdataarb () before using glbuffersubdataarb ().)
Gldeletebuffersarb ()
void glDeleteBuffersARB(GLsizei n, const GLuint* ids)
You can delete a single VBO or multiple VBOs with gldeletebuffersarb () if they are not used anymore. After a buffer object is deleted, its contents will be lost.
The following code is an example of creating a single VBO for vertex coordinates. notice that you can delete the memory allocation for vertex array in your application after you copy data into VBO.
GLuint vboId; // ID of VBOGLfloat* vertices = new GLfloat[vCount*3]; // create vertex array...// generate a new VBO and get the associated IDglGenBuffersARB(1, &vboId);// bind VBO in order to useglBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId);// upload data to VBOglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, vertices, GL_STATIC_DRAW_ARB);// it is safe to delete after copying data to VBOdelete [] vertices;...// delete VBO when program terminatedglDeleteBuffersARB(1, &vboId);
Drawing VBO
Because VBO sits on top of the existing vertex array implementation, rendering VBO is almost same as using
Vertex array. only difference is that the pointer to the vertex array is now as an offset into a currently bound buffer object. therefore, no additional APIs are required to draw a VBO blocks t glbindbufferarb ().
// bind VBOs for vertex array and index arrayglBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId1); // for vertex coordinatesglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vboId2); // for indices// do same as vertex array except pointerglEnableClientState(GL_VERTEX_ARRAY); // activate vertex coords arrayglVertexPointer(3, GL_FLOAT, 0, 0); // last param is offset, not ptr// draw 6 quads using offset of index arrayglDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, 0);glDisableClientState(GL_VERTEX_ARRAY); // deactivate vertex array// bind with 0, so, switch back to normal pointer operationglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
Binding the buffer object with 0 switchs off VBO operation. It is a good idea to turn VBO off after use, so normal vertex Array Operations with absolute pointers will be re-activated.
Updating VBO
The advantage of VBO over
Display list is the client can read and modify the buffer object data, but display list cannot. the simplest method of updating VBO is copying again new data into the bound VBO with glbufferdataarb () or glbuffersubdataarb (). for this case, your application
Shocould have a valid vertex array all the time in your application. That means that you must always have 2 copies of vertex data: one in your application and the other in VBO.
The other way to modify buffer object is to map the buffer object into client's memory, and the client can update data with the pointer to the mapped buffer. the following describes how to map VBO into client's memory and how to access the mapped data.
Glmapbufferarb ()
VBO provides glmapbufferarb () in order to map the buffer object into client's memory.
void* glMapBufferARB(GLenum target, GLenum access)
If OpenGL is able to map the buffer object into client's address space, glmapbufferarb () returns the pointer to the buffer. Otherwise it returns NULL.
The first parameter,TargetIs mentioned earlier at glbindbufferarb () and the second parameter,
AccessFlag specifies what to do with the mapped data: read, write or both.
GL_READ_ONLY_ARBGL_WRITE_ONLY_ARBGL_READ_WRITE_ARB
Note that glmapbufferarb () causes a synchronizing issue. If the GPU is still working with the buffer object, glmapbufferarb () will not return until GPU finishes its job with the corresponding buffer object.
To avoid waiting (idle), you can call first glbufferdataarb () with NULL pointer, then call glmapbufferarb (). in this case, the previous data will be discarded and glmapbufferarb () returns a new allocated pointer immediately even
If GPU is still working with the previous data.
However, this method is valid only if you want to update entire data set because you discard the previous data. if you want to change only portion of data or to read data, you better not release the previous data.
Glunmapbufferarb ()
GLboolean glUnmapBufferARB(GLenum target)
After modifying the data of VBO, it must be unmapped the buffer object from the client's memory. glunmapbufferarb () returns gl_true if success. when it returns gl_false, the contents of VBO become upted while the buffer was mapped.
The specified uption results from screen resolution change or window system specific events. In this case, the data must be resubmitted.
Here is a sample code to modify VBO with mapping method.
// bind then map the VBOglBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId);float* ptr = (float*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);// if the pointer is valid(mapped), update VBOif(ptr){ updateMyVBO(ptr, ...); // modify buffer data glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); // unmap it after use}// you can draw the updated VBO...
Example
This demo application makes a VBO wobbling in and out along normals. it maps a VBO and updates its vertices every frame with the pointer to the mapped buffer. you can compare the specified mace with a traditional vertex array implementation.
It uses 2 Vertex buffers; one for both vertex coords and normals, And the other stores index array only.
Download the source and binary:
Vbo.zip, vbosimple.zip.
Vbosimple is a very simple example to draw a cube using VBO and
Vertex array. You can easily see what is common and what is different between VBO and VA.
I also include a makefile (makefile. Linux) for Linux System inSRCFolder, so you can build an executable on your Linux box, for example:
> make -f Makefile.linux