I'm learning to use opengl and things have been going well for the last week. But I ran into an issue when trying to render both 2d and 3d objects using batch rendering. What i've read about vao's is that you can use them but you don't have to. Opengl will create a default one, unless you are running the core profile which you will have to create one. But you can just ignore them if you want. But by using them you are supposed to be able to just bind the vertex array that is associated with the VBO and IBO you want to draw. Is this the only use of them? Just being able to bind the VBO and IBO in one function call rather than 2?
Either way, my code doesn't seem to want to run without the VAO. and it doesn't want to work unless i bind the vao, vbo, and ibo. I'm very confused. from what i've read this is wrong. I should be able to just bind the vao.
in my code I use the concept of layers to create different projections to render to. Each layer has it's own vertex buffer and index buffer, and the vbo, ibo, and vao objects for the opengl bindings. Below is the code I use to create my layers.
void create_2d_layer(_render_layer* layer, u32 num_objects) {
layer->vpo = 4; // 4 vertices per object
layer->ipo = 6; // 6 indices per object
layer->num_vertices = num_objects * layer->vpo;
layer->num_indicies = num_objects * layer->ipo;
layer->vertex_buffer = (f32*)malloc(layer->num_vertices * sizeof(_vertex));
layer->index_buffer = (u32*)malloc(layer->num_indicies * sizeof(u32));
setup_buffers(layer);
}
void create_3d_layer(_render_layer* layer, u32 num_objects) {
layer->vpo = 8; // 8 vertices per object
layer->ipo = 36; // 36 indices per object
layer->num_vertices = num_objects * layer->vpo;
layer->num_indicies = num_objects * layer->ipo;
layer->vertex_buffer = (f32*)malloc(layer->num_vertices * sizeof(_vertex));
layer->index_buffer = (u32*)malloc(layer->num_indicies * sizeof(u32));
setup_buffers(layer);
}
//GLCALL is a macro to do some debug error handling.
static void setup_buffers(_render_layer* layer) {
GLCALL(glGenVertexArrays(1, &layer->vao));
GLCALL(glBindVertexArray(layer->vao));
GLCALL(glGenBuffers(1, &layer->vbo));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, layer->vbo));
GLCALL(glBufferData(GL_ARRAY_BUFFER, layer->num_vertices * sizeof(_vertex), 0, GL_DYNAMIC_DRAW));
GLCALL(glEnableVertexAttribArray(0));
GLCALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(_vertex), (const void*)offsetof(_vertex, position)));
GLCALL(glEnableVertexAttribArray(1));
GLCALL(glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(_vertex), (const void*)offsetof(_vertex, colour)));
GLCALL(glEnableVertexAttribArray(2));
GLCALL(glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(_vertex), (const void*)offsetof(_vertex, texture_coord)));
GLCALL(glEnableVertexAttribArray(3));
GLCALL(glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(_vertex), (const void*)offsetof(_vertex, texture_id)));
GLCALL(glGenBuffers(1, &layer->ibo));
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, layer->ibo));
GLCALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, layer->num_indicies * sizeof(u32), 0, GL_DYNAMIC_DRAW));
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
GLCALL(glBindVertexArray(0));
}
After I do all my updating I update the buffers with the new vertex data:
void update_buffers(_render_layer* layer) {
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, layer->vbo));
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, layer->ibo));
GLCALL(glBufferSubData(GL_ARRAY_BUFFER, 0, layer->num_vertices * sizeof(_vertex), layer->vertex_buffer));
GLCALL(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, layer->num_indicies * sizeof(u32), layer->index_buffer));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
and to draw each layer:
void draw_layer(_render_layer* layer) {
GLCALL(glBindVertexArray(layer->vao));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, layer->vbo));
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, layer->ibo));
// layer->index is the index of the next object to add to the layer
// in this case we can use it as the number of objects in the layer
GLCALL(glDrawElements(GL_TRIANGLES, layer->index * layer->ipo, GL_UNSIGNED_INT, 0));
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
GLCALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
GLCALL(glBindVertexArray(0));
}
If I comment out the vao binding code then nothing renders. but if I just bind the vao my program crashes when calling glDrawElements. From what I've read I should be able to do either. but I need to bind all 3 to render properly. Hopefully someone can help clear up this confusion.