# VBO help

This topic is 2708 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi!
I've been trying to understand VBO's and I actually thought that I did, but it seems I still have questions.

I'm loading an OBJ-file to vectors and then use that information to load up buffers of different kinds (normals, texcoords ...).
At the moment I've restricted myself to just vertex positions and the indices of these.
Please let me know if I understand this correctly:
glGenBuffers(1, &vboID[0]); // generates a buffer in slot 0 glBindBuffer(GL_ARRAY_BUFFER, vboID[0]); // binds the buffer as an ARRAY_BUFFER glBufferData(GL_ARRAY_BUFFER, sizeof(float)*vertices.size(), NULL, GL_STATIC_DRAW); // describes what I want to do with the buffer and the size of it glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*vertices.size(), &vertices[0]); // loads the buffer with data from the vertices vector with starting position 0 in the array

After I've done this, I do the same with the indices but at slot 0:
glGenBuffers(1, &vboID[1]); // generates a buffer in slot 1 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID[1]); // binds the buffer as an ELEMENT_ARRAY_BUFFER glBufferData(GL_ELEMENT_ARRAY_BUFFER, ((int)(vFaces.size()) * sizeof(float)), &(vFaces.at(0)), GL_STATIC_DRAW); // loads the buffer with data from the vFaces vector with starting position 0 in the array as well as setting the size of the buffer

After that, I try to draw the model with a "glDrawElements" call (after creating an "earth" object):
glDrawElements(GL_TRIANGLES, sizeof(earth.vFaces), GL_UNSIGNED_INT, &earth.vFaces.at(0));

This gives me absolutely nothing.
When I try to activate and use a VAO then the screen flickers, the graphics driver resets and the program crashes.

What is it that I'm not getting?
The questions that I'm thinking of is how do the program know which VBO to use as a reference for the index VBO? And how does it know the difference between a VBO containing vertex positions and one containing, for example normals?

Thanks for taking the time!
Marcus

##### Share on other sites
glDrawElements(GL_TRIANGLES, sizeof(earth.vFaces), GL_UNSIGNED_INT, &earth.vFaces.at(0));

It should (I think) be earth.vFaces *3 as you are telling OpenGL to render 4 or 2 (depends if earth.vFaces is a int or a short int) vertices. Also the count parameter is in vertices, not in triangles.

Then, if you are using vbo's you don't need to pass &earth.vFaces.at(0). Passing NULL is is sufficient

The proper call should (again, I think) be: glDrawElements(GL_TRIANGLES, earth.vFaces *3, GL_UNSIGNED_INT, NULL);

Hope this helps,

assainator

##### Share on other sites

Then, if you are using vbo's you don't need to pass &earth.vFaces.at(0). Passing NULL is is sufficient
[/quote]

It's better than sufficient, if you pass in an arbitrary memory location while your vbo is bound, its going to do the pointer arithmetic:

start of vbo + address of earth.vFaces = garbage in the middle of nowhere

which will probably cause your program to crash. Definitely want (void*)0 here as the last argument, or NULL.

It should (I think) be earth.vFaces *3
[/quote]
I think should be "earth.vFaces.size()*3", earth.vFaces looks like a vector, thus doesn't make any sense to multiply a std::vector by 3.

The questions that I'm thinking of is how do the program know which VBO to use as a reference for the index VBO? And how does it know the difference between a VBO containing vertex positions and one containing, for example normals?
[/quote]

The index buffer is always and only the thing bound to GL_ELEMENT_ARRAY_BUFFER. When you start drawing, it pulls indices from this buffer. Vertex and normal data are a little different, they work through the concept of ArrayPointers, which I conspicuously don't see in your code (a problem if you don't have it).

When you draw it doesn't matter if a buffer or not is bound to GL_ARRAY_BUFFER, it only reads data from where the pointers are set. So to draw a an array of vertices:

glBindBuffer(GL_ARRAY_BUFFER, id);
glVertexPointer(...);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexId);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements();
glDisableClientState(GL_VERTEX_ARRAY);

If you want to draw normals, you do the same thing with glNormalPointer, theres a whole family of gl*Pointer functions. However if you're using shaders and not the fixed pipeline, this changes a little bit to:

glBindBuffer(GL_ARRAY_BUFFER, id);
glVertexAttribPointer(...);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(attribId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexId);
glDrawElements();
glDisableVertexAttribArray(attribId);

Look up the manual page for any of the new functions I've defined here if you want to know how to use them.

##### Share on other sites

Then, if you are using vbo's you don't need to pass &earth.vFaces.at(0). Passing NULL is is sufficient

It's better than sufficient, if you pass in an arbitrary memory location while your vbo is bound, its going to do the pointer arithmetic:

start of vbo + address of earth.vFaces = garbage in the middle of nowhere

which will probably cause your program to crash. Definitely want (void*)0 here as the last argument, or NULL.

