Can I have multiple GL_ARRAY_BUFFER buffers? - c++

So I was looking at another SO question regarding the command glVertexAttribPointer and I ran into a slight confusion. The accepted answer to this question explains,
But there's an additional implied piece of state that is also stored away for attribute 0 when you make the call: the data is read from the buffer currently bound to GL_ARRAY_BUFFER
This makes sense to me, but what if I have multiple buffers that are bound as GL_ARRAY_BUFFER? How does the glVertexAttribPointer() method know which one to set the attributes of?
For example, in my code, I'm drawing a gradient triangle. To do this, I've created 2 VBOs, one with color data in an array and another with vertex locations.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
static const GLfloat points[] = {
//data here
};
static const GLfloat colors[] = {
//data here
};
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
vs = glCreateShader(GL_VERTEX_SHADER);
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vs, 1, &vertexShaderData, NULL);
glShaderSource(fs, 1, &fragShaderData, NULL);
glCompileShader(vs);
glCompileShader(fs);
sp=glCreateProgram();
glBindFragDataLocation(sp, 0, "outColor");
glAttachShader(sp, vs);
glAttachShader(sp, fs);
glLinkProgram(sp);
glUseProgram(sp);
glGenBuffers(1, &colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 9);
When I call the command, where do I specify which buffer to use?

This makes sense to me, but what if I have multiple buffers that are bound as GL_ARRAY_BUFFER?
That's not possible. When you bind a buffer (or any OpenGL object) to a target, it automatically unbinds whatever was there before.
OpenGL object targets are like global variables. What happens when you set a global integer to 3? It's old value is gone.
glVertexAttribPointer will always use whatever buffer is currently bound to GL_ARRAY_BUFFER. So in your first call, it will use buffer. In your second call, it will use colorBuffer.
This is why it is important to remember that glVertexAttribPointer operates on what is currently bound. Because even after you bind colorBuffer, and set it to be used by attribute 1, attribute 0 still receives its vertex data from buffer.
So while you cannot have multiple buffers bound to GL_ARRAY_BUFFER, you can use multiple buffers as sources for your vertex data.

Related

OpenGL can't update vertex buffer with VAO procedure

I'm attempting to move a vertex by modifying it's positional vertex attribute. As a test, I have added the line vertices[0] = 0.4f; both before and after the creation of my VAO procedure, to see whether I am able to modify the vertices array after an initial render. When I add it before the VAO creation, it modifies the location of the vertex, and when it is added afterwards it does not. This leads me to believe my rendering procedure:
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
Somehow isn't actually updating the buffer with the current float[] in memory. However, I can then replace the line glBindVertexArray(VAO); with the whole rendering procedure:
// 2. copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
// 2. copy our vertex indices in a buffer for OpenGL to use
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
// 3. then set our vertex attributes pointers:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); // Pos vec3
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3* sizeof(float))); // Col vec4
glEnableVertexAttribArray(1);
And with this as my rendering procedure, I can update the vertices array and this change is carried across to the GPU, updating the position of the vertex on-screen. Here is my VAO creation code:
// Generate a Vertex Array Object to store our rendering procedure.
unsigned int VAO;
glGenVertexArrays(1, &VAO);
// 1. bind Vertex Array Object, Element Buffer Object
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// 2. copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
// 2. copy our vertex indices in a buffer for OpenGL to use
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
// 3. then set our vertex attributes pointers:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); // Pos vec3
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3* sizeof(float))); // Col vec4
glEnableVertexAttribArray(1);
So it works when I express the rendering procedure explicitly, but not when I store it in a VAO? From what I understand, a VAO is a construct for storing a rendering procedure, and when we then run glBindVertexArray(VAO);, this rendering procedure is carried out. Am I understanding this wrong? Is there another line I need in either the creation of the VAO or when rendering?
Here is the full source in C++: https://pastebin.com/DgZuZt4K
And the same thing written in OpenTK, C#: https://pastebin.com/DHj9UN16
[...] From what I understand, a VAO is a construct for storing a rendering procedure, [...]
No it is not. A Vertex Array Object stores states.
When glBufferData/glBufferSubData is called, then the buffer object's data store is initialized respectively updated.
When glVertexAttribPointer is called, then states are set in the state vector of the VAO. The buffer object which is currently bound to the target GL_ARRAY_BUFFER is associated to the specified vertex attribute in the currently bound VAO.
The VAO stores the information about how to interpret the vertex information and the id of the VBO for each attribute.
But the VAO does not store a procedure or even a process. When you have changed the vertices, then you have to update the Vertex Buffer Object by either glBufferSubData or buffer mapping.
Related: What is the proper way to modify OpenGL vertex buffer?
If you want to specify and enable a vertex attribute (glVertexAttribPointer / glEnableVertexAttribArray), then you have to bind the VAO and the VBO. The VAO stores the specification and the id of the VBO is stored in the VAO.
If you want to update the vertex coordinates and attributes (e.g. glBufferSubData), then you have to bind the VBO.
If you want to draw the mesh (e.g. glDrawArrays), then it is sufficient to bind the VAO.

