How to use a VBO

I’m trying really hard to understand this, but some of the code I don’t understand.

First off, to my understanding, this just creates the points for the triangle.

FloatBuffer vertexData = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
        vertexData.put(new float[]{-0.5f, -0.5f, 0, 0.5f, -0.5f, 0, 0.5f, 0.5f, 0});
        vertexData.flip();

Now this here would initialize it?

int vboVertexHandle = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
        glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

and under my gameloop this would bind/draw the triangle?

glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
            glVertexPointer(vertexSize, GL_FLOAT, 0, 0L);

I think this just tells you it’s a triangle.

       glEnableClientState(GL_VERTEX_ARRAY);
            glEnableClientState(GL_COLOR_ARRAY);
            glDrawArrays(GL_TRIANGLES, 0, amountOfVertices);
            glDisableClientState(GL_COLOR_ARRAY);
            glDisableClientState(GL_VERTEX_ARRAY);

As you can see, I’m not so knowledgable on VBOs. Can i get some explanation or a link to a good in depth tutorial for this?

For VBOs:

Generate an ID for the VBO:

int ID = 0;
IntBuffer buffer = BufferUtils.createIntBuffer(1);
ARBVertexBufferObject.glGenBuffersARB(buffer);
ID = buffer.get(0);

Put Coordinates into Buffer:

FloatBuffer buffer = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
buffer.put(new float[]{-0.5f, -0.5f, 0, 0.5f, -0.5f, 0, 0.5f, 0.5f, 0});
buffer.flip();

Connect Generated ID with Buffer that stores Coordinates:

ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, ID);
ARBVertexBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, buffer,ARBVertexBufferObject.GL_STATIC_DRAW_ARB);

And finally, for Drawing:

GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); 
ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, ID);
GL11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0);// The 3 stands for each vertex having 3 parts (x y and z) for colors for example it has 4, r g b and a
GL12.glDrawRangeElements(GL11.GL_TRIANGLES, 0, length, length,GL11.GL_UNSIGNED_INT, 0); // So it Renders Triangles, could render Quads too etc. I guess, never tested it
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);

I think you would need an Index Buffer aswell and “length” stands for the length of the index Buffer :slight_smile: those are some snippets from my code

Your computer contains a CPU and a GPU. Just for simplicity, you can think that the CPU and the GPU has their own memory. In other words The GPU can’t directly access memory in your CPU and visa-versa. However, you can send data to the GPU to have it render. One way to do this is to send all your vertices on every single draw call and have the GPU do the rest. This mode of rendering was useful years ago when GPUs were not the powerful beasts they are today. It is known as immediate mode rendering.

Now a more sensical way to go about this problem is to create a place where you can save the data in the GPU, so you don’t have to send it every single frame. This memory in the GPU (or in anything in that case) is called a buffer.

Now in C and other system languages you deal with memory a lot more directly and there is no JVM and other things moving things around and doing weird stuff with your data. In Java we have another step in VBO rendering. We make a FloatBuffer, (a buffer on the CPU), and store our data inside it. Now think of your memory as a strip of paper, and the computer memory writer as the head of a printer. Now as the “printer puts data on the paper” the head moves away from the beginning of the data. We need to move the head back to the beggining of the data so that we can specify where the data starts. One call to do that is flip the other is reverse. They both work in this case (but they do have a difference in other cases).

Ok, so we have made our FloatBuffer on the CPU now we have to make our Buffer on the GPU.
This is just a simple glGenBuffers. The “handle” is like the address on the GPU where it resides.

OpenGL is a state based api. A state is like a characteristic or a variable in an object. There can only be one “state” binded to a characteristic at a time. One of these variables in OpenGL is GL_ARRAY_BUFFER, this is just characteristic that explains which VBO is currently being used at the time. You can only have one binded at the time.

So I have a buffer on my CPU and GPU, but the data is only on the CPU. I have to copy my data into the data on the GPU. So first i bind the buffer to tell OpenGL that I am going to make changes to the buffer. Next I send my data over using a glBufferData call.

