I'm using OpenGL to draw a large tile map currently made up of 50 x 50 tiles. I'm using GLFW, GLEW and GLM to handle most of the OpenGL functions. When I try to draw the map it will only render at about 30 fps, as opposed to drawing one object at 1000+ fps. This is even if I'm drawing a single color for every tile instead of a texture. To draw the tiles I loop through the map and draw apply a transformation to a single VBO, answers such as this seem to imply that even though this is not the most effective method for rendering large groups of items, I should still be able to get decent framerates. I can't figure out how to increase my framerate without reducing the number of tiles I'm drawing. Here is the relevant code to drawing the tiles:
Code to draw the tiles (called every frame):
for (int i = 0; i < map.getWidth(); i++) {
for (int j = 0; j < map.getHeight(); j++) {
renderer->drawSprite(glm::vec2(i * tilesize, j * tilesize), glm::vec2(tilesize, tilesize));
}
}
Renderer code:
Renderer(Shader& shader) {
this->shader = shader;
GLuint VBO;
GLfloat vertices[] = {
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 1.0f, 0.0f
};
glGenVertexArrays(1, &this->quadVAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(this->quadVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void drawSprite(int spritex, int spritey, glm::vec2 position, glm::vec2 size = glm::vec2(10, 10), GLfloat rotate = 0.0f, glm::vec3 color = glm::vec3(1.0f)) {
this->shader.use();
//model transformations
this->shader.setMat4("model", model);
glBindVertexArray(this->quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
}
Vertex Shader:
#version 460 core
in vec2 TexCoords; //currently not used since I'm trying to draw colors
out vec4 color;
void main() {
color = vec4(1.0, 0.5, 0.5, 1.0);
}
Fragment Shader:
#version 460 core
layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() {
TexCoords = vertex.zw;
gl_Position = projection * view * model * vec4(vertex.xy, 0.0, 1.0);
}
glGetString(GL_RENDERER) returns that the program is using my gtx 1070 so my computer should easily be able to render this number of objects. Is there a something wrong with the way I'm drawing the tiles? Or is drawing this number of objects in this way just not a feasible way to draw the tiles?
First, as you are using the same shader and the same VAO for each draw, you should use your shader and bind your VAO once (before your two loops). This should really improve your performance.
To go further I recommand you to look the function glDrawArraysInstanced which allows to draw all your tiles with only one draw call.
You will need to pass all the model matrices to the shader (via a texture or a shader storage buffer depending on the version of OpenGL you are targetting) and use gl_InstanceID to retrieve your matrix.