Click here to Skip to main content
15,881,852 members
Articles / Multimedia / OpenGL

Flexible Particle System - Emitter and Generators

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
16 May 2014CPOL2 min read 10.4K   4   4
Description of my emitter and generator module for particle system
particle emitter

In our particle system, we already have a basic foundation: the container and the framework. Now we need some modules that can actually wake particles. In this post, I will describe the emitter module and generators.

The Series

Introduction

Basic design:

  • SRP principle: particle system contains a particle container, list of emitters, list of updaters. It does only basic stuff like initialization, cleanup and manages the update procedure.
  • Generators can generate one or several different attributes for a particle.
  • An emitter holds one or more generators.
  • Updating and killing particles are left to updaters.

The gist is located here: fenbf / BasicParticleGenerators

Emitter Loop

C++
void ParticleEmitter::emit(double dt, ParticleData *p)
{
    const size_t maxNewParticles = static_cast<size_t>(dt*m_emitRate);
    const size_t startId = p->m_countAlive;
    const size_t endId = std::min(startId + maxNewParticles, p->m_count-1);

    for (auto &gen : m_generators)            // << gen loop
        gen->generate(dt, p, startId, endId);

    for (size_t i = startId; i < endId; ++i)  // << wake loop
        p->wake(i);
}

The idea: an emitter should emit a number of particles each frame. The pace of course depends on emit rate. The emitter should generate all needed attributes, but each attribute can be set by a different generator. So we have One to Many relation.

In the gen loop, we call generators code. Each generator will set parameters for particles ranging from startId up to endId.

Then in the wake loop, we wake selected particles.

Generator

A generator should now actually be quite a simple module: just take a range of particles and set new values for some parameter. All the 'complex' code was handled already by the particle system and the emitter (generator's parent).

Here is an example of BoxPosGen:

C++
class BoxPosGen : public ParticleGenerator
{
public:
    glm::vec4 m_pos{ 0.0 };
    glm::vec4 m_maxStartPosOffset{ 0.0 };
public:
    BoxPosGen() { }

    virtual void generate(double dt, ParticleData *p, 
                          size_t startId, size_t endId) override;
};

void BoxPosGen::generate(double dt, ParticleData *p, size_t startId, size_t endId)
{
    glm::vec4 posMin{ m_pos.x - m_maxStartPosOffset.x, 
                      m_pos.y - m_maxStartPosOffset.y, 
                      m_pos.z - m_maxStartPosOffset.z, 
                      1.0 };
    glm::vec4 posMax{ m_pos.x + m_maxStartPosOffset.x, 
                      m_pos.y + m_maxStartPosOffset.y, 
                      m_pos.z + m_maxStartPosOffset.z, 
                      1.0 };

    for (size_t i = startId; i < endId; ++i)
    {
        p->m_pos[i] = glm::linearRand(posMin, posMax);
    }
}

Thanks to this idea, we can have a set of different generators and combine them into various emitters!

Other generators:

  • RoundPosGen - Generates particle's position around the circle (XY axis only)
  • BasicColorGen - Generates start and end color for a particle
  • BasicVelGen - Velocity only, you can set min and max on each axis
  • SphereVelGen - Velocity vector is generated from a sphere around point
  • BasicTimeGen - Time generation: between min and max

Example Emitter

Emitter that uses RoundPosGen, BasicColorGen, BasicVelGen and BasicTimeGen:

C++
auto particleEmitter = std::make_shared<ParticleEmitter>();
{
    particleEmitter->m_emitRate = (float)NUM_PARTICLES*0.45f;

    // pos:
    auto posGenerator = std::make_shared<generators::RoundPosGen>();
    posGenerator->m_center = glm::vec4{ 0.0, 0.0, 0.0, 0.0 };
    posGenerator->m_radX = 0.15f;
    posGenerator->m_radY = 0.15f;
    particleEmitter->addGenerator(posGenerator);

    auto colGenerator = std::make_shared<generators::BasicColorGen>();
    colGenerator->m_minStartCol = glm::vec4{ 0.7, 0.0, 0.7, 1.0 };
    colGenerator->m_maxStartCol = glm::vec4{ 1.0, 1.0, 1.0, 1.0 };
    colGenerator->m_minEndCol = glm::vec4{ 0.5, 0.0, 0.6, 0.0 };
    colGenerator->m_maxEndCol = glm::vec4{ 0.7, 0.5, 1.0, 0.0 };
    particleEmitter->addGenerator(colGenerator);

    auto velGenerator = std::make_shared<generators::BasicVelGen>();
    velGenerator->m_minStartVel = glm::vec4{ 0.0f, 0.0f, 0.15f, 0.0f };
    velGenerator->m_maxStartVel = glm::vec4{ 0.0f, 0.0f, 0.45f, 0.0f };
    particleEmitter->addGenerator(velGenerator);

    auto timeGenerator = std::make_shared<generators::BasicTimeGen>();
    timeGenerator->m_minTime = 1.0;
    timeGenerator->m_maxTime = 3.5;
    particleEmitter->addGenerator(timeGenerator);
}
m_system->addEmitter(particleEmitter);

Image 2

Circle particle emitter

Final Notes

I think that SRP principle helps a lot in this design. The code seems to be simple and straightforward to read. Each module does only one thing.

Another advantage of the system is that we can 'easily' translate this into a visual editor. You create a system, then add emitter, then fill it with different generators. The whole system can be set up from small blocks.

Are there any disadvantages? You need to understand the whole hierarchy of particle updaters/generators. For a simple system probably that is too much, but over time, such solution should help.

What's Next

Generators and emitters are useless when there is no Update mechanism! Next time, I will describe such system in my particle 'engine'.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Poland Poland
Software developer interested in creating great code and passionate about teaching.

Author of C++17 In Detail - a book that will teach you the latest features of C++17!

I have around 11 years of professional experience in C++/Windows/Visual Studio programming. Plus other technologies like: OpenGL, game development, performance optimization.

In 2018 I was awarded by Microsoft as MVP, Developer Technologies.

If you like my articles please subscribe to my weekly C++ blog or just visit www.bfilipek.com.

Comments and Discussions

 
GeneralMy vote of 5 Pin
imagiro1-Dec-14 22:56
imagiro1-Dec-14 22:56 
Very nice article (the whole series). I like especially that you cover the basics as well as presenting some advanced considerations.
GeneralRe: My vote of 5 Pin
Bartlomiej Filipek1-Dec-14 23:04
Bartlomiej Filipek1-Dec-14 23:04 
QuestionNice Pin
Manikandan1018-May-14 6:06
professionalManikandan1018-May-14 6:06 
AnswerRe: Nice Pin
Bartlomiej Filipek18-May-14 9:12
Bartlomiej Filipek18-May-14 9:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.