OpenGL - Combine Vertex Array Object and Index Buffer (GL_ELEMENT_ARRAY_BUFFER) - c++

I do want to use an Index Buffer (GL_ELEMENT_ARRAY) together with an Vertex array object. I have the following code:
// Set stuff up
glGenVertexArrays(1, &VertexArrayObjectId);
glBindVertexArray(VertexArrayObjectId);
glGenBuffers( 1, &ArrayBufferId );
glBindBuffer( GL_ARRAY_BUFFER, ArrayBufferId );
glBufferData( GL_ARRAY_BUFFER, sizeof(float) * finalData.size() , finalGPUData, GL_STATIC_DRAW );
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (GLvoid*) 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_TRUE, sizeof(float) * 8, (GLvoid*) 12);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (GLvoid*) 20);
glGenBuffers(1, &IndexBufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, finalIndices.size() * sizeof(unsigned int), finalGPUIndices, GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
//Render
//Set up shader etc
glBindVertexArray(VertexArrayObjectId);
//glBindBuffer( GL_ARRAY_BUFFER, ArrayBufferId );
//glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (GLvoid*) 0);
//glVertexAttribPointer(1, 2, GL_FLOAT, GL_TRUE, sizeof(float) * 8, (GLvoid*) 12);
//glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (GLvoid*) 20);
glDrawElements(GL_TRIANGLES, finalIndices.size(), GL_UNSIGNED_INT, (void*) 0 );
According to my knowledge, the 4 lines of code, which are commented out are not necessary, because this information is stored in the VAO. (I mean, saving these calls is the purpose of the VAO) However if I run this code it only draws a few Triangles at the origin rather than at the correct vertex position. If I include these lines however, everything gets drawn correctly. So apparently the GL_ELEMENT_ARRAY_BUFFER information is stored correctly within the VAO, but the vertex attributes are not. Is my understanding wrong or are there simply mistakes in my code?
Any help is greatly appreciated.

Related

RenderDoc Opengl doesn't show VBO with DSA

I was working on an OpenGL project where I tried to use DSA concepts instead of binding the variables. One way that I use this is when creating a VBO, VAO, and EBO for a set of meshes from a model that I loaded. The code runs fine on my own executable after compiling and linking everything.
I've tried to add other unrelated functionality, but I need to debug it through RenderDoc. The problem is that nothing shows on screen when I run the executable through it.
I saw that one of the reasons why is because it doesn't see the VBO that I create for each mesh and shows it as Unkown Resource #.
I changed the DSA code that creates these buffers to do it the normal way, and it actually works when I do it that way. I'm confused if there is a bug with my code in terms of the way I do the calls, or if it's something else like a driver issue that I can't really fix by myself. For reference, I have a RX 6700 XT in case someone else has gone through the same issue.
For reference the DSA Way:
GLuint binding_index = 0;
glCreateVertexArrays(1, &mesh.VAO);
glCreateBuffers(1, &mesh.EBO);
glCreateBuffers(1, &mesh.VBO);
glNamedBufferStorage(mesh.VBO, sizeof(Vertex) * mesh.vertices.size(), mesh.vertices.data(), GL_DYNAMIC_STORAGE_BIT);
glNamedBufferStorage(mesh.EBO, mesh.indices.size() * sizeof(unsigned int), mesh.indices.data(), GL_DYNAMIC_STORAGE_BIT);
glVertexArrayVertexBuffer(mesh.VAO, binding_index, mesh.VBO, 0, sizeof(Vertex));
glVertexArrayElementBuffer(mesh.VAO, mesh.EBO);
glEnableVertexArrayAttrib(mesh.VAO, 0);
glEnableVertexArrayAttrib(mesh.VAO, 1);
glEnableVertexArrayAttrib(mesh.VAO, 2);
glEnableVertexArrayAttrib(mesh.VAO, 3);
glEnableVertexArrayAttrib(mesh.VAO, 4);
glVertexArrayAttribFormat(mesh.VAO, 0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(mesh.VAO, 1, 3, GL_FLOAT, GL_FALSE, offsetof(Vertex, Normal));
glVertexArrayAttribFormat(mesh.VAO, 2, 2, GL_FLOAT, GL_FALSE, offsetof(Vertex, TexCoords));
glVertexArrayAttribFormat(mesh.VAO, 3, 3, GL_FLOAT, GL_FALSE, offsetof(Vertex, Tangent));
glVertexArrayAttribFormat(mesh.VAO, 4, 3, GL_FLOAT, GL_FALSE, offsetof(Vertex, Bitangent));
glVertexArrayAttribBinding(mesh.VAO, 0, binding_index);
glVertexArrayAttribBinding(mesh.VAO, 1, binding_index);
glVertexArrayAttribBinding(mesh.VAO, 2, binding_index);
glVertexArrayAttribBinding(mesh.VAO, 3, binding_index);
glVertexArrayAttribBinding(mesh.VAO, 4, binding_index);
Normal Way:
glGenVertexArrays(1, &mesh.VAO);
glGenBuffers(1, &mesh.VBO);
glGenBuffers(1, &mesh.EBO);
glBindVertexArray(mesh.VAO);
glBindBuffer(GL_ARRAY_BUFFER, mesh.VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), mesh.vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), mesh.indices.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, Normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, TexCoords));
// vertex tangent
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent));
// vertex bitangent
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent));

