Related topics: vertex arrays, display lists, pixel buffer objects
Download: Vbo.zip, Vbosimple.zip
Create VBO to draw VBO Update Vbo Example
The Gl_arb_vertex_buffer_object extension improves OpenGL performance by providing the advantages of vertex arrays and display lists and avoiding their shortcomings. The vertex buffer object (vertex buffer object,vbo) allows the vertex array to be stored in high-performance graphics memory located on the server side, and improves the efficiency of data transfer. If the buffer object is used to store pixel data, it is called a pixel buffer object (PBO).
Using vertex data can reduce the number of function calls and redundant use of shared vertices, but the disadvantage of vertex arrays is that the functions in the vertex array are in the client and the data in the array needs to be sent to the server side each time it is referenced.
Instead, the display list is on the server side, so it doesn't have to endure the overhead of data transfer. However, when a display list is compiled, the data displayed in the table can no longer be modified.
The vertex buffer object (VBO) creates a "buffer object" for the vertex attribute in high-performance memory on the server side, and provides functions to refer to the array used in the vertex array, such as Glvertexpointer (), Glnormalpointer (), Gltexcoordpointer () and so on.
Memory management in a vertex buffer object (VBO) places the buffer object in the most appropriate place in memory based on the user-defined target and usage modes. Therefore, memory management optimizes buffers by coordinating in 3 of different memory (system memory, AGP, video card memory).
Unlike a display list, data in a vertex buffer that is mapped to a client's memory region can be read or updated by the buffer.
Another advantage of vertex buffer objects (VBO) is that buffer objects can be shared by multiple clients, such as displaying lists and textures. Because the vertex buffer object (VBO) is located on the server side, multiple clients can access the same buffer using the associated identifier.
Create Vbo
Creating a VBO requires 3 steps: Using Glgenbuffersarb () to generate a buffer object, binding a buffer object with Glbindbufferarb (), and using Glbufferdataarb () to copy the vertex data into the buffer object.
Glgenbuffersarb () Glgenbuffersarb () creates a buffer object and returns the label of the buffer object. It requires two parameters: the first parameter indicates the number of buffer objects to be created, and the second parameter indicates the address of the Gluint type variable or array that returns one or more buffers marked.
<span style= "White-space:pre" > </span>void glgenbuffersarb (glsizei N, gluint* IDs)
Glbindbufferarb () When the buffer object is created, we need to bind the buffer object before using the buffer object. Glbindbufferarb () requires two parameters: Target and ID.
<span style= "White-space:pre" > </span>void glbindbufferarb (glenum target, gluint ID)
Target tells Vbo whether this buffer object is used to store vertex array data or to store indexed array data: Gl_array_buffer_arb or Gl_element_array_buffer_arb. Any vertex attributes, such as vertex coordinates, texture coordinates, normal vectors, and color information, need to use Gl_array_buffer_arb as the target. An indexed array, like the gldraw[range]elements () function, needs to be bound to Gl_element_array_buffer_arb. Note that this target flag helps VBO determine the best location for vertex buffers, for example, some systems will place the index array in AGP or system memory, and the vertex array in the graphics card memory.
When Glbindbufferarb () is first called, VBO initializes the buffer with a memory area of size 0 and sets the initial state of the VBO, such as usage and access properties.
Glbufferdataarb () You can use Glbufferdataarb () to copy the array into the buffer object after the buffer is initialized.
<span style= "White-space:pre" > </span>void glbufferdataarb (glenum target, Glsizei size, const void* Data, Glenum usage)
The first parameter of the target may be gl_array_buffer_arb or Gl_element_array_buffer_arb. Size is the number of bytes of data that will be transferred. The 3rd parameter is a pointer to the data source, and if the pointer is null, VBO will retain only the specified size of storage space. The last parameter usage is a performance parameter in another VBO that indicates how the buffer will be used, static (static), dynamic (active), stream (stream), read (read), copy (copy), Draw (draw).
VBO Specifies the value of the enumeration in 9 for the usage flag:
Gl_static_draw_arb
gl_static_read_arb
gl_static_copy_arb
gl_dynamic_draw_arb
gl_dynamic_read_ ARB
gl_dynamic_copy_arb
gl_stream_draw_arb
gl_stream_read_arb
Gl_stream_copy_arb
"Static" means that the data in VBO cannot be changed (specified once using multiple times), "dynamic" means that the data will be changed frequently (specified multiple times), "stream" means that the data is changed in each frame (specified once used). "Draw" means that data is transferred to GPU rendering (from application to OpenGL), "read" means that the data is read by the client's application (from OpenGL to the application), and "copy0" means that it can be used both for "draw" and "read".
Note that only the "draw" flag can be used by VBO, and the "copy" and "read" markers are meaningful to the pixel buffer object (PBO) and the frame buffer object (FBO).
VBO memory Management selects the most appropriate memory location for the buffer object based on the value of usage, for example, Gl_static_draw_arb and Gl_stream_draw_arb will select the video card memory, Gl_dynamic_draw_ The ARB will select AGP memory. Any buffer associated with _READ_ can use either system memory or AGP memory because the data should be easily accessible.
Glbuffersubdataarb ()
<span style= "White-space:pre" > </span>void glbuffersubdataarb (glenum target, glint offset, GLsizei Size, void* data)
Similar to Glbufferdataarb (), Glbuffersubdataarb () is used to copy data into VBO, but it only copies part of the data into the buffer that already exists, starting at the given offset. (The total size of the buffer must be set using the Glbufferdataarb () before using Glbuffersubdataarb ())
Gldeletebuffersarb ()
<span style= "White-space:pre" > </span>void gldeletebuffersarb (glsizei N, const gluint* IDs)
You can use the Gldeletebuffersarb () function to delete one or more vbo that are no longer in use. When the buffer object is deleted, its contents are lost.
The following code is an example of creating a simple vertex buffer object (VBO) for vertex coordinates. Note that when you copy all the data into VBO, you can delete the memory allocated for the vertex array in your application.
Gluint vboid; VBO ID
glfloat* vertices = new glfloat[vcount*3];//create vertex array ...
Generates a new vertex buffer object and gets the associated ID
glgenbuffersarb (1, &vboid);
Bind vertex Buffer object
glbindbufferarb (Gl_array_buffer_arb, vboid);
Copy the data into the vertex buffer object
glbufferdataarb (Gl_array_buffer_arb, datasize, vertices, gl_static_draw_arb);
After copying the data into the vertex buffer object, you can delete the vertex array.
delete [] vertices;
...
Delete Vertex buffer object When program terminates
Gldeletebuffersarb (1, &vboid);
Draw Vbo
Because VBO is implemented based on vertex arrays, rendering Vbo is similar to using vertex arrays. The only difference is that the pointer to the vertex data now becomes the offset to the buffer object that is now bound. Therefore, there is no need for additional APIs to draw Vbo other than Glbindbufferarb ().
Binds a vertex array and an indexed array Vbo
glbindbufferarb (Gl_array_buffer_arb, vboId1); For the vertex array
glbindbufferarb (Gl_element_array_buffer_arb, VBOID2);//for indexed arrays
//Except pointers are different from other and vertex array operations
Glenableclientstate (Gl_vertex_array); Activates the vertex array
glvertexpointer (3, gl_float, 0, 0); The last parameter is offset
//using the offset value of the indexed array to draw 6 polygons
gldrawelements (gl_quads, gl_unsigned_byte, 0);
Gldisableclientstate (Gl_vertex_array); Disables the vertex array
//binding 0, which returns to the normal pointer operation
Glbindbufferarb (Gl_array_buffer_arb, 0);
Glbindbufferarb (Gl_element_array_buffer_arb, 0);
The last row of the buffer object bound to 0 closes the VBO operation. This is a good way to close vbo with VBO, so that normal vertex array operations will be activated again.
Update Vbo
The advantage of VBO compared to the display list is that the client can read and change the data in the buffer object, and the display list cannot. The simplest way to update the data in VBO is to use the Glbufferdataarb () or Glbuffersubdataarb () function to copy the data over and over again into the vbo you are binding. In this case, your application needs to have a valid vertex array all the time. This means that you need to have two copies of the vertex array: one in your application and the other in Vbo.
Another way to modify a buffer object is to map the buffer object to client memory, and then the client can update the data using pointers to maps to buffers. The following shows how to map a VBO to client memory and how to access the mapped data.
Glmapbufferarb () Vbo uses Glmapbufferarb () to map the buffer object to client memory.
<span style= "White-space:pre" > </span>void* glmapbufferarb (glenum target, glenum access)
If OpenGL can map the buffer to the client's memory, Glmapbufferarb () returns a pointer to the buffer, otherwise null is returned.
The first parameter, the target and the above Glbindbufferarb (), the second parameter access specifies the operation of the mapped data: Read, write, or read and write.
Gl_read_only_arb
Gl_write_only_arb
Gl_read_write_arb
Note Glmapbufferarb () will cause a synchronization problem. If the GPU is still working in the vertex buffer, then the Glmapbufferarb () function will return after the GPU finishes working on the specified buffer.
To avoid waiting, you can first call the Glbufferdataarb () function with a null pointer and then call Glmapbufferarb (). In this case, the previous data will be discarded, and Glmapbufferarb () will immediately return a pointer to the newly allocated area, even though the GPU is still working on the previous data.
However, this approach works only if you need to update the entire data set, because it will discard the previous data. If you just want to change part of the data or just want to read the data, you'd better not discard the previous data.
Glunmapbufferarb ()
<span style= "White-space:pre" > </span>glboolean glunmapbufferarb (glenum target)
After modifying the VBO data, the mapping of the buffer object and the client memory must be removed. Glunmapbufferarb () will return gl_true if successful. When it returns GL_FALSE, the contents of Vbo are destroyed. The cause of the damage is the change in window resolution or the time of the system. In this case, the data needs to be resubmitted.
Here is an example of modifying VBO using a mapping method:
Bind and Map Vbo
Glbindbufferarb (Gl_array_buffer_arb, vboid);
float* ptr = (float*) glmapbufferarb (Gl_array_buffer_arb, gl_write_only_arb);
If the mapping succeeds, update Vbo
if (PTR)
{
Updatemyvbo (ptr, ...); Modify buffer Data
Glunmapbufferarb (GL_ARRAY_BUFFER_ARB);//de-map
}
//Use new VBO drawing
...
Example
This example causes the VBO to oscillate along the normal vector, which maps the VBO to the client and changes in each frame. You can compare it with traditional vertex arrays in a way that compares performance.
It uses two vertex buffers: one for vertex coordinates and normal vectors, and the other for storing indexes.
Download source and executable files: Vbo.zip, Vbosimple.zip
Vbosimple is a very simple example of drawing cubes using VBO and vertex arrays. You can easily see the similarities and differences between vertex arrays and VBO.
I also have the Makefile file (makefile.linux) running under Linux under the SRC folder, and you can also build the executable file under Linux using the following method:
<span style= "White-space:pre" > </span>make-f makefile.linux