Why does a 'sequential' arrangement of vertex attribute data lead to crash? - opengl

I have an OpenGL application with shaders that can render objects with texture.
When i create simple rectangle with 'interleaved' attributes like this:
GLuint createRectInterleaved(float fW, float fH) {
GLuint vao;
GLuint rect_buffer;
float vertex_data[] = {
// position normal texture coords
-fW/2, -fH/2, 0, 0, 0, 1, 0, 0,
fW/2, -fH/2, 0, 0, 0, 1, 1, 0,
fW/2, fH/2, 0, 0, 0, 1, 1, 1,
-fW/2, -fH/2, 0, 0, 0, 1, 0, 0,
fW/2, fH/2, 0, 0, 0, 1, 1, 1,
-fW/2, fH/2, 0, 0, 0, 1, 0, 1};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &rect_buffer);
glBindBuffer(GL_ARRAY_BUFFER, rect_buffer);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertex_data),
vertex_data,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (3*sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (6*sizeof(float)));
glEnableVertexAttribArray(2);
return vao;
}
then the application works and the square is rendered with its texture as expected.
But if i use a sequential arrangement of the vertex attributes:
GLuint createRectSequential(float fW, float fH) {
GLuint vao;
GLuint rect_buffers[3];
float vertex_positions[18] = {
-fW/2, -fH/2, 0,
fW/2, -fH/2, 0,
fW/2, fH/2, 0,
-fW/2, -fH/2, 0,
fW/2, fH/2, 0,
-fW/2, fH/2, 0};
float vertex_normals[18] = {
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1};
float vertex_tc[12] = {
0, 0,
1, 0,
1, 1,
0, 0,
1, 1,
0, 1};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(3, rect_buffers);
glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[0]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertex_positions),
vertex_positions,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[1]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertex_normals),
vertex_normals,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[2]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertex_tc),
vertex_tc,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);
glEnableVertexAttribArray(2);
return vao;
}
then my application crashes in the call to
glDrawArrays(GL_TRIANGLES, 0, 6);
Both VAOs are handled exactly the same - the only difference is the argument for glBindVertexArray() before drawing: either the interleaved or the sequential VAO.
If i comment out the creation of the texture attribute, the sequential VAO does not cause a crash.
What am i doing wrong in the 'sequential' version?
(edit: spelling mistake)

The glVertexAttribPointer are wrong in the second code sample. All of them operate on attribute 0. In the first version, they initialize all attributes from 0 to 2. Since you still enable those attributes but do not bind data to it, OpenGL tries to read from some memory that doesn't belong to the application.
The correct version would be:
glGenBuffers(3, rect_buffers);
glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[0]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertex_positions),
vertex_positions,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[1]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertex_normals),
vertex_normals,
GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
// /\ Corrected Attribute here
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[2]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertex_tc),
vertex_tc,
GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);
// /\ Corrected Attribute here
glEnableVertexAttribArray(2);

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));

Do I have to call glVertexAttribPointer() each frame, for each rendered mesh?

I have seen other people's code where they only called glVertexAttribPointer() when they initialized the vao. When I do that, only the first object in my scene gets rendered, but if I call it each frame * each object, everything renders fine... so does this mean I have to set glVertexAttribPointer() for each object before drawing? Or am I missing something?!
glBindVertexArray(mesh->getVao());
glBindBuffer(GL_ARRAY_BUFFER, mesh->getVbo());
for(int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
// Vertex Positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex UVs
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex Normals
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex Tangents
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex Binormals
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
// Draw
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getVbo());
glDrawElements(GL_TRIANGLES, mesh->getNumberOfIndices(), GL_UNSIGNED_SHORT, (void*)0);
for (int i = 0; i < 5; i++)
glDisableVertexAttribArray(i);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
This is 1 draw call per object. It works perfect, but do I really need to call glVertecAttribPointer() each frame for each object as such?
Vertex attribute pointers and index buffers are part of the VAO state, so they only have to be called once in the beginning.
Init:
glGenVertexArray(1, &vao);
glBindVertexArray(vao);
for(int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
// Vertex Positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex UVs
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex Normals
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex Tangents
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex Binormals
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
// Index Buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getVbo());
//Unbind VAO
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //Unbind the index buffer AFTER the vao has been unbinded
In each frame call
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, mesh->getNumberOfIndices(), GL_UNSIGNED_SHORT, (void*)0);
glBindVertexArray(0);

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

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.