I need some some advice on my particle system.
Right now I have a particle emitter which holds a list of particles and each particle has a VBO for its vertices and uvs.
Which is bad I know this, it with drawing only 150 particles, I go from just over 100 draw calls, to 3000 draw calls using gDEBugger.
Each particle keeps track of its own local and world matrix.
I know the general idea is that I need to create a single VBO for each piece of data in the particle emitter, but then how to I pass the mvp for each particle, my particles are not always going to start at the same size.
Do I do something like this:
int i = 0;
// Pass in new mvp here and any other data that may have changed like colour
glDrawArrays(GL_TRIANGLE_STRIP, i, 4);
i+= 4;
My code is below:
// Particle Initialization
uvs.push_back(Vector2(1,1));
vertices.push_back(Vector3(
0+(particleInfo.sizeX/2),
0+(particleInfo.sizeY/2),
0));
uvs.push_back(Vector2(0,1));
vertices.push_back(Vector3(
0-(particleInfo.sizeX/2),
0+(particleInfo.sizeY/2),
0));
uvs.push_back(Vector2(1,0));
vertices.push_back(Vector3(
0+(particleInfo.sizeX/2),
0-(particleInfo.sizeY/2),
0));
uvs.push_back(Vector2(0,0));
vertices.push_back(Vector3(
0-(particleInfo.sizeX/2),
0-(particleInfo.sizeY/2),
0));
// This is just a bind function.
// Binding the Data
void Particle::bind()
{
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vector3), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(Vector2), &uvs[0], GL_STATIC_DRAW);
}
Here is where I update the particle based on the properties.
// Updating the Matrix
/* removed for space */
localMatrix = Matrix4::toMatrix4(rotation,position,scale);
Drawing the Particles
void Particle::draw()
{
if(alive)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
Camera *cam = this->particleInfo.scene->getActivePerspectiveCamera();
worldMatrix = cam->getObjectToWorld().inverse() * localMatrix;
Matrix4 mvp = cam->getProjectionMatrix() * worldMatrix;
glUniformMatrix4fv((*particleInfo.shader)["mvp"], 1, GL_FALSE, mvp.transpose().getArray());
glUniform4f((*particleInfo.shader)["colour"],
particleInfo.colour.R,
particleInfo.colour.G,
particleInfo.colour.B,
particleInfo.colour.A);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
(*particleInfo.shader)["modelVertex"], // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
(*particleInfo.shader)["uv"], // attribute
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size());
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);
}
}
Particle Emitter Draw
void ParticleEmitter::draw()
{
Component::draw();
if(running)
{
iter = particles.begin();
this->getShader()->begin();
textureDiffuse->bindTexture((*this->getShader())["diffuseTextureSampler"],0);
while (iter != particles.end())
{
(*iter)->draw();
++iter;
}
glBindTexture(GL_TEXTURE_2D, 0);
this->getShader()->end();
}
}