I am trying to render two triangles on the screen at once, using two different VBOs so that I can add textures later (to my understanding, if you want to add different textures, you must make two VBOs?). I have tried using a combination of VAOs (both examples) and VAOs and IBOs (1st example).
Edit: As Stackoverflow doesn't recognise the tag, I'd like to clarify that IBO stands for Index Buffer Object
In both cases, I get a blank red screen.
I have previously managed to draw four triangles onto the screen using only one VBO and one IBO, but no VAO, putting all of the vertices into the one VBO, however I feel I need to learn how to draw multiple VBOs, as having everything in one VBO will become cumbersome and inefficient as greater numbers of objects are added.
I have already consulted other related questions as well as several tutorials, but have failed to find the information I am looking for in them (the tutorials tending to only describe drawing one item)
https://learnopengl.com/Getting-started/OpenGL
OpenGL - VAO, VBO, IBO, glDrawElements not displaying
What is the role of glBindVertexArrays vs glBindBuffer and what is their relationship?
Textured triangles with OpenGL using VBO/IBO
Here is my source code:
Render loop
private void setupLoop() {
GL.createCapabilities();
debugProc = GLUtil.setupDebugMessageCallback();
// Set the clear color
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
while (!glfwWindowShouldClose(window)) {
Engine.makeAndDrawBuffersForTwoTriangles();
renderLoop();
}
}
private void renderLoop() {
// Run the rendering loop until the user has attempted to close
// the window or has pressed the ESCAPE key.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
float aspect = (float) width / height;
glLoadIdentity();
glOrtho(-aspect, aspect, -1, 1, -1, 1);
glfwSwapBuffers(window); // swap the color buffers
// Poll for window events.
glfwPollEvents();
}
Defining my vertices and declaring my ids
static int vbo_left;
static int vao_left;
static int ibo_left;
static float left_vertices[] = { -0.5f, 0f, -0.25f, 0.5f, 0f, 0f };
static int left_indices[] = { 0, 1, 2, 3, 4, 5 };
static int vbo_right;
static int vao_right;
static int ibo_right;
static float right_vertices[] = { 0f, 0f, 0.25f, -0.5f, 0.5f, 0f };
static int right_indices[] = { 0, 1, 2, 3, 4, 5 };
1st Engine class
public static void makeAndDrawBuffersForTwoTriangles() {
// VBO
vbo_left = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
glBufferData(GL_ARRAY_BUFFER, left_vertices, GL_STATIC_DRAW);
// IBO
ibo_left = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_left);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
(IntBuffer) BufferUtils.createIntBuffer(left_indices.length).put(left_indices).flip(), GL_STATIC_DRAW);
glVertexPointer(2, GL_FLOAT, 0, 0L);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// VAO
vao_left = glGenVertexArrays();
glBindVertexArray(vao_left);
glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 2, 0);
glBindVertexArray(0);
// VBO
vbo_right = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo_right);
glBufferData(GL_ARRAY_BUFFER, right_vertices, GL_STATIC_DRAW);
// IBO
ibo_right = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_right);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
(IntBuffer) BufferUtils.createIntBuffer(right_indices.length).put(right_indices).flip(),
GL_STATIC_DRAW);
glVertexPointer(2, GL_FLOAT, 0, 0L);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// VAO
vao_right = glGenVertexArrays();
glBindVertexArray(vao_right);
glBindBuffer(GL_ARRAY_BUFFER, vbo_right);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 2, 0);
glBindVertexArray(0);
// Unbind all
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// Draw elements
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_left);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 2, 0);
glDrawElements(GL_TRIANGLES, left_indices.length, GL_UNSIGNED_INT, 0L);
glBindBuffer(GL_ARRAY_BUFFER, vbo_right);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_right);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 2, 0);
glDrawElements(GL_TRIANGLES, right_indices.length, GL_UNSIGNED_INT, 0L);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
/*
// Draw Arrays
glBindVertexArray(vao_left);
glDrawArrays(GL_TRIANGLES, 0, left_indices.length);
glBindVertexArray(vao_right);
glDrawArrays(GL_TRIANGLES, 0, right_indices.length);
glBindVertexArray(0);
*/
2nd Engine class
public static void makeAndDrawBuffersForTwoTriangles() {
vbo_left = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
glBufferData(GL_ARRAY_BUFFER, left_vertices, GL_STATIC_DRAW);
vao_left = glGenVertexArrays();
glBindVertexArray(vao_left);
glBindBuffer(GL_ARRAY_BUFFER, vao_left);
glVertexAttribPointer(vao_left, 2, GL_FLOAT, false, 2, 0);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
vbo_left = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
glBufferData(GL_ARRAY_BUFFER, left_vertices, GL_STATIC_DRAW);
vao_left = glGenVertexArrays();
glBindVertexArray(vao_left);
glBindBuffer(GL_ARRAY_BUFFER, vao_left);
glVertexAttribPointer(vao_left, 2, GL_FLOAT, false, 2, 0);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(vao_left);
glDrawArrays(GL_TRIANGLES, 0, left_vertices.length);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(vao_right);
glDrawArrays(GL_TRIANGLES, 0, right_vertices.length);
}
The Index buffers binding is stated in the Vertex Array Object. Invoking glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
breaks the binding of the index buffer to the VAO.
You have to delete glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
.
Furthermore, the vertex specification is stored in the VAO, so the VAO has to be bound, before the array of generic vertex attribute data is specified and the index buffer is bound:
// VBO
vbo_left = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
glBufferData(GL_ARRAY_BUFFER, left_vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// IBO
ibo_left = glGenBuffers();
// VAO
vao_left = glGenVertexArrays();
glBindVertexArray(vao_left);
// IBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_left);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
(IntBuffer) BufferUtils.createIntBuffer(left_indices.length).put(left_indices).flip(), GL_STATIC_DRAW);
// vertex specification
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_left);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 2, 0);
Note, in compare to the index buffer, the array buffer binding is a global state.
Each attribute which is stated in the VAOs state vector may refer to a different ARRAY_BUFFER
. This reference is stored when glVertexAttribPointer
(respectively glVertexPointer
) is called. Then the buffer which is currently bound to the target ARRAY_BUFFER
is associated to the attribute and the name (value) of the object is stored in the state vector of the VAO.
But the index buffer is a state of the VAO. When a buffer is bound to the target ELEMENT_ARRAY_BUFFER
, then this buffer is associated to the vertex array object which is currently bound.