I am having trouble merging multiple simple objects into a single mesh with OpenGL. Before I go on I am aware of instancing and I'm certain that it's not what I want.
I'm drawing a cube with the following buffers:
float cubeVertices[] = {
-0.5f, 0.5f, 0.5f, //front top left
0.5f, 0.5f, 0.5f, //front top right
-0.5f, -0.5f, 0.5f, //front bottom left
0.5f, -0.5f, 0.5f, //front bottom right
-0.5f, 0.5f, -0.5f, //back top left
0.5f, 0.5f, -0.5f, //back top right
-0.5f, -0.5f, -0.5f, //back bottom left
0.5f, -0.5f, -0.5f //back bottom right
};
unsigned int cubeIndices[] = {
0, 2, 1, //FRONT
1, 2, 3,
0, 1, 4, //TOP
4, 1, 5,
1, 3, 5, //RIGHT
5, 3, 7,
2, 7, 3, //BOTTOM
7, 2, 6,
6, 2, 0, //LEFT
0, 4, 6,
6, 4, 5, //BACK
5, 7, 6
};
I then call glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr) which works as wanted.
Now my problem is if I want to draw multiple cubes in the same draw call (Still don't want instancing). My current way of rendering multiple cubes is by:
for (int y = 0; y < 2; ++y)
{
for (int x = 0; x < 2; ++x)
{
for (int z = 0; z < 2; ++z)
{
model = glm::mat4{1.0f};
model = glm::translate(model, glm::vec3{x, y, z});
shader.SetMat4("uModel", model);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr);
}
}
}
Which is fine for a 2x2x2 cube of cubes but if I want to go larger like 32x32x32 it starts to fall apart performance wise.
So I was wondering how I can merge this 2x2x2 cube into a single mesh and call glDrawElements(GL_TRIANGLES, 36 * 8, GL_UNSIGNED_INT, nullptr) or similar.
I've tried:
std::array<glm::vec3, 8> locations{};
for (int x = 0; x < 2; ++x)
{
for (int y = 0; y < 2; ++y)
{
for (int z = 0; z < 2; ++z)
{
locations[x + 2 * (y + 2 * z)] = glm::vec3{x, y, z};
}
}
}
glBindVertexArray(cubeVAO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO[1]);
glBufferData(GL_ARRAY_BUFFER, locations.size(), locations.data(), GL_DYNAMIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glEnableVertexAttribArray(1);
glBindVertexArray(0);
And using gl_Position = uProjection * uView * uModel * vec4(aPos * aLocation, 1.0f); where uModel is just a glm::mat4{1.0f}, aPos is from cubeVertices and aLocation is from the locations array.
I've got a couple ideas on why it doesn't work which I'll list.
First off: aLocation is different for every vertex instead of staying constant for the entire cube and then changing to the next location. Not sure how to do that. I could copy and paste the same location for every vertex I assume but that seems to defeat the purpose of using an element buffer in the first place.
Second: cubeIndices[] only holds enough indices for a single cube so I could also fix that by copy pasting the cubeIndices 8 times but doesn't that defeat the purpose of using an element buffer if I just have the same data 8 times?
So maybe a double element buffer could work?
I know instancing does seem like a really obvious solution but I guarantee that it's not what I am after.
I'm quite new to OpenGL so I don't have the most solid grasp of what I'm doing yet so I'm just trying to figure OpenGL out by making small projects. If someone could help it would be greatly appreciated.