• Create Account

#Actualharshman_chris

Posted 18 January 2013 - 08:20 PM

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;

particleInfo.colour.R,
particleInfo.colour.G,
particleInfo.colour.B,
particleInfo.colour.A);

glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
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(
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();

while (iter != particles.end())
{
(*iter)->draw();
++iter;
}

glBindTexture(GL_TEXTURE_2D, 0);

}
}

#1harshman_chris

Posted 18 January 2013 - 08:15 PM

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, or do I loop through the particles and just pass the mvp for each particle and only store 1 vertex and 1 uv coords since they are always the same and any changes happen in the mvp.

// 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;

particleInfo.colour.R,
particleInfo.colour.G,
particleInfo.colour.B,
particleInfo.colour.A);

glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
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(
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();

while (iter != particles.end())
{
(*iter)->draw();
++iter;
}

glBindTexture(GL_TEXTURE_2D, 0);

}