Ditching Immediate Mode: OpenGL Vertex Buffer Objects
- 2
- Add a Comment
Yesterday, I wrote about using vertex arrays in OpenGL as a better alternative to the deprecated immediate mode. Today I will discuss a slightly more advanced topic, the Vertex Buffer Object (VBO). The process of using them is very similar to that of using vertex arrays, except you are storing the arrays in the GPU’s memory so that it can be accessed quickly when the GPU needs it, rather than sending it from your program to the GPU every time.
This tutorial will use the same arrays used in the vertex array tutorial, and will not use indicies either.
First things first, you have to create the buffers for your data.
GLuint vboId = 0; glGenBuffers(1, &vboId); glBindBuffer(GL_ARRAY_BUFFER, vboId); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) + sizeof(colors), NULL, GL_STATIC_DRAW);
If you look at the documentation for glBufferData, you will notice that the third argument is for specifying the pointer of the array. I have not done that here. Instead, I will be storing both the vertex and color arrays in the same VBO, which is why I gave the sum of the sizes of both arrays as the second argument, which is the size of the data the VBO will hold.
Next, we fill the VBO with our arrays.
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(colors), colors);
In the above code, the first call to glBufferSubData loads the vertex array into the VBO. Then, the second call loads the color array, offsetting it to the space after the vertex array.
Now it is time to draw the primitive.
glBindBuffer(GL_ARRAY_BUFFER, vboId); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(3, GL_FLOAT, 0, 0); glColorPointer(3, GL_FLOAT, 0, (GLvoid*)(12 * sizeof(GLfloat))); glDrawArrays(GL_LINE_LOOP, 0, 4); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0);
The first line above basically tells OpenGL to get the buffer ready to be read so that we can draw our primitive. The rest is pretty similar to the vertex array code, with the exception of a few things. In the glVertexPointer and glColorPointer calls, we no longer specify the array to be used in the final argument. Instead, we are specifying an offset so that OpenGL knows where in the VBO to look for the values. The vertices were placed in the beginning, so the offset is 0 in the glVertexPointer call. However, we specify an offset in the call to glColorPointer that is equal to the size of the vertex array we loaded, because we stored the color information immediately after the vertices. Then we draw, disable the states we enabled before, and the final line tells OpenGL to basically unbind the buffer, because leaving it bound can cause problems later in your program.
When you are finished with your program, you should delete any buffers you created.
glDeleteBuffers(1, &vboId);
Finally, here’s a performance tip, if you create a buffer, draw, and then delete that buffer on every iteration of your game loop, you will see serious slowdowns. Instead, create buffers before your game loop begins and delete them when you are sure you are done with them.



2 Comments
Peter
April 20th, 2011
at 5:51am
Excellent little tutorial. The clearest, cleanest, and most understandable VBO walkthrough I have found.
Kyle
January 16th, 2012
at 6:05pm
Y U NO USE GENERIC ATTRIBUTE FUNCTIONS