PDA

View Full Version : Request for Advice - Optimizing My Drawing Calls...



tmason
06-12-2014, 12:47 AM
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(ModelViewMat rix)));
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);
}
}