Why VAO can use VBO data without binding it?
https://learnopengl.com/Advanced-OpenGL/Instancing
i find it from this webpage.
the code page:
https://learnopengl.com/code_viewer_gh.php?code=src/4.advanced_opengl/10.3.asteroids_instanced/asteroids_instanced.cpp
unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, amount * sizeof(glm::mat4), &modelMatrices[0], GL_STATIC_DRAW);
for (unsigned int i = 0; i < rock.meshes.size(); i++)
{
unsigned int VAO = rock.meshes[i].VAO;
glBindVertexArray(VAO);
// set attribute pointers for matrix (4 times vec4)
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0);
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4)));
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2 * sizeof(glm::vec4)));
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3 * sizeof(glm::vec4)));
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
glVertexAttribDivisor(5, 1);
glVertexAttribDivisor(6, 1);
glBindVertexArray(0);
}
the rock.meshes[i].VAO use the buffer data without bind it?
i think it should be this:
for (unsigned int i = 0; i < rock.meshes.size(); i++)
{
unsigned int VAO = rock.meshes[i].VAO;
GLuint buffer;
glBindVertexArray(VAO);
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, amount * sizeof(glm::mat4), &modelMatrices[0], GL_STATIC_DRAW);
......
}
No, buffer is still bound to the target GL_ARRAY_BUFFER.
OpenGL is a state engine, and the last instruction which binds a buffer object to the the target GL_ARRAY_BUFFER was:
glBindBuffer(GL_ARRAY_BUFFER, buffer);
So buffer is still bound when you do the definition of generic vertex attribute data.
When the array of generic vertex attribute data is specified (glVertexAttribPointer), then the vertex specification (index, tuple size, format, stride, offset, ...) and the "name" of the current buffer object, which is bound to the target GL_ARRAY_BUFFER, is set to the Vertex Array Objects state vector.
See Vertex Buffer Object.
Note, an Index buffer would be stated in the Vertex Array Object directly. So the Vertex Array Object has to be bound, before a buffer is bound to the target GL_ELEMENT_ARRAY_BUFFER.
Binding a buffer object to the target GL_ARRAY_BUFFER does not change the the current Vertex Array Object's states, but binding a buffer object to the target GL_ELEMENT_ARRAY_BUFFER modifies the VAOs states.
A Vertex Array Object can refer to only one index buffer, but it can refer to a separate array buffer for each attribute.
Related
I use the following code to render a simple quad using a vertex array and an index buffer.
In the Vertex specification, I see
The index buffer binding is stored within the VAO.
But in my code, in the render loop, I need to bind the index buffer to see the quad.
The data:
float mesh[24] = {
// pos // color
0, 0, 0, 1, 1, 0,
-.5, 0, 0, 0, 1, 1,
-.5, 0, .5, 1, 0, 1,
0, 0, .5, 1, 1, 1
};
int indices[6] = {0, 1, 2, 0, 2, 3};
The initialization of the buffers:
GLuint vao{};
GLuint buffers[2]{};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(2, buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(float), mesh, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3 * sizeof(float)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(int), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
And in the main loop, I use:
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); // Why this line is necessary ?
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
Why should I use glBindBuffer() with GL_ELEMENT_ARRAY_BUFFER in the render loop?
Why this line is necessary ?
It is not necessary. However, the element buffer reference is stored in the VAO. Just remove glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);. This line breaks the binding of the index buffer and to the VAO.
The Index Buffer (ELEMENT_ARRAY_BUFFER) binding is stored within the Vertex Array Object. When glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO) is called the element buffer object ID is stored in the currently bound Vertex Array Object. Therefore the VAO must be bound before the element buffer with glBindVertexArray(VAO).
Unlike to the Index Buffer, the Vertex Buffer binding (ARRAY_BUFFER) is a global state.
Each attribute which is stated in the VAOs state vector may refer to a different ARRAY_BUFFER. When glVertexAttribPointer is called the buffer which is currently bound to the target ARRAY_BUFFER, is associated to the specified attribute index and the ID of the object is stored in the state vector of the currently bound VAO.
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);
I create my buffers with the following code:
//generate buffers
glGenVertexArrays(1, &VAO);
//glGenBuffers(1, &EBO);
glGenBuffers(1, &VBO_vertices);
glGenBuffers(1, &VBO_colors);
glGenBuffers(1, &VBO_normals);
// Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).
glBindVertexArray(VAO);
// Copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, VBO_vertices);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*vertices.size(), &vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vTable.size() * sizeof(int), &vTable[0], GL_STATIC_DRAW);
// Position attribute
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); //size = 3 (X,Y,Z)
glEnableVertexAttribArray(0);
//Buffer for color
glBindBuffer(GL_ARRAY_BUFFER, VBO_colors);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*vertices.size(), &v_color[0], GL_STATIC_DRAW);
// Color attribute
glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); //size = 3 (R,G,B)
glEnableVertexAttribArray(1);
//Buffer for normals
glBindBuffer(GL_ARRAY_BUFFER, VBO_normals);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*vertices.size(), &v_normals[0], GL_STATIC_DRAW);
//normal attribute
glVertexAttribPointer((GLuint)2, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); //size = 3 (R,G,B)
glEnableVertexAttribArray(2);
// Unbind the VAO
glBindVertexArray(0);
My data are :
vector<vec3> vertices, v_normals,v_color;
vector<int> vTable;
I have vertices, normals and colors per vertex and an index table with the index vertices of each triangle.
When I try to render this, nothing appears on the window.
glBindVertexArray(VAO); //Bind VAO
glDrawElements(GL_TRIANGLES, vTable.size(), GL_UNSIGNED_INT, &vTable[0]);
glBindVertexArray(0); //Unbind VAO
If I used this:
glDrawArrays(GL_TRIANGLES,0,vTable.size());
It draws something but an incomplete object, like in the link image.
image
Anybody knows what happens? Thanks in advance
Your glDrawElements call is wrong, the last parameter should be a byte offset into your GL_ELEMENT_ARRAY_BUFFER that holds the indices, not pointer to system memory.
glDrawElements(GL_TRIANGLES, vTable.size(), GL_UNSIGNED_INT, 0);
I have a mesh class as follows
Mesh_PTI::Mesh_PTI(bool dynamic) : m_dynamic(dynamic), m_drawCount(0)
{
glGenVertexArrays(1, m_vertexArrays);
glBindVertexArray(m_vertexArrays[0]);
glGenBuffers(NUM_BUFFERS, m_buffers);
glBindVertexArray(0);
}
Mesh_PTI::Mesh_PTI(glm::vec3 positions[], glm::vec2 texCoords[], unsigned short indices[], unsigned short numVertices, unsigned int numIndices, bool dynamic) :
m_dynamic(dynamic)
{
glGenVertexArrays(1, m_vertexArrays);
glBindVertexArray(m_vertexArrays[0]);
glGenBuffers(NUM_BUFFERS, m_buffers);
createBuffers(positions, texCoords, indices, numVertices, numIndices, false);
glBindVertexArray(0);
m_drawCount = numIndices;
}
Mesh_PTI::~Mesh_PTI()
{
glDeleteBuffers(NUM_BUFFERS, m_buffers);
glDeleteVertexArrays(1, m_vertexArrays);
}
void Mesh_PTI::draw()
{
if(m_drawCount > 0)
{
glBindVertexArray(m_vertexArrays[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[INDEX_VB]);
glDrawElements(GL_TRIANGLES, m_drawCount, GL_UNSIGNED_SHORT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
}
void Mesh_PTI::setData(glm::vec3 positions[], glm::vec2 texCoords[], unsigned short indices[], unsigned short numVertices, unsigned int numIndices)
{
glBindVertexArray(m_vertexArrays[0]);
createBuffers(positions, texCoords, indices, numVertices, numIndices, false);
glBindVertexArray(0);
m_drawCount = numIndices;
}
void Mesh_PTI::createBuffers(glm::vec3 positions[], glm::vec2 texCoords[], unsigned short indices[], unsigned short numVertices, unsigned int numIndices, bool dynamic)
{
glBindBuffer(GL_ARRAY_BUFFER, m_buffers[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(positions[0]), positions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, m_buffers[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(texCoords[0]), texCoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[INDEX_VB]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, numIndices * sizeof(indices[0]), indices, GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_SHORT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
I need to update the vertex data. If I delete the mesh and load the vertex data using the constructor, everything works fine.
If I initialize it with the first constructor and use the setData function to load vertex data, multiple instances of this class only render the last one that had setData called.
What am I doing wrong?
glGenBuffers only returns available buffer names at the time at which the method is called, it does not reserve those names. So the next time you call glGenBuffers without binding anything to the first buffers from the call of glGenBuffers, you will get the same names since they haven't been used yet. When you later call glBindBuffers, you will find all your instances are using the same names for their VBOs, so they are overwriting each other.
You are also trying to bind an element array buffer as a vertex attribute, which doesn't
make any sense because indices are used as part of glDrawElements (unless you are using
them in your shader for some reason).
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_SHORT, GL_FALSE, 0, NULL);
// ^~~~~ but your indices are GL_UNSIGNED_SHORT
On a related note: you don't need to bind your index buffer every time before you draw with a VAO, since the index buffer is part of the VAO state. Specified vertex data is bound using the glVertexPointer* functions, so the vertex->attribute bindings and their appropriate VBO is part of state as well, but GL_ARRAY_BUFFER isn't.
I'm attempting to copy two vertex buffer objects from one Mesh object to another, through the copy assignment operator. Initially, my Vertex Array Object and the Buffers are initialized as follows:
void Mesh::construct(Vertex* vertices, unsigned int nVerts) {
vertexCount = nVerts;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
std::vector<glm::vec3> positions;
std::vector<glm::vec2> texCoords;
positions.reserve(nVerts);
texCoords.reserve(nVerts);
for (unsigned int i = 0; i < nVerts; i++) {
positions.push_back(vertices[i].getPosition());
texCoords.push_back(vertices[i].getTexCoord());
}
for (int i = 0; i < NUM_BUFFERS; i++) {
glGenBuffers(1, &vab[i]);
}
glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
This works fine when instantiating a Mesh object, and calling:
void Mesh::render() {
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, vertexCount);
glBindVertexArray(0);
}
However, when I try to copy the mesh into another, and render it, I get a segmentation fault on the glDrawArrays(GL_TRIANGLES, 0, vertexCount); line.. This is my copy assignment operator:
Mesh& Mesh::operator=(const Mesh& param) {
if (this == ¶m) {
return *this;
} else {
GLint size = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
for (int i = 0; i < NUM_BUFFERS; i++) {
glGenBuffers(1, &vab[i]);
}
// Vertices
// Bind Buffers
glBindBuffer(GL_COPY_READ_BUFFER, param.vab[POSITION_VB]);
glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size);
glBindBuffer(GL_COPY_WRITE_BUFFER, vab[POSITION_VB]);
glBufferData(GL_COPY_WRITE_BUFFER, size, nullptr, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Copy Data
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size);
// Texture Coords
// Bind Buffers
glBindBuffer(GL_COPY_READ_BUFFER, param.vab[TEXCOORD_VB]);
glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size);
glBindBuffer(GL_COPY_WRITE_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_COPY_WRITE_BUFFER, size, nullptr, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
// Copy Data
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size);
// Unbind buffers
glBindVertexArray(0);
this->vertexCount = param.vertexCount;
return *this;
}
}
Can anyone see any problems with this? I've checked that the size being returned from glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size); is correct in both cases (for both position and texture coordinate buffer). I've also checked glGetError() after both calls to glCopyBufferSubData, which both return 0. Not sure what to try next? My error may be elsewhere, but this is the first time I have tried copying buffers, so want to check that I'm doing that part right. If it helps, my Mesh destructor is:
Mesh::~Mesh() {
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(NUM_BUFFERS, vab);
}
Through a debugger I can see that this is, of course, being called once, after the line:
this->mesh = Mesh(*texture);
Which is simply constructing a mesh, then assigning it (the texture just sizes the quad to the size of the texture, and calls the constructor shown at the start with the correct vertex positions).
You copy the arrays, but you never bind the copied versions to GL_ARRAY_BUFFER, meaning your glVertexAttribPointer calls are pointing to nothing.
I'm also a little wary of this code:
glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
It seems like the position vertex pointer will be referring to the texture data, because that's the currently bound vertex buffer when you call glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
I'd think you'd want the order to be like so:
glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
But I'm not certain. I usually interleave all my vertex attributes into a single vertex buffer.