Cool now i have lots of random 1s and 0s on the GPU, this isn’t that useful without explaining to the GPU what these 1s and 0s mean. This is pretty much the part where i turn my Buffer into a Vertex Buffer Object.

I use glVertexPointer, glColorPointer, etc. to explain to the GPU which 1’s and 0’s mean what. I point to which pieces of the buffer are vertices, colors, texture coords, etc.

Ok, so our VBO is set, The GPU has it’s data and an explanation of what every piece means. Now we can run a draw call (with the buffer binded) and openGL will draw whatever we want.

Remember the state things I was talking about earlier. There are a couple “client states” that openGL also has. This states simply tell OpenGL what pieces of data to use when rendering. Should it ignore the color values, or use them. ETC. If not specified it ignores it.

I think I got the majority of it.

Lots of this is metaphorical (aka. not what “actually” happens), but hopefully it will make it much easier for you to visualize.

@Seiya02 What’s the point of ID?

@The Lion King Great, in depth explanation. I’m still pretty lost. Any visuals?

EDIT: I’m learning based off of Oskar Veerhoaks’ tutorial:

 public static void main(String[] args) {
        try {
            Display.setDisplayMode(new DisplayMode(640, 480));
            Display.setTitle("Vertex Buffer Object Demo");
            Display.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
            Display.destroy();
            System.exit(1);
        }

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(1, -1, 1, -1, 1, -1);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        final int amountOfVertices = 3;
        final int vertexSize = 3;
        final int colorSize = 3;

        FloatBuffer vertexData = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
        vertexData.put(new float[]{-0.5f, -0.5f, 0, 0.5f, -0.5f, 0, 0.5f, 0.5f, 0});
        vertexData.flip();

        FloatBuffer colorData = BufferUtils.createFloatBuffer(amountOfVertices * colorSize);
        colorData.put(new float[]{1, 0, 0, 0, 1, 0, 0, 0, 1});
        colorData.flip();

        int vboVertexHandle = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
        glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        int vboColorHandle = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle);
        glBufferData(GL_ARRAY_BUFFER, colorData, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        while (!Display.isCloseRequested()) {
            glClear(GL_COLOR_BUFFER_BIT);

            
            //to load a texture, create it then do this
            //glBindTexture(GL_TEXTURE_2D, nameoftexture.getTextureID());
            
            
            glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
            glVertexPointer(vertexSize, GL_FLOAT, 0, 0L);

            glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle);
            glColorPointer(colorSize, GL_FLOAT, 0, 0L);
            
            
            glEnableClientState(GL_VERTEX_ARRAY);
            glEnableClientState(GL_COLOR_ARRAY);
            glDrawArrays(GL_TRIANGLES, 0, amountOfVertices);
            glDisableClientState(GL_COLOR_ARRAY);
            glDisableClientState(GL_VERTEX_ARRAY);

            Display.update();
            Display.sync(60);
        }

        glDeleteBuffers(vboVertexHandle);
        glDeleteBuffers(vboColorHandle);

        Display.destroy();
        System.exit(0);
    }
}

No visuals on hand, I could probably draw some up with paint and edit the post tomorrow. Post any specific questions if you have them though.

Okay, I’ll piece by piece. First off

 final int amountOfVertices = 3; //do I just make this 4 if I want a
        final int vertexSize = 3;    //quad/
        final int colorSize = 3;

        FloatBuffer vertexData = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
        vertexData.put(new float[]{-0.5f, -0.5f, 0, 0.5f, -0.5f, 0, 0.5f, 0.5f, 0});
        vertexData.flip();

What exactly are these methods supposed to do? Do they initialize how your going to draw things? If I made a second shape or made a quad, would these change in any way?

  int vboVertexHandle = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
        glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

Since this is in the game loop, and this gets called every frame, does this actually draw it?

glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
            glVertexPointer(vertexSize, GL_FLOAT, 0, 0L);

Since this gets enabled and then disabled, does this draw it?

