1
votes

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

https://www.lwjgl.org/guide

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

    }
1

1 Answers

1
votes

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.