Not able to create object using DSA

This code works fine.
glGenVertexArrays(1, &m_VAO);
glGenBuffers(1, &m_VBO);
glGenBuffers(1, &m_EBO);
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(VertexFormat), &data[0] , GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GL_UNSIGNED_INT), &indices[0], GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(6 * sizeof(float)));
glBindVertexArray(0);
But when i try to change it to DSA nothing gets drawn on the screen.
glCreateBuffers(1, &m_VBO);
glNamedBufferStorage(m_VBO, data.size() * sizeof(VertexFormat), &data[0], GL_DYNAMIC_STORAGE_BIT);
glCreateBuffers(1, &m_EBO);
glNamedBufferStorage(m_EBO, indices.size() * sizeof(unsigned int), &indices[0], GL_DYNAMIC_STORAGE_BIT);
glCreateVertexArrays(1, &m_VAO);
glVertexArrayVertexBuffer(m_VAO, 0, m_VBO, 0, data.size() * sizeof(VertexFormat));
glVertexArrayElementBuffer(m_VAO, m_EBO);
glEnableVertexArrayAttrib(m_VAO, 0);
glEnableVertexArrayAttrib(m_VAO, 1);
glEnableVertexArrayAttrib(m_VAO, 2);
glVertexArrayAttribFormat(m_VAO, 0, 3 , GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(m_VAO, 1, 3 , GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(m_VAO, 2, 2 , GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribBinding(m_VAO, 0, 0);
glVertexArrayAttribBinding(m_VAO, 1, 0);
glVertexArrayAttribBinding(m_VAO, 2, 0);
What is the issue in the DSA section of code?
You did not transfer over two pieces of information.
You didn't specify the stride in glVertexArrayVertexBuffer correctly. When using separate attribute format, a stride of 0 doesn't mean "tightly packed"; it means exactly what it says: zero bytes will be added to get the next array element.
You also didn't specify the offsets for each attribute in glVertexArrayAttribFormat the way you did with glVertexAttribPointer.

With OpenGL 4.3, how do I correctly use glVertexAttribFormat/Binding?

I was trying to use this feature, here is what I did:
glGenBuffers(1, &m_vbo_id);
glGenVertexArrays(1, &m_vao_id);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
glBindVertexArray(m_vao_id);
glEnableVertexAttribArray(0); // Vertices
glEnableVertexAttribArray(1); // Color
glEnableVertexAttribArray(2); // Texture coordinates
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(0, m_vbo_id);
glVertexAttribFormat(1, 4, GL_FLOAT, GL_FALSE, 24* sizeof(float));
glVertexAttribBinding(1, m_vbo_id);
glVertexAttribFormat(2, 2, GL_FLOAT, GL_FALSE, 42* sizeof(float));
glVertexAttribBinding(2, m_vbo_id);
glBindVertexBuffer(m_vbo_id, m_buffer_data[00], 54*sizeof(float), 0);
glBindVertexBuffer(m_vbo_id, m_buffer_data[18], 54*sizeof(float), 0);
glBindVertexBuffer(m_vbo_id, m_buffer_data[42], 54*sizeof(float), 0);
m_bufferdata is a std::array<float, 54>, containing all the floats, which is rebuilt every frame.
This will generate a GL_INVALID_OPERATION. Can anyone tell me why or how I correctly order the calls?
The second argument of glVertexAttribBinding is not the buffer object, but the binding index.
The arguments of glBindVertexBuffer are the binding index, the buffer object, the offset and the stride. Stride is (3+4+2)*sizeof(float) for a tightly packed buffer:
int bindingindex = 0;
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(0, bindingindex);
glVertexAttribFormat(1, 4, GL_FLOAT, GL_FALSE, 24* sizeof(float));
glVertexAttribBinding(1, bindingindex);
glVertexAttribFormat(2, 2, GL_FLOAT, GL_FALSE, 42* sizeof(float));
glVertexAttribBinding(2, bindingindex);
glBindVertexBuffer(bindingindex, m_vbo_id, 0, 9*sizeof(float));

How to configure VAO and VBO for custom made Structure

I am trying to construct a bar.
First i declare a structure
struct VertexFormat
{
glm::vec3 positions;
glm::vec3 normal;
glm::vec2 texCoord;
VertexFormat(glm::vec3 pos, glm::vec3 norm, glm::vec2 coord) : positions(pos), normal(norm), texCoord(coord)
{ }
};
and than i configure the VAO and the VBO
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(VertexFormat), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size(), &indices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, data.size() * sizeof(VertexFormat), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, data.size() * sizeof(VertexFormat), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, data.size() * sizeof(VertexFormat), (void*)(6 * sizeof(float)));
glBindVertexArray(0);
Nothing gets drawn when i issue the drawing commands
glBindVertexArray(m_VAO);
glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
My question is that am i defining the offsets for the data in the buffer correctly ?
There are several problems with this code:
First, the amount of data uploaded to the EBO is wrong. The size of the data has to be given in byte. Assuming that indices contains unsigned integers, the code should be:
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
Then, stride describes the offset between two consecutive vertices in the buffer, not the total size of your data. In your case, every vertex starts sizeof(VertexFormat) after the previous one.
The correct code should be:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)(6 * sizeof(float)));

