Jump to content
  • Advertisement
Sign in to follow this  
emberintherain

Particle System Question

This topic is 2529 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey everyone,

I have a particle system but am wondering if there is a more efficient way to implement it. The current particle class I have looks like this.


//=============================================//
//// Copyright 2012 - Ember in the Rain, LLC //
// All Rights Reserved //
// Developer: Shawn M. Foster //
//=============================================//
#ifndef _PARTICLE_H_
#define _PARTICLE_H_
class Particle {
public:

/** Variables **/
//============================//
int id;
int lastTime;
int pType;

bool active;

Vector position;
Vector velocity;
Vector acceleration;
Vector color;
float size;
float mass;
float age;
float lifeSpan;

/** Methods **/
//============================//
Particle(LONG id);
~Particle();
void Update(int time);
void DrawParticle();
};
#endif


I am wondering if it would be more efficient to simplify the particle class to something like this.


#ifndef _N_PARTICLE_H_
#define _N_PARTICLE_H_
/** Particle Class **/
/**----------------------------------------------**/
class NParticle {

public:
NParticle();
float mass; //mass
float age; //age
Vector pos; //position vector
Vector vel; //velocity vector
Vector frc; //force accumulator
Vector col; //RGB color
float rad; //repulsive radius
};
/**----------------------------------------------**/
#endif



And then do any updating and drawing of the particles in the Particle System Class.. Does this sound like a better approach . Do you think that I do too much processing by updating the particle in the particle class and drawing it in that class?

Thanks,

Shawn

Share this post


Link to post
Share on other sites
Advertisement
Yes, it is better to batch things, and don't draw every particle on its own.
Make one particle system, and draw that in one draw call if possible.

You might also want to inline your constructor in case you will use that to quickly create individual particles.

Share this post


Link to post
Share on other sites
Thanks for the reply. So when you say inline my constructor you mean declaring and defining it all in the class declaration? smile.png

Like this...


#ifndef _N_PARTICLE_H_
#define _N_PARTICLE_H_
/** Particle Class **/
/**----------------------------------------------**/
class NParticle {

public:
NParticle(int indx) {id = indx;}
int id;
float mass; //mass
float age; //age
Vector pos; //position vector
Vector vel; //velocity vector
Vector frc; //force accumulator
Vector col; //RGB color
float rad; //repulsive radius
};
/**----------------------------------------------**/
#endif



Thanks,

Shawn

Share this post


Link to post
Share on other sites
He means to prepend the inline keyword to your ctor. This will remove the overhead of having to call to the ctor function every single time a particle is created. It will simply put the calling code wherever you create a particle(instead of having to "move" to the ctor, it is already there)

Share this post


Link to post
Share on other sites

He means to prepend the inline keyword to your ctor.


Actually defining the constructor in the class definition inlines implicitly. ;-) However, I don't think inlining the constructor will result in a big speed gain. But there are a few rules of thumbs you might consider in terms of optimizing your particle system:

Batch Drawcalls
Don't do a single drawcall for each particle. Rather batch many particles and render those with a single drawcall.

Use Texturatlases
Packing particle textures together in a atlas avoids texture switches

Try low resolution rendering
Render particle effects to low resolution targets for the sake of fillrate saving

Simulation on gpu
If your gpu is free you could do the simulation on gpu side to save memory bandwith (etc...)

Avoid Branches (etc...)
Don't do to many branches, virtual function calls etc.. Don't provide an update methode for a particle, do rather operate on particle batches


And then do any updating and drawing of the particles in the Particle System Class..


Yep, that sounds better! :)

Use Multithreading
If you'r doing the simulation on the CPU you could consider to swap the simulation to a free CPU core.

Use SIMD
Again, if you'r doing the simulation on the CPU you could use SIMD for speeding up the simulation.

Use cachefriendly datastructures
Using processor caches properly can result in big speed gains

Use specialized allocators (particle pools)
You could pool/preallocate particles to speed up allocation

Share this post


Link to post
Share on other sites
Thanks for the replies.


Don't do a single drawcall for each particle. Rather batch many particles and render those with a single drawcall.
[/quote]

So in this situation I fill my particle array once, then loop through my array of particles and call the draw function for each iteration?
Or, iterate through the particles inside of the draw function?

currently I draw the particles in the same loop as I update each particle's position. :) Which is a member of the ParticleSystem class. :)

I will look in to all of the other suggestions you made. smile.png Thanks again for your reply.

~Shawn

Share this post


Link to post
Share on other sites

So in this situation I fill my particle array once, then loop through my array of particles and call the draw function for each iteration?


No not exactly. You would loop through all your particles and write the vertices in one big vertexbuffer. Afterwards you just draw the geometrie residing in this vertexbuffer. Here is some pseudocode to illustrate the idea:


for each particle p
{
/// this'll generate the actual geometry for the particle (i.e. a quad)
vertices = generateVerticesForParticle(p);
/// draw a single particle
drawPrimitive(vertices)
}



for each particle p
{
/// this'll generate the actual geometry for the particle (i.e. a quad)
vertices = generateVerticesForParticle(p);
/// write the vertices to the end of the vertexbuffer
writeVerticesToVertexbuffer(vertexBuffer, vertices);
}
/// draw the particles in a single draw call
drawPrimitives(vertexBuffer);

Share this post


Link to post
Share on other sites
Switching from an AOS (array of structures) approach to a SOA (structure of arrays) approach for your particle data, then ensuring your arrays are 128 bit aligned allows for blindingly fast SIMD implementations.

A tightly packed float3 array thats 128-bit aligned at the start is faster to operate on than a typical aligned "128-bit" float3 structure, as long as you ensure the number of particles is a multiple of 4.

Memory is also kept contigious, which is always a bonus as cache read/writes are less likely to miss.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!