OpenGL, known as Open Graphics Library, is a graphics API that allows us to create and render 2D and 3D graphics in our applications. It has a set of functions that assist us in creating our graphic objects.
glDrawElements functionThe glDrawElements is a function in Open GL that allows us to draw shapes on the screen using vertices and indices. The vertices represent the corners of our shape while, indices represent the order in which vertices are connected in the shape.
The syntax of the function is following:
void glDrawElements(GLenum renderMode, GLsizei elementCount, GLenum indexType, const void* indices);
RenderMode : It is the type of geometry to be drawn or rendered. It can be points, lines, or triangles.
elementCount: It is the number of indices to be rendered.
indexType: It is the type of indices.
indices: These are the points to the array of indices that define the vertices to be rendered.
glDrawElements draws nothingThere can be various reasons why our glDrawElements function draws nothing. These reasons include the following:
When we draw shapes in OpenGL, we use shaders. Shaders are small programs that run on the graphics card and define how each vertex and fragment of an object should be rendered. We have to ensure the correct setup of the shader program. If the shaders setup is incorrect, the objects may not appear on the screen.
In the following code, we use glAttachShader function to attach the vertexShader and fragmentShader to our shaderProgram. Then we use the glLinkProgram function to link our shaderProgram to the code. The variable success checks if we encounter any errors.
// Attaching and linking shadersglAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// Checking for any errorsint success;glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (success==false) {char errorMessage[512];glGetProgramInfoLog(shaderProgram, 512, NULL, errorMessage);cout << "Shader program linking error: " << errorMessage << endl;// Handling the error appropriately}
Before using glDrawElements function, we bind the vertex buffer objects (VBO) and element buffer objects (EBO) correctly.
VBO contains our vertex data or vertices.
EBO contains our index data or indices.
In the following code, we use glBindBuffer function to bind our buffer objects.
// Binding the vertex buffer objectglBindBuffer(GL_ARRAY_BUFFER, Vetrex_buffer_objects);// Binding the element buffer objectglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer_objects);
Each vertex has its attributes, such as position and color. If the vertex attributes are not set up correctly, the vertices may not be interpreted correctly during rendering, which results in the glDrawElements function drawing nothing.
In the following code, we set the attribute for a vertex with its attribute at position 0. The position of attributes starts from index 0. We use glVertexAttribPointer function to interpret the vertex data for a specific attribute. Then we use glEnableVertexAttribArray function to enable the attribute array for the specified attribute index so that it can be used during rendering.
// Specifying the vertex attribute pointersglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);
// Setting the view matrixglm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));glUniformMatrix4fv(viewUniformLocation, 1, GL_FALSE, glm::value_ptr(view));// Setting the projection matrixglm::mat4 projection = glm::perspective(glm::radians(45.0f), screenWidth / screenHeight, 0.1f, 100.0f);glUniformMatrix4fv(projectionUniformLocation, 1, GL_FALSE, glm::value_ptr(projection));
To check the proper working of our getIdrawElements, we ensure that depth testing is enabled and face culling is disabled in our code. Depth testing and face culling are techniques used in 3D rendering to determine which objects should be visible on the screen.
We can enable depth testing and disable face culling using the following functions.
// Enabling depth testingglEnable(GL_DEPTH_TEST);// Disabling face cullingglDisable(GL_CULL_FACE);
Before calling the glDrawElements function, we have to ensure we send correct data in the parameters of our function.
We have to ensure that the numIndices and the indexType matches our data. Moreover, we must check that we set the correct drawing mode to draw our desired shape. The offset specifies the starting point from where the indices should be read.
// Drawing using glDrawElementsglDrawElements(renderMode, numIndices, indexType, offset);
glDrawElementsIn the following code, we set up a basic OpenGL application that creates a window and renders a triangle on the screen.
#include <GL/glew.h>
#include <GLFW/glfw3.h>
int main()
{
// Initializing GLFW
glfwInit();
// Creating a window
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Window", NULL, NULL);
if (window == NULL)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initializing GLEW
if (glewInit() != GLEW_OK)
{
glfwTerminate();
return -1;
}
// Setting up vertex data
float vertices[] = {
-0.5f, -0.5f, 0.0f, // Vertex 1
0.5f, -0.5f, 0.0f, // Vertex 2
0.0f, 0.5f, 0.0f // Vertex 3
};
// Setting up index data
unsigned int indices[] = {
0, 1, 2 // Indices for drawing a triangle
};
// Creating vertex buffer object (VBO)
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Creating element buffer object (EBO)
GLuint EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Setting up vertex attributes
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Rendering loop
while (!glfwWindowShouldClose(window))
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Draw the triangle using glDrawElements
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
// Cleaning up
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
// Terminate GLFW
glfwTerminate();
return 0;
}
When the glDrawElements function in OpenGL draws nothing, there can be various negligence and inconsistencies causing the error. It is crucial to investigate each potential cause to identify the specific problem.
Free Resources