Request for Advice - Optimizing My Drawing Calls...

Hello,

Folks here have given excellent advice before, I thought I would give this another try.

I have the code below which works but I believe I can do a better job of rendering.

Essentially I load my geometry in via a “for loop”, find the duplicate geometry to set up instancing, load the goods into OpenGL, sort the loaded geometry by whether it has transparency or not, and then draw.

I have two areas below where I believe I can speed things up but I am not sure how.

The first is the way I load materials: Current I am using a uniform buffer object and loading it in based on the contents of the file. I want to use a standard buffer so that I can just have one call to glDrawElementsInstanced (or a better equivalent) but the offset for the material is by an arbitrary amount based on what the object is rather than an easy-to-define offset like the number of vertices. You will see this in code below.

The second way is my MVP and normal matrices. Currently I calculate all of the instances MVPs CPU side and then push the data down to the graphics card via a glBufferSubData but is there a smarter way of doing things?

If you see anything else, I am all ears.

Thank you all for any guidance you can provide.

First, how I load my geometry into OpenGL:


void HighSpeedMeshCache::LoadIntoOpenGL()
{

	glGenVertexArrays(1, &Pointer_VAO);
	glBindVertexArray(Pointer_VAO);

	glGenBuffers(1, &Vertex_VBO);

	glBindBuffer(GL_ARRAY_BUFFER, Vertex_VBO);

	glBufferData(GL_ARRAY_BUFFER, TotalBufferSize, NULL, GL_STATIC_DRAW);

	glBufferSubData(GL_ARRAY_BUFFER, NULL, VerticesBufferSize, Vertices);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);

	if (HasNormals) {

		glBufferSubData(GL_ARRAY_BUFFER, NormalOffset, NormalBufferSize, Normals);

		glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
		glEnableVertexAttribArray(1);

	}

	if (HasUVs) {
		glBufferSubData(GL_ARRAY_BUFFER, UVOffset, UVBufferSize, UVs);

		glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0);
		glEnableVertexAttribArray(2);

	}

	glGenBuffers(1, &MVP_VBO);
	glBindBuffer(GL_ARRAY_BUFFER, MVP_VBO);

	glBufferData(GL_ARRAY_BUFFER, ModelMatrixIntances.size() * sizeof(glm::mat4), NULL, GL_DYNAMIC_DRAW);

	glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 0));
	glEnableVertexAttribArray(3);
	glVertexAttribDivisor(3, 1);

	glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 4));
	glEnableVertexAttribArray(4);
	glVertexAttribDivisor(4, 1);

	glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 8));
	glEnableVertexAttribArray(5);
	glVertexAttribDivisor(5, 1);

	glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(GLfloat) * 12));
	glEnableVertexAttribArray(6);
	glVertexAttribDivisor(6, 1);

	glGenBuffers(1, &NormalMatrix_VBO);
	glBindBuffer(GL_ARRAY_BUFFER, NormalMatrix_VBO);

	glBufferData(GL_ARRAY_BUFFER, ModelMatrixIntances.size() * sizeof(glm::mat3), NULL, GL_DYNAMIC_DRAW);

	glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(glm::mat3), (void*)(sizeof(GLfloat) * 0));
	glEnableVertexAttribArray(7);
	glVertexAttribDivisor(7, 1);

	glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(glm::mat3), (void*)(sizeof(GLfloat) * 3));
	glEnableVertexAttribArray(8);
	glVertexAttribDivisor(8, 1);

	glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(glm::mat3), (void*)(sizeof(GLfloat) * 6));
	glEnableVertexAttribArray(9);
	glVertexAttribDivisor(9, 1);

	glGenBuffers(1, &Index_VBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Index_VBO);

	glBufferData(GL_ELEMENT_ARRAY_BUFFER, TotalPolygonCount * 3 * sizeof(unsigned int), Indices, GL_STATIC_DRAW);

	glBindVertexArray(0);
}

And this is how I draw the geometry per mesh.

This function runs in a loop per mesh:


void HighSpeedMeshCache::DrawMe(GlMaintenance* CurrentOpenGLController)
{
	glBindVertexArray(Pointer_VAO);

	for (int i = 0; i < ModelMatrixIntances.size(); i++) {
		glm::mat4 ModelViewMatrix = CurrentOpenGLController->GetViewMatrix() * ModelMatrixIntances[i];
		glm::mat3 NormalMatrix = glm::transpose(glm::inverse(glm::mat3(ModelViewMatrix)));
		glm::mat4 ModelViewProjectionMatrix = CurrentOpenGLController->GetProjectionViewMatrix() * ModelMatrixIntances[i];
		glBindBuffer(GL_ARRAY_BUFFER, MVP_VBO);
		glBufferSubData(GL_ARRAY_BUFFER, (i * (sizeof(glm::mat4))), sizeof(glm::mat4), glm::value_ptr(ModelViewProjectionMatrix));
		glBindBuffer(GL_ARRAY_BUFFER, NormalMatrix_VBO);
		glBufferSubData(GL_ARRAY_BUFFER, (i * (sizeof(glm::mat3))), sizeof(glm::mat3), glm::value_ptr(NormalMatrix));
	}

	for (int i = 0; i < Materials.size(); i++) {
		glBufferData(GL_UNIFORM_BUFFER, sizeof(Materials[i].ColorProperties), Materials[i].ColorProperties, GL_DYNAMIC_DRAW);

		glDrawElementsInstanced(GL_TRIANGLES, (Materials[i].TriangleCount * 3)
		               , GL_UNSIGNED_INT, reinterpret_cast<const GLvoid *>(Materials[i].Offset * sizeof(unsigned int)), NumberOfChildItems + 1);
	}
}