glEnableClientState(GL_VERTEX_ARRAY);
            glEnableClientState(GL_COLOR_ARRAY);
            glDrawArrays(GL_TRIANGLES, 0, amountOfVertices);
            glDisableClientState(GL_COLOR_ARRAY);
            glDisableClientState(GL_VERTEX_ARRAY);

First one builds the Data Buffer holding your data on the CPU.

The second one builds a buffer on the GPU and move your data from the CPU to the GPU.

The 3rd one tells the GPU which piece of the data is the vertices, colors, etc.

The 4th one tells the GPU to use the vertices and colors from the data in the buffer to draw triangles

I sort of got the hang of this(after 5 hours of struggly literally!). So, if I wanted to create another triangle I would make another FloatBuffer and a copy of everything?

I give up on VBOs :cranky:. I wasted almost 10 hours whatching the same video and doing research. Appearently I can only render one thing with VBO. I tried rearanging things as much as I could. It’s driving me insane! I tried initializing everything for a second triangle, but it doesn’t appear. >:(

put the extra data in the FloatBuffer, put that extra data into the VBO, change the length in verticies of the glDrawArrays call, that should be it I believe

Wouldn’t this just connect to the first triangle? I want to draw a second one to ensure my knowledge.

Just use Immediate mode. Much better no matter how old :stuck_out_tongue:


glDrawArrays(GL_TRIANGLES, 0, 3); //Draw triangle 1 in the VBO
glDrawArrays(GL_TRIANGLES, 3, 3); //Draw triangle 2 in the VBO

If you have multiple VBOs, you need to set up the vertex attribute pointers correctly every time you want to switch between VBOs so OpenGL reads from the correct one.

Immediate mode is deprecated for a reason.

No, its like sprite batching you send it the data for all the traingles and call glDrawArrays once. It will draw all the triangles seperate, unless you use triangle strips in which case they are attached

Do I have to create a whole float buffere and vboHandler in order to use glDrawArrays to make another triangle?

No, that’s what we’re trying to tell you. If you’re using GL_TRIANGLES, then it will draw a completely separate triangle if you just supply the necessary vertices.

Wait, is this your question? http://gamedev.stackexchange.com/questions/77622/using-vbos-for-the-begginer

So for the first triangle I would do this In my loop:

glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
            glVertexPointer(vertexSize, GL_FLOAT, 0, 0L);


            glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle);
            glColorPointer(colorSize, GL_FLOAT, 0, 0L);


            glEnableClientState(GL_VERTEX_ARRAY);
            glEnableClientState(GL_COLOR_ARRAY);
            glDrawArrays(GL_TRIANGLES, 0, amountOfVertices);
            glDisableClientState(GL_COLOR_ARRAY);
            glDisableClientState(GL_VERTEX_ARRAY);

Then In the second one:

glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle2);
            glVertexPointer(vertexSize, GL_FLOAT, 0, 0L);


            glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle2);
            glColorPointer(colorSize, GL_FLOAT, 0, 0L);


            glEnableClientState(GL_VERTEX_ARRAY);
            glEnableClientState(GL_COLOR_ARRAY);
            glDrawArrays(GL_TRIANGLES, 0, amountOfVertices);
            glDisableClientState(GL_COLOR_ARRAY);
            glDisableClientState(GL_VERTEX_ARRAY);

Would it require a second handler?

Yeah, I’m trying hard to understand this. Thanks for your website, I forgot about it.

If anyone could explain visually, I could really use the help.

Skype: minecraft13jay

You don’t need a separate handle.

Just add more vertices in your float array.


// You will have to play around with the vertices
new float[]{-0.5f, -0.5f, 0, 0.5f, -0.5f, 0, 0.5f, 0.5f, 0/*end of first triangle*/, -0.75f, -0.75f, 0, 0.75f, -0.75f, 0, 0f, 0f, 0}

Every vertex has a color, so you would add more colors.

new float[]{1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1}

You will also have to change [icode]amountOfVertices[/icode] to match how many vertices you have.