OpenGL drawing several objects

How usually people draw several objects in OpenGL 3.3+?
I have 2 objects: a terrain and a sphere. For each object i have 2 arrays(of vertices and indices). I tried to set different VBO and IBO(like this):
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)12);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)20);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
glDrawElements(GL_TRIANGLES, (size-1)*(size-1)*6, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_VBOsphere);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBOsphere);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
but looks like GPU calculates/draw everything only after closing of this function and I see only a sphere. So, what should I do?
It looks like you misunderstood the implications of binding a buffer, and the correct sequence of calls.
You expected that in this sequence, the draw call would get its vertices from the VBO with id m_VBO:
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
glDrawElements(GL_TRIANGLES, (size-1)*(size-1)*6, GL_UNSIGNED_INT, 0);
That's not the way it works. The current GL_ARRAY_BUFFER binding has absolutely no effect on the draw call.
You need to have the right VBO bound when glVertexAttribPointer() is called. Beyond the direct arguments that specify values for the setup of the corresponding attribute (format, stride, etc), this call also specifies that the currently bound VBO is used as the source for the attribute data.
Therefore, you need the glVertexAttribPointer() calls for each object, and call them after binding the corresponding VBO.
The call sequence is then:
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)12);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)20);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
glDrawElements(GL_TRIANGLES, (size-1)*(size-1)*6, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_VBOsphere);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)12);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)20);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBOsphere);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
If you want to reduce the number of setup calls you need before each draw call, look up Vertex Array Objects (VAO).