It should (I think) be earth.vFaces *3
[/quote]
I think should be "earth.vFaces.size()*3", earth.vFaces looks like a vector, thus doesn't make any sense to multiply a std::vector by 3.

The questions that I'm thinking of is how do the program know which VBO to use as a reference for the index VBO? And how does it know the difference between a VBO containing vertex positions and one containing, for example normals?
[/quote]

The index buffer is always and only the thing bound to GL_ELEMENT_ARRAY_BUFFER. When you start drawing, it pulls indices from this buffer. Vertex and normal data are a little different, they work through the concept of ArrayPointers, which I conspicuously don't see in your code (a problem if you don't have it).

When you draw it doesn't matter if a buffer or not is bound to GL_ARRAY_BUFFER, it only reads data from where the pointers are set. So to draw a an array of vertices:

glBindBuffer(GL_ARRAY_BUFFER, id);
glVertexPointer(...);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexId);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements();
glDisableClientState(GL_VERTEX_ARRAY);

If you want to draw normals, you do the same thing with glNormalPointer, theres a whole family of gl*Pointer functions. However if you're using shaders and not the fixed pipeline, this changes a little bit to:

glBindBuffer(GL_ARRAY_BUFFER, id);
glVertexAttribPointer(...);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(attribId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexId);
glDrawElements();
glDisableVertexAttribArray(attribId);

Look up the manual page for any of the new functions I've defined here if you want to know how to use them.
[/quote]

Thanks for the answers. It did the trick. Figures it was me not thinking straight about the count parameter and the NULL pointer at the end.
I'm not using any deprecated functions (OGL 3.x - 4) so the gl*Pointer functions won't cut it.
The latter code block is closer to what I'm doing.

I'm now trying to get the program to take my normals into account when displaying the model.

