After learning about VBOs, a friend told me to try using VAOs for linking cube indices with the vertices. I followed about every tutorial I could find with no avail. It looks like the buffers are binding correctly and everything works up until I try to draw them.
This is how I generate the VAO -
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glEnableVertexAttribArray(0);
glGenBuffers(1, &cubeIndex);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cubeIndex);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 36 * sizeof(GLuint), cubeIndices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_UNSIGNED_INT, GL_FALSE, sizeof(GLuint)*3, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(1);
glGenBuffers(1, &cubeVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 21 * sizeof(GLfloat), cubeVertPoints, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*3, 0);
glBindVertexArray(0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Rendering -
glEnableClientState(GL_VERTEX_ARRAY);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, size);//Runtime exception here if anything larger that '2' is provided?
glBindVertexArray(0);
Your code does not make sense. You never bind anything to GL_ARRAY_BUFFER, so your glVertexAttribPointer() calls will point to invalid VBOs - explaining the crash when you try to draw that thing.
I'm not sure what you're trying to do here. It looks like cubeIndex is supposed to be the element array for indexed rendering. But you seem to try to use the indices as vertex attributes. But you should use that as GL_EMEMENT_ARRAY_BUFFER (as you already do) in conjunction with glDrawElements() (what you don't do). Your cubeVBO should be a GL_ARRAY_BUFFER, and you should use that as a vertex attribute.
The sizes of your array also seem strange. 36 Uints do make sense as index buffer when drawing a cube with 6 sides and 2 triangles each. But 21 floats for the vertex data with 3 components per vector are just 7 vertices - strange for a cube.
Please have a look at the Vertex Specification and Vertex Rendering pages in the OpenGL wiki, or look into some tutorials - the code you posted so far makes me think that you didn't grasp the underlying concepts.
Related
I want to create a VAO for every 3D Object in my program.
I create two VAO's:
//in some method 1
glGenVertexArrays(1, &vao1);
//in some method 2
glGenVertexArrays(1, &vao2);
then for earch VAO I create 2 VBO's:
glBindVertexArray(vao1);
glGenBuffers(2, vbos1);
glBindVertexArray(0);
//and the same for vao2, vbos2
then I send the data to the gpu:
glBindVertexArray(vao1);
glBindBuffer(GL_ARRAY_BUFFER, vbos1[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions1), positions1, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos1[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
//and the same for vao2, vbos2, indices2
Then I do the same thing for vao2.
Now only vao2 is drawn.
If I switch the
glGenVertexArrays(1, &vao2);
glGenVertexArrays(1, &vao1);
Then only the vao1 is drawn.
I draw the vaos via:
glBindVertexArray(vao1);
glDrawElements(GL_TRIANGLES, indices1, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//in another method
glBindVertexArray(vao2);
glDrawElements(GL_TRIANGLES, indices2, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
It makes no difference in which order I draw them, send the data to the gpu or initialize the buffers.
Why is that so?
Right: the order of creating VAOs makes no difference.
Among other things, a VAO stores the buffer binding. You don't need to bind a buffer each time you draw or update data. Just bind the VAO.
If the whole data fits in GPU memory you can update data only once, likely at buffer+VAO creation and binding. If not, then binding the VAO also makes the buffer "associated" in that VAO ready for receiving data.
I'm creating a VBO, populating it with data, then that data is being rendered using the following code:
// Buffer data
glGenBuffers(1, &VBOID);
glBindBuffer(VBOID, GL_ARRAY_BUFFER); // Shouldn't these be the other way around?
glBufferData(GL_ARRAY_BUFFER, bufferSize, buffer, GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, buffer);
// Draw arrays
glBindBuffer(VBOID, GL_ARRAY_BUFFER);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_TRIANGLES, 0, bufferSize);
glDisableClientState(GL_VERTEX_ARRAY);
However, the openGL reference (https://www.opengl.org/sdk/docs/man/html/glBindBuffer.xhtml) says that the glBindBuffer function takes the target TYPE of buffer, then the buffer ID, not the other way around. When I put them in that way around, nothing draws to the screen, however when they're the 'wrong' way around, it seems to work just fine.
To clarify:
// Should be this
glBindBuffer(GL_ARRAY_BUFFER, VBOID);
// Only this works
glBindBuffer(VBOID, GL_ARRAY_BUFFER);
I feel like this is one of those really dumb issues, but I just can't see where the problem is. Could anyone shed some light on the situation?
Thanks.
It should definitely be written like this:
glBindBuffer(GL_ARRAY_BUFFER, VBOID);
I can't explain why reversing those arguments results in successful drawing. However, there's a few oddities you have in your code that you need to revise:
glVertexPointer(3, GL_FLOAT, 0, buffer);
This is immediate mode code. I don't think it's been deprecated, but the correct way to write this is
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, nullptr);
On top of that, you have two references to setting client state—glEnableClientState(GL_VERTEX_ARRAY); and glDisableClientState(GL_VERTEX_ARRAY);—These are also part of immediate mode, and should be removed.
Finally, the whole thing should be wrapped up inside a Vertex Array Object, like so:
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &VBOID);
glBindBuffer(GL_ARRAY_BUFFER, VBOID);
glBufferData(GL_ARRAY_BUFFER, bufferSize, buffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, nullptr);
glEnableVertexAttribArray(0);
// Draw arrays
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, num_of_vertices); //num_of_vertices is usually the number of floats in the buffer divided by the number of dimensions of the vertex, or 3 in this case, since each vertex is a vec3 object.
I know that VAOs store vertex attribute settings and bound buffer objects, but I'm not sure what is the correct binding-unbinding order I should be doing. Is the next order right?
glBindVertexArray(vao); //bind vao
glBindBuffer(GL_ARRAY_BUFFER, vbo); //bind vbo
glBufferData(GL_ARRAY_BUFFER, sizeof(vec3) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(vertex_index, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(vertex_index);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); //bind ebo
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(), GL_STATIC_DRAW);
glBindVertexArray(0); //unbind vao
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind vbo
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind ebo
At the moment, this is the code I use and it works, but I came to this after many attempts so I want to be sure this is the right way.
GL_ARRAY_BUFFER can be unbound right after glEnableVertexAttribArray/glVertexAttribPointer, since the binding gets stored by these two functions. Unbinding it afterwards is not noted by the VAO anymore.
Since there always exists just one GL_ELEMENT_ARRAY_BUFFER, the VAO stores the last binding state of this buffer type. Thus the index buffer has to be bound up to the moment where the VAO gets unbound.
Your code example is totally valid. You could move the GL_ARRAY_BUFFER unbinding some lines up, but this is not required.
So I wanted to implement a simple VBO to see if it was worth switching from display lists for static objects in my scene. So far, I don't think Im doing it anytime soon. So heres my problem: I can render vertices fine, but as soon as I throw in texture coordinates, it crashes. So I do a bit of experimenting and its because I'm binding a texture to the thing. I have NEVER heard of this as being a problem. Literally the exact same code, using display lists works. Here is my code:
//create a vertex buffer object for the particles to use
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//create the data, this is really sloppy
float QuadVertextData[] = {0,0,0,1,0,0,1,1,0,0,1,0};
float QuadTextureData[] = {0,1,1,1,1,0,0,0};
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3, &QuadVertextData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//generate another buffer for the texcoords
glGenBuffers(1, &VBOT);
glBindBuffer(GL_ARRAY_BUFFER, VBOT);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2, &QuadTextureData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
and rendering:
glUseProgram(shader);
glBindTexture(GL_TEXTURE_2D, texture);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, VBOT);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
I really have no idea why this is happening, Doing a texture without a shader crashes it, binding a shader without a texture crashes it. Any help or advice?
In a core opengl profile, you need to use VAOs in order to work with calls such as glDrawArrays and glDrawElements. A VAO (vertex array object) is a list of binding points for VBOs that encapsulates information such as data format and number of components for each VBO that is bound to it. In code it looks something like this.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3, &QuadVertextData, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glGenBuffers(1, &vbot);
glBindBuffer(GL_ARRAY_BUFFER, vbot);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2, &QuadTextureData, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glBindVertexArray(0);
The 0 and 1 (the first argument to glVertexAttribPointer) specifies the generic vertex attribute index in your shader. The 2 and 3 (the second argument) specify the number of components. Your input should be defined like this in the shader in order to work with this VAO:
layout(location=0) in vec3 position;
layout(location=1) in vec2 textureCoordinates;
Before drawing anything, you just have to use the shader program, bind your texture and bind the VAO:
glUseProgram(shader);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(vao);
glDrawArrays(GL_QUADS, 0, 4);
Don't forget to set the texture location of the sampler2D uniform in the shader.
If you want to learn more about switching to the OpenGL core profile, I recommand the tutorials from http://www.opengl-tutorial.org/
I have a method for initializing my VBO/VAO:
glBindBuffer(GL_ARRAY_BUFFER, mVBO_VertexShader);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData), indexData, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// setup VAO
glBindVertexArray(mVAO);
glBindBuffer(GL_ARRAY_BUFFER, mVBO_VertexShader);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
And then a separate method for drawing;
glBindVertexArray(mVAO);
glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_SHORT, &mIndexBuffer);
glBindVertexArray(0);
Do I need to unbind the GL_ELEMENT_ARRAY_BUFFER after my call to glDrawElements or is its state 'tied' to the VAO? (So if I unbind the VAO, the GL_ELEMENT_ARRAY_BUFFER will also be unbound)?
GL_ELEMENT_ARRAY_BUFFER is tied to the VAO state. I quote the OpenGL 3.3 spec: "The resulting vertex array object is a new state vector, comprising all the state values listed in tables 6.4 and 6.5."
Table 6.4 contains ELEMENT ARRAY BUFFER BINDING. So no, you do not need to unbind it.
Additionally, you probably want to pass NULL as the last parameter to glDrawElements in your example, since the address is relative to the bound element array buffer..
Bind your vertex array when you set the vertex attrib pointer.
So basically just don't unbind your vertex array as you only have one.