How to fix OpenGL stack corruption when exiting

I've been following some opengl tutorials in C++ (moving from using java, so I know openGL alright, but memory management, pointers, etc I'm a little slow on) from http://www.opengl-tutorial.org, and I'm currently having problems with an error when exiting my application.
I am trying to add a normals vertex attrib array. It seems to work fine during runtime, but when I exit the application, I get this:
"Run-Time Check Failure #2 - Stack around the variable 'normalbuffer' was corrupted."
I of course did some googling, and found that this error was normally related to arrays and index out of bounds errors, but normalbuffer is just a GLuint. As far as I can tell, the code for implementing my normalbuffer is identical to that implementing my vertex positions and my uv texture map.
Here is my initialization code:
// Create Vertex Buffer
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
// Create UV Buffer
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(glm::vec2), &uvs[0], GL_STATIC_DRAW);
// Create Normals Buffer
GLuint normalbuffer;
glGenBuffers(2, &normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals[0], GL_STATIC_DRAW);
And then my looped code (run every frame):
//...
//Load the vertex positions array
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, //Specify which attribute index we are using
3, //Size of the attribute
GL_FLOAT, //Type of attribute
GL_FALSE, //Normalized?
0, //Stride
(void*)0 //Array Buffer Offset
);
//Load the UV positions array
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
1, //Specify which attribute index we are using
2, //Size of the attribute
GL_FLOAT, //Type of attribute
GL_FALSE, //Normalized?
0, //Stride
(void*)0 //Array Buffer Offset
);
//Load the normal vectors array
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
2, //Specify which attribute index we are using
3, //Size of the attribute
GL_FLOAT, //Type of attribute
GL_FALSE, //Normalized?
0, //Stride
(void*)0 //Array Buffer Offset
);
//glDrawArrays() happens here
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
//...
This error doesn't seem to happen at all during run time, only when I close the program by hitting the escape key (so I'm not killing the process in VS).
The 1st parameter of glGenBuffers specifies the number of buffer object names to be generated.
You generate 2 objects, but pass the address of the single variable normalbuffer to glGenBuffers.
2 objects are generated and the names of the objects are written to the memory addressed by &normalbuffer and (&normalbuffer) + 1. This causes the stack corruption.
Change the number of objects to be generated:
GLuint normalbuffer;
glGenBuffers(2, &normalbuffer);
glGenBuffers(1, &normalbuffer);

Opengl VAO and VBO objects

I want to create multiple vertex buffers in objects (one by object). the constructor is:
VertexBuffer::VertexBuffer(const GLvoid *data,
GLsizeiptr size,
GLenum mode,
GLsizei count,
GLsizei stride,
ShaderInterface *shaderInterface,
GLvoid *positionOffset,
GLvoid *normalOffset)
: _mode(mode),
_count(count),
_stride(stride),
_shaderInterface(shaderInterface),
_positionOffset(positionOffset),
_normalOffset(normalOffset)
{
glGenBuffers(1, &_vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
//
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0); //??????
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
//
}
If I create 1 object VertexBuffer, this works ok. But if I create another object (I won't use it) and I draw the first object again the result is not correct (for example, the object showed is in other place). Why?
You don't seem to store the vao anywhere, but you should. Before drawing each object you shall glBindVertexArray its vao (but not _vertexBufferID) before you call any of glDraw*.
See also this answer to see what state VAOs contain.

Can a different VAO use the previous used vertex attribute index number

Can two VAOs (va01, vao2) have the same vertex attribute index number?
GLuint vao1, vao2;
glGenVertexArrays(1, &vao1);
glGenVertexArrays(1, &vao2);
{
glBindVertexArray(vao1);
...
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
...
glBindVertexArray(0);
}
{
glBindVertexArray(vao2);
...
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
...
glBindVertexArray(0);
}
Suppose vbo1 and vbo2are defined before these code and they got glBufferDataalready. Can vao1 and vao2 both have the same vertex attribute index number 0?
Yes, several VAOs can set up the same vertex attributes, pointing to different VBOs each.
Suppose vbo1 and vbo2are defined before these code and they got glBufferDataalready. Can vao1 and vao2 both have the same vertex attribute index number 0?
You are confusing some things here. VAOs never care about the BufferData. VAOs store the attribute pointers, the attribute enables, and the GL_ELEMENT_ARRAY_BUFFER_BINDING. They do not store any vertex data, they only reference to it. And they do reference a VBO by name - that means that you can just do:
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glVertexAttribPointer(i, ...); // here, a reference to vbo1 gets part of the attrib pointer for attrib i
...
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBufferData(...); // VAO will now point into this buffer storage
(this also means that you can set up the pointer before you created the buffer storage for the VBO, you just need to have created the VBO object). Maybe you find my illustration in this answer helpful.

Order of arguments in glBindBuffer

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.