I'm sorry, but I just can't seem to wrap my head around how this works.
This is the code where I enable all my buffers and my VAO. Note that the normals and texture coordinate buffers are commented out, since they won't work. Obviously
void CModel::initVBO() { glGenVertexArrays(1, &vaoID[0]); // generates a vertex array to slot 0 in my VAO array glBindVertexArray(vaoID[0]); // binds the vertex array in slot 0 // vertex buffer glGenBuffers(1, &vboID[0]); // generates a VBO in slot 0 in my VBO array glBindBuffer(GL_ARRAY_BUFFER, vboID[0]); // binds the buffer as an ARRAY_BUFFER in slot 0 glBufferData(GL_ARRAY_BUFFER, sizeof(float)*vertices.size(), NULL, GL_STATIC_DRAW); // describes what I want to do with the buffer + size glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*vertices.size(), &vertices[0]); // fills the buffer with data /* // texture buffer glGenBuffers(1, &vboID[1]); glBindBuffer(GL_ARRAY_BUFFER, vboID[1]); glBufferData(GL_ARRAY_BUFFER, ((int)(texcoords.size()) * 3 * sizeof(float)), &(texcoords.at(0)), GL_STATIC_DRAW); // normal buffer glGenBuffers(1, &vboID[2]); glBindBuffer(GL_ARRAY_BUFFER, vboID[2]); glBufferData(GL_ARRAY_BUFFER, ((int)(normals.size()) * 3 * sizeof(float)), &(normals.at(0)), GL_STATIC_DRAW); */ // index buffer glGenBuffers(1, &vboID[1]); // generates a buffer in slot 1 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID[1]); // binds the buffer as an ELEMENT_ARRAY_BUFFER (since this concerns indices) glBufferData(GL_ELEMENT_ARRAY_BUFFER, ((int)(vFaces.size()) * sizeof(float)), &(vFaces.at(0)), GL_STATIC_DRAW); // loads the buffer with data, sets the size of the vector vFaces times float and tells it to start at position 0 in the vector vFaces glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // this points to the 0 slot vertex array object glEnableVertexAttribArray(0); // this enables the vertex array in slot 0 // glBindVertexArray(0); // this inactivates my vertex array... from a tutorial... why would I want to do this? }

As you can see, some question marks in the comments. Am I going about this correctly? I've tried generating and binding another vaoID to the VBO connected to my normals. But that didn't work... it sort of took the normals as vertex coordinates and that made my model "spiky" and completely round... which isn't right, since the model I'm loading at the moment is a human model.
I'm not understanding this.

Thanks for your time, guys. It's appreciated. It took some time to "sort of" understand VBO's. VAO's are proving to be a bit more difficult than I thought.

##### Share on other sites

glDrawElements(GL_TRIANGLES, sizeof(earth.vFaces), GL_UNSIGNED_INT, &earth.vFaces.at(0));

It should (I think) be earth.vFaces *3 as you are telling OpenGL to render 4 or 2 (depends if earth.vFaces is a int or a short int) vertices. Also the count parameter is in vertices, not in triangles.

Then, if you are using vbo's you don't need to pass &earth.vFaces.at(0). Passing NULL is is sufficient

The proper call should (again, I think) be: glDrawElements(GL_TRIANGLES, earth.vFaces *3, GL_UNSIGNED_INT, NULL);

Hope this helps,

assainator

Thanks, assainator. It helped a lot!

##### Share on other sites
You're throwing around the term "slot 0" in a lot of places, I don't think you really understand what it means.

Particularly here:

glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // this points to the 0 slot vertex array object

I think you should read up on this function which you will need:
glGetAttribLocation

in vec3 myNormal;

When you compile the shader, an attribute location is assigned to this variable, maybe it will be "3". Another variable like "myPosition" maybe gets assigned to "1". For a particular variable, you query the location with glGetAttribLocation, then use this as an argument to the glVertexAttribPointer/glEnableVertexAttribArray.

Also you don't really need VAO for anything, they're just a thin wrapper around several VBOs. They maybe save you one or two calls when setting up to render, but that's about it. If you're having trouble you can just stick with vertex buffers until you work out all the issues.

##### Share on other sites

It should (I think) be earth.vFaces *3

I think should be "earth.vFaces.size()*3", earth.vFaces looks like a vector, thus doesn't make any sense to multiply a std::vector by 3.
[/quote]
I wouldn't know, as I haven't seen all of his code. I interpreted earth.vFaces as a face-count value instead of a vector.

assainator

##### Share on other sites
Could one explain the VAO - VBO relationship like this?
When having many polygons on screen, VBO's are used to get a performance boost. When having a lot of VBO's (many, many objects) on screen, VAO's are used to get a performance boost.

Or am I wrong about the uses?
If not, then VBO's are practically required with most modern games (many polygons per object), while the addition of VAO's is more of a choice based on how many objects that would be on screen at the same time. An example for when to use VBO's without VAO's would then be when programming a game like DOOM 3, where there's not a lot of models on screen at the same time but the objects that are on screen are using many polygons. An example of a game that would benefit from VAO's would be Empire: Total War and Minecraft. Empire because of the massive amounts of units on screen at the same time and Minecraft because of all the blocks (which only have 6 quads (12 tris) but are in massive amounts).

Again, am I understanding the use of VAO and VBO now? I seem to have problems understanding the manual, it's easier when I can discuss this with you guys.

Thanks again.

##### Share on other sites
I'd say you've got the basic idea. Don't overstate the performance benefit of VAOs though, I'd imagine it to be fairly trivial. You're basically just replacing 1-10 or so opengl calls with one call, which could help a bit, but probably is not a huge deal (it may not actually be any different under the hood, if the driver is just replacing the vao call with the equivalent pointer calls). I've read a few threads on opengl.org and from what I can tell nobody actually knows if they give any performance benefit or not (it's up to the driver implementers to make it so, which seems has really not been done).

Please also don't assume that every 'thing' on the screen needs its own VBO. You mention total war, and even if there might be 500 infantry units on the battlefield, this is likely just a single VBO rendered 500 times.

The number of VBOs you have will boil down to personal preference, number of passes, how you organize your models, etc. VAO are optional if you want to use them, the code may be a little bit cleaner, but it's up to you. Don't lose any sleep over them

##### Share on other sites

I'd say you've got the basic idea. Don't overstate the performance benefit of VAOs though, I'd imagine it to be fairly trivial. You're basically just replacing 1-10 or so opengl calls with one call, which could help a bit, but probably is not a huge deal (it may not actually be any different under the hood, if the driver is just replacing the vao call with the equivalent pointer calls). I've read a few threads on opengl.org and from what I can tell nobody actually knows if they give any performance benefit or not (it's up to the driver implementers to make it so, which seems has really not been done).

Please also don't assume that every 'thing' on the screen needs its own VBO. You mention total war, and even if there might be 500 infantry units on the battlefield, this is likely just a single VBO rendered 500 times.

The number of VBOs you have will boil down to personal preference, number of passes, how you organize your models, etc. VAO are optional if you want to use them, the code may be a little bit cleaner, but it's up to you. Don't lose any sleep over them

Haha, no I won't lose any sleep at all (have skipped them).
Now I need to figure out how to interleave (or assign) normals and texture coordinates with my vertex positions. Any tips? I was thinking of binding one VBO for each value... but that feels like defeating the purpose of using VBO's. And then I noticed that you can use an offset with the drawElements call.
Do I interleave the values in a new vector containing: [0]: X, Y, Z (3 values for vertex position) | [1]: X, Y, Z (3 values for normals) | [2]: U, V (2 values for texture coordinates (UV)) and then start over at position [3] with the next positions?
Having done this, how the hell do I get the glDrawElements call to actually draw all three?

1. 1
2. 2
3. 3
Rutin
21
4. 4
5. 5

• 14
• 30
• 13
• 11
• 11
• ### Forum Statistics

• Total Topics
631778
• Total Posts
3002310
×