Search code examples
openglglfwglew

Drawing a cube using Indexed Draw in modern OpenGL


I'm trying to draw a cube using indexed draw in OpenGL 3.3. But it does not show up right... Here is what I tried doing.

GLfloat vertices01[] = {
  -1.0f,1.0f,0.0f,
  -1.0f,-1.0f,0.0f,
  1.0f,1.0f,0.0f,
  1.0f,-1.0f,0.0f,
  -1.0f,1.0f,-1.0f,
  -1.0f,-1.0f,-1.0f,
  1.0f,1.0f,-1.0f,
  1.0f,-1.0f,-1.0f
};
unsigned int indices01[] = {
  0, 2, 3, 1,
  2, 6, 7, 3,
  6, 4, 5, 7,
  4, 0, 1, 5,
  0, 4, 6, 2,
  1, 5, 7, 3
};


Mesh* obj3 = new Mesh();
obj3->CreateMesh(vertices01, indices01, 24, 24);
meshList.push_back(obj3);

meshList[0]->RenderMesh();

//in mesh class indexCount = numOfIndices;

glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0])*numOfIndices, indices, GL_STATIC_DRAW);

glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0])*numOfVertices, vertices, GL_STATIC_DRAW);

glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

glBindVertexArray(0);

glBindVertexArray(VAO);

//bind ibo
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);

glDrawElements(GL_TRIANGLES,indexCount, GL_UNSIGNED_INT, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);

the output shows a partial cube whose each side had one triangle each and also a triangle going through it's diagonal


Solution

  • If you use a compatibility profile context, then you can keep your indices an use GL_QUADS instead of GL_TRIANGLES. But that's deprecated (Legacy OpenGL ).

    Since the primitive type is GL_TRIANGLES, each side of the cube has to be formed by 2 triangles. See Triangle primitives.

    Change the index buffer to solve the issue:

    unsigned int indices01[] = {
      0, 2, 3, 0, 3, 1,
      2, 6, 7, 2, 7, 3,
      6, 4, 5, 6, 5, 7,
      4, 0, 1, 4, 1, 5,
      0, 4, 6, 0, 6, 2,
      1, 5, 7, 1, 7, 3,
    };
    

    An alternative solution would be to use the primitive type GL_TRIANGLE_STRIP and a Primitive Restart index.

    Enable primitive restart and define a restart index:

    e.g.

    glEnable( GL_PRIMITIVE_RESTART );
    glPrimitiveRestartIndex( 99 );
    

    Define 2 triangle strips, which are separated by the restart index:

    unsigned int indices01[] = {
        0, 1, 2, 3, 6, 7, 4, 5,
        99, // 99 is the restart index
        7, 3, 5, 1, 4, 0, 6, 2
    };
    int indexCOunt = 17;
    

    And draw the elements:

    glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, 0);
    

    Note, the Index buffer binding is stored in the Vertex Array Object.
    So it is sufficient to bind the index buffer once, when the VAO is setup:

    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);  
    
    // [...]
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
    
    // [...]
    
    // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); <---- delete this
    
    glBindVertexArray(0);
    

    Then it is superfluous to bind the index buffer again, before the draw call:

    glBindVertexArray(VAO);
    
    // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); <---- now this is superfluous 
    
    glDrawElements(GL_TRIANGLES,indexCount, GL_UNSIGNED_INT, 0);
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);