Reputation: 2033
I want to render 100,000+ number of cubes (made of 36 vertices, using indexed geometry in the same VAO) with one draw call, is this possible?
All the geometry data (vertice data) is the same, since they are all cubes. The projection and camera view is also the same and passed to the vertex shader as uniforms.
Render.cpp
for (auto chunk : world->chunks) {
for (auto cube : chunk.blocks) {
glBindTexture(GL_TEXTURE_CUBE_MAP, textures[cube.texture]);
// Model - transform_z * transform_y * transform_x * transform_translation * transform_scaling
model = Mat4<GLfloat>();
model = model.translate(cube.position);
model = model.scale(cube.scale);
model = model * transformation_matrix_x(cube.theta_x);
model = model * transformation_matrix_y(cube.theta_y);
model = model * transformation_matrix_z(cube.theta_z);
glUniformMatrix4fv(gl_model, 1, GL_TRUE, model.data());
// One draw call per cube is not scalable
glDrawElements(GL_TRIANGLES, cube.indices.size(), GL_UNSIGNED_INT, 0);
}
// A draw call like this would be nice since they share so much data.
// glDrawLotsOfElements(GL_TRIANGLES, cube.indices.size() * numCubes, GL_UNSIGNED_INT, 0);
}
Vertex shader
#version 330 core
in vec3 position;
in vec4 vColor;
out vec4 fColor;
out vec3 fTexcoord;
// Model
uniform mat4 model;
// View or a.k.a camera matrix
uniform mat4 camera_view;
// Projection
uniform mat4 projection;
void main() {
gl_Position = projection * camera_view * model * vec4(position, 1.0f);
fColor = vColor;
fTexcoord = normalize(position);
}
The number of cubes are dynamic, if that matters.
Upvotes: 1
Views: 870
Reputation: 119
I used instanced rendering a while ago when rendering particles, so we'll see if this can point you in the right direction.
Before your game loop you will call a function where you render your scene. In the function you can setup the model matrices like this, so you can have each cube at a different position in the world:
//matrices for the cubes
//set amount by the number of cubes you want to draw
glm::mat4* modelMatrices;
modelMatrices = new glm::mat4[amount];
You will then enter a loop where you will give each cube a different position
for (GLuint i = 0; i < amount; i++)
{ //use a function like rand() to get the x,y,z values different
glm::mat4 model;
model = glm::translate(model, glm::vec3(x, y, z));
modelMatrices[i] = model;
}
Now it looks a bit different when filling the buffers, because you have to send the model matrices (mat4) as an attribute to the GPU side, so you will need 4 vertex attribute pointers for that, and also don't forget
glVertexAttribDivisor(1, 1);
glVertexAttribDivisor(2, 1);
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
and at last
glDrawArraysInstanced(GL_POINTS, 0, 1, amount); //replace to specify for a cube
Then you will have to use glDrawArraysInstanced
one more time when you actually render the cubes.
On the GPU side you only have to replace the usual model matrix with the one you sent before.
Upvotes: 1