Archived

This topic is now archived and is closed to further replies.

ElvenAngel

Particles in DrawArrays

Recommended Posts

ElvenAngel    122
Im working on a particle system to work in a program for my class. I was told calling glBegin and glEnd to render the particles might not be the most effective way to handle all the particles inside of a game. So i''ve been trying to figure out a method of drawing them as Triangle Strips in DrawArrays. I was wondering if anyone had any advice on how to handle rendering those properly.

Share this post


Link to post
Share on other sites
JTippetts    12950
It''s pretty simple. Just set up an array of vertex structs, with four elements for each particle. I like to use a static buffer with enough vertices for, say, 1000 particles. Then I can iterate through all of the particles belonging to a particular emitter or effect, transform their location into a particle billboard, and insert the calculated vertices into the array.

My typical particle vertex struct is just a structure with (x,y,z,r,g,b,u,v). The texture coordinates (u,v) can be pre-set when the array is allocated, since they never change. A particle texture is always fully mapped across the quad. (r,g,b) is determined of course by the particle''s color.

struct VertexStruct
{
float x,y,z;
float r,g,b;
float u,v;
};

I pre-generate two vector values--quad_lower_left and quad_lower_right--representing the lower left and lower right corners of a PARTICLE_SIZE sized quad billboard. These vectors are reverse transformed using the current modelview matrix orientation. Then, to calculate the vertices of a given particle billboard I take the particle''s world location. For the lower left corner I use position+quad_lower_left. For the lower right corner I use position+quad_lower_right. These values can be subtracted from the location to calculate the opposite corners. That is, the upper left corner of the billboard is calculated as position-quad_lower_right and the upper right corner is position-quad_lower_left. This way, I only have to the perform the reverse transform on two vectors, and can reuse this reverse transform to form all particles.

double mat[16];
Vector3 quad_lower_left, quad_lower_right;

glGetDoublev( GL_MODELVIEW_MATRIX, mat );

// Reverse transform
quad_lower_left.x() = (-ParticleSize/2) * (mat[0] + mat[1]);
quad_lower_left.y() = (-ParticleSize/2) * (mat[4] + mat[5]);
quad_lower_left.z() = (-ParticleSize/2) * (mat[8] + mat[9]);
quad_lower_right.x() = (ParticleSize/2) * (mat[0] - mat[1]);
quad_lower_right.y() = (ParticleSize/2) * (mat[4] - mat[5]);
quad_lower_right.z() = (ParticleSize/2) * (mat[8] - mat[9]);



This was a trick I picked up from the particles demo included with GLFW (courtesy of Marcus Geelnard), for quickly performing the reverse transformation once then using the calculated values to build all the particle quads. The above operation takes a point and transforms it by the transpose of the current orientation matrix.

I fill the static vertex array with enough vertex data for 1000 particles. If the effect or emitter owns more than that, I batch them 1000 at a time or until I finish the list. I set the array pointers as follows:

glVertexPointer(3, GL_FLOAT, sizeof(VertexStruct), &(VertBuffer[0].x));
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexStruct), &(VertBuffer[0].s));
glColorPointer(4, GL_FLOAT, sizeof(VertexStruct), &(VertBuffer[0].r));

where VertBuffer is my array of 4000 vertices. Then a simple

glDrawArrays( GL_QUADS, 0, 4 * NumActiveParticles );

where NumActiveParticles is how many particle quads I filled the array with, will draw all quads in the array. Once the particles are drawn, if I have more pending I go back and resume where I left off, batching in a new chunk.


Golem
Blender--The Gimp--Python--Lua--SDL
Nethack--Crawl--ADOM--Angband--Dungeondweller

Share this post


Link to post
Share on other sites
Trienco    2555
it depends on what you do and need. you can have a particle system with glbegin, point sprites and 100 000 particles running at 110fps on a radeon 9800. try the same when you use a vertex array/buffer and just creating/updating the quads will kill more performance than using immediate mode. even with a simple vertex program and and immediate mode you can get 62fps. if they fill a bigger part of your screen or arent exactly small youll run into trouble with fillrate anyway and more complicated particle updates will be a bigger problem too.

seeing how arrays and buffer just add a lot of overhead to solve a problem that often isnt even a problem id stick with immediate mode until it turns out to be too slow.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Trienco is right on here. For this kind of static data (only the position/orientation is changing) vertex arrays would be mass-overkill. For this, look in to Display Lists (Faster then vertex arrays in most cases, just less flexible).

Share this post


Link to post
Share on other sites