3
votes

I just started learning OpenGL and I am having some trouble with glDrawElements. I am trying to draw two triangles using glDrawElements with GL_TRIANGLE, but only one triangle appears.

What is expected: glDrawElements draw two triangles with vertices

(0,0) (1,1) (-1,1) and (0,0) (-1,-1) (1,-1)

What happens: glDrawElements draw one triangle with vertices (0,0) (1,1) (-1,1)

Short, Self Contained, Correct (Compilable), Example:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

int main(int argc, char *argv[])
{
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(640, 480, "Sample code does not display two triangles", NULL, NULL);
    glfwMakeContextCurrent(window);

    glewInit();

    GLfloat vertices[] {
        +0.0f, +0.0f, //0
        +1.0f, +1.0f, //1
        -1.0f, +1.0f, //2
        -1.0f, -1.0f  //3
        +1.0f, -1.0f  //4
    };

    GLuint vertexBufferID;
    glGenBuffers(1, &vertexBufferID);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);

    GLuint indexBufferID;
    GLushort indices[] {0,1,2, 0,3,4};
    glGenBuffers(1, &indexBufferID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    while (!glfwWindowShouldClose(window))
    {
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

This sample opens a 640x480 GLFW window, displays a triangle with vertices in both upper corners and the third vertex in the middle of the window. The other triangle, with vertices in both bottom corners and the third vertex in the middle, is missing. Why is that?

Specs:
OS: Linux Mint 17
GPU: nVidia GTX 275
GPU driver: 331.67
GLEW version: 1.10.0
GLFW version: 3.0.4

1
glDrawElements doesn't use an index buffer. You have to pass in the indices pointer as the last parameter instead of 0.indeterminately sequenced
@indeterminatelysequenced: I was also going to start my comment with "what?", but genpfault beat me to it. Of course it uses index buffers. How else would you use index buffers?Reto Koradi
Just one (probably dumb) question: aren't we supposed to always write shaders?Antonio Ribeiro

1 Answers

7
votes

Commas are important. This:

GLfloat vertices[] =
{
    +0.0f, +0.0f, //0
    +1.0f, +1.0f, //1
    -1.0f, +1.0f, //2
    -1.0f, -1.0f  //3
    +1.0f, -1.0f  //4
};
size_t elements = sizeof( vertices ) / sizeof( GLfloat ) = 9(!)

is not the same as this:

GLfloat vertices[] =
{
    +0.0f, +0.0f, //0
    +1.0f, +1.0f, //1
    -1.0f, +1.0f, //2
    -1.0f, -1.0f, //3
    +1.0f, -1.0f  //4
};
size_t elements = sizeof( vertices ) / sizeof( GLfloat ) = 10

Note the added comma at the end of line 3.

If vertices only has 9 elements then when glDrawElements() goes to try to read the fifth vertex only the X coordinate will be valid. The Y coordinate will contain garbage if you're lucky, a segfault if you're not.

Also, you shouldn't use the generic vertex attribute functions without specifying some shaders.

All together:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

int main(int argc, char *argv[])
{
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(640, 480, "Sample code does not display two triangles", NULL, NULL);
    glfwMakeContextCurrent(window);

    glewInit();

    GLfloat vertices[] =
    {
        +0.0f, +0.0f, //0
        +1.0f, +1.0f, //1
        -1.0f, +1.0f, //2
        -1.0f, -1.0f, //3
        +1.0f, -1.0f, //4
    };

    GLuint vertexBufferID;
    glGenBuffers(1, &vertexBufferID);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glEnableClientState( GL_VERTEX_ARRAY );
    glVertexPointer( 2, GL_FLOAT, 0, 0 );

    GLuint indexBufferID;
    GLushort indices[] = { 0,1,2, 0,3,4 };
    glGenBuffers(1, &indexBufferID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    while (!glfwWindowShouldClose(window))
    {
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}