I’m trying to do a batch renderer, where everything is submitted for a frame, and then it’s batched into as few draw commands as possible. Using Core 3.3.
I have VBO1 with interleaved vertex attributes. It contains Position, Normal, and UVs. I’ve loaded it with the vertex data for a Quad, followed by a Cube.
VBO2 will later contain model matrix vertex attributes.
I have an IBO with indices to draw the Quad (6 indices), followed by indices to draw the Cube (36 indices). The cube indices’s values restart at 0, hence the need for Base Vertex type calls.
I have a VAO that sets up attributes 0, 1, and 2 from VBO1 (for position, normal, uv), and sets up attribute 3, 4, 5, 6 from VBO2 (for model mat4). The attribute divisor for 3, 4, 5, 6 is set to 1.
When the user submits a thing to render, they’ll provide a model matrix. This info is stored in a container until it’s time to batch everything.
What I do is:
- Sort the submitted render requests based upon Mesh (quad or cube atm), followed by distance from the camera view.
- Loop through the sorted list
- For every item in the list, copy its model matrix to VBO2, starting from offset 0.
- For every item in the list, keep track of the how many instances of each mesh need to be drawn
At the end of this VBO1 is unchanged, IBO is unchanged, but now VBO2 is loaded up with model matrices in the order required for each model instance. I.e., all the cube’s model matrices, ordered by distance from camera, followed by all the quad’s model matrices etc. I’ve verified this via RenderDoc.
Then, I call glDrawElementsInstancedBaseVertex for each mesh that needs to be drawn (i.e. Cube, followed by Quad).
The problem is that if I’m drawing cubes first, I’ll submit:
glDrawElementsInstancedBaseVertex(GL_TRIANGLES, 36, // because there are 36 indices for the mesh GL_UNSIGNED_INT, sizeof(GLuint) * 6, // the start index in IBO for cube is 6 number of instances, 4); // because the base vertex index, the value to add to each of the cube's indices is 4, to skip over the quad's vertices.
The problem is that the base vertex value 4, is also used to skip over the first 4 vertices in VBO2. But I don’t want to skip in VBO2.
So, it is possible to control the base vertex value per buffer? Or attribute by attribute? Failing both of these, is there another way to achieve the same outcome (instanced rendering with instanced vertex attributes, but without rebinding VAOs?)