Like many others i started to learn programming through the Unity game engine. Game engines are large pieces of software that encapsulates a lot of the necessary features to make games. This includes low level utilities like windowing, graphics api abstraction and audio playback. Engines might also cover higher level stuff like navigation and level editing. They usually abstract a lof of functionality away so the end user don't have to worry about the implementation details. This is also the case for particle systems. Back in 2012 when unity released their now famous Shuriken particle system. Since then, it has been a go-to solution for most unity developers. It's powerful, fast and fairly easy to use.

About a year ago i was working on a 2 week game project for school. We where using Monogame XNA and happened to need a particle system. Since Unity is closed sourced and under strict licensing you cannot just copy Shuriken over. So i wanted a native C# solution.

First a bit of insight to the project architecture. It used a classical object oriented approach, without components. There is an abstract GameObject class that has virtual lifetime methods like Update() and Render(). Furthermore the GameObject has internal state like the active state and references to the global game and scene. The Scene that has a list of GameObjects and iterates the GameObjects and responsible for invoking the lifetime methods. The first implementation of the particle system was developed in this environment and went something like this:

public class Particle : GameObject 
{
    public float lifetime;
    public Vector3 position;
    public Vector3 velocity;

    public Texture2D texture;
    // A bunch of curves controlling behavior over time
    public Curve alphaOverLifetime;
    ...

    public override void Update()
    {
        position += velocity*Time.DeltaTime;
        ...
    }
    ...
}

In this approach each single particle is thought of as a single instance. Each derive from GameObject and is individually simulated and rendered. The game core already has a pooling system, since each particle is simply a GameObject the emitter just pulls a particle from the pool and spawns it. This is very easy to implement and only took a couple of hours. The particles where only one small part of a much larger game and no additional thought was put into it. This solution works fine.

Rainbow colored star particles emitting from cursor on black background

Because particles are so visually fun to play with, I decided to run some experiments after the game was done. I however ran into problems scaling the particle simulation to any larger size. I came to the, now obvious conclusion, that it has horrible performance. In my case I was experiencing lag with just 20.000 particles. Though you might think that 20.000 is a lot, and you're right is some sense. You might never have so many particles at once in your game. If you're making a simple game and have a large performance budget, there's no way this will impact the perceived quality. But when comparing to state of the art AAA games like Battlefield, it quickly becomes obvious that my modern desktop should be able to handle more sprites on the screen.

In this blog series I will describe the process of programming my own particle system. I will be taking a data oriented approach as opposed to the object oriented mindset described in this article. It describes how I was able to 100x+ the performance through data oriented design. I go into technical detail to try to reason about the choices made. To do this we have to learn a bit about computers.

Click here to read part 2 where I go into detail with CPU cache and memory locality.