Adding a particle system to the Null Engine
- Anthon Reid
- Jun 25
- 3 min read
Updated: Jun 30

When I started working on this engine, I really wanted to do two things: write a 2D renderer, and make a particle system. Since then, I have expanded on those goals as I found more and more cool stuff to attempt. But this month, I finally found the time to start working on my particle system.
I had written particle systems before as part of school projects, but they were often very difficult to work with. One was completely C++ with no serialization. If you wanted an emitter, you had to write every part of it by hand. This led to a lot of duplicate code for menial modifications, like having a version with a different color. The other, although data-driven with an ImGui editor, had the opposite problem. It was supposed to be a modular and scalable approach, but in the end, it was poorly optimized and ended up being an unfortunate performance bottleneck.
With this system, I wanted to solve both of those issues. And so I set out to build a particle system using compute shaders that still could be modular and scalable.
To do that, I studied Unreal's Niagara system as well as Unity's particle system. I wanted to see what settings were shared between the two systems to determine what would be essential for a particle system to have. I also wanted to see which approach was easiest to use.
Like with most of my engine, I went with a setup akin to that of Unity's. The particle system would be a component that is attachable to an entity, and would be edited in the game scene rather than a separate window. This would help keep things to scale most easily. I, however, liked a specific aspect of Unreal's approach over Unity's. In Unity, to make a fire, you would have to do something like have a GameObject hold the fire emitter, and have a child of it hold the smoke emitter, and another have the sparks. In Unreal, however, a system could easily be comprised of multiple emitters.
I now had a basic idea of what I was going to do. I would make a particle system with compute shaders. It would be an entity component where each system could be comprised of multiple emitters.
Now I just needed to figure out how :]

After a bit of work, I got particles to spawn and die. Everything was happening in one shader and I could have a lot of particles on screen while barely loosing any frames.
The next challenge would be to add some control over the emission of particles. That would be key to create different behaviors.

To implement emit rates, I had to separate my compute shader into three. One to initialize my particles when generating the SSBO, one to emit, and one to update.
I also added some particle modifiers. These would be functions that modify particle states, like fade, size, or color modifiers. This was adapted from my last attempt at a particle system, however this time it would all occur in GLSL.
This caused my shader to get very crowded, which led me to do something interesting. I learned this from my time adding Lua scripts to the engine: if, for some reason, you establish a pattern in how you organize Lua or GLSL files, those tend to be loaded in as strings before creating the shader program or the Lua script. Which means, one could potentially modify those strings beforehand. I decided to use that to add #includes to my shader files in order to keep things organized.
I imagine there’s a better way to do this, but I was curious how well that would work. And it turns out that setup worked well enough for what I was trying to do.

I then wrote a few modifiers inspired by ones I saw in Unreal’s Niagara and Unity’s particle systems. By passing in emitter flags, I can disable certain updates. This lets me customize which modifiers an emitter is using, making the system very modular.

In the end, I'm happy with my results so far. Above is an entity with a particle system holding three emitters, each with their own unique behavior. I also added support for curves to give users better control over how modifiers interpolate between values, as well as the ability for users to draw their own curves.
Next steps would be to add support for textures and animations. At that point, I think I’d be done with this mini project. At least for now.
Commenti