ParticleSystem refactor
by Lukas Joergensen · 08/04/2014 (3:28 pm) · 27 comments
Hey guys!
As some of you know, I've been working on refactoring the ParticleSystem.
Mostly I've been aiming at updating the ParticleSystem to a more modern design, generally I dislike the Polymorphic and simple design that T3D uses, in which inheritance seems to be the solution to everything!
One of my teacher at CS taught me to major lessons: Polymorphism is usually a bad solution in the long-term and you should always design your code such that you add by addition and not by modification!
Which is exactly what I've done with the ParticleSystem.
Originally, all the functionality was packed down into two classes: ParticleData and ParticleEmitters.
Which means that ParticleEmitters had the responsibility of: calculating particles initial position, manage the particle memory pool, render the particles, simulate the particles, update the particles and the list goes on and on.
Now I've split it up into more smaller classes:

It's pretty simple actually, you have the ParticleSystem class, which delegates the work into the other classes. Besides delegating the work out, it's also responsible for being the glue between the components of the ParticleSystem and the rest of the engine, so it handles all external requests (like emitParticles) and sends the appropriate commands to the components.
ParticleRenderers renders the particle, whatever this entails is up to the renderer. It could be Billboards, Pointlights or whatever. By changing how particles are rendered, you can easily accomplish stuff like glowing particles, ribbonParticles etc.
Or even utilize other objects as if they were particles! This is one of the newer IPS features which you can preview in the video below:
The ParticleEmitter changes the pattern which particles are emitted in, this is the good old roots of IPS. This is where you'll create your GraphEmitter, GroundEmitter, MaskEmitter or whatever you need.
Last but not least you have the IParticleBehaviours, which is small components you plug into the system to affect how particle behave (this is actually ripped right out of IPS).
This way you can have attracted particles, sticky particles or particles that can collide with objects without having to touch any of the existing code!
Here is a short video of the ParticleSystem refactor in action:
The code is cleaner and easier to maintain.
I'll be extending the ParticleSystem with some of the features found in IPS, so this isn't entirely a "behind the scenes" change.
This will break the ParticleEditor, since even if we made a patch-solution it is simply not geared to handle this change. (Although the datablock editor still works fine as you can see in the video above, I don't know if the ParticleEditor is necessary in the first place).
More work needs to be done, I'm still working on it but to really polish this refactor, we will at some point need other people to look at the refactor and find bugs and tell me what features are missing.
Edit: btw some of the changes that I forgot to mention are:
Instead of specifying the time between particles, you now specify the particles per second. I liked this approach more, since the time between particles doesn't increase the amount of emitted particles linearly.
I also trimmed down the Particle struct a bit, which should save some memory, completely removed the "ParticleData" class and I added a "ParticlePool" class to manage the particle pool, instead of having that code directly in the ParticleSystem class.
As some of you know, I've been working on refactoring the ParticleSystem.
Mostly I've been aiming at updating the ParticleSystem to a more modern design, generally I dislike the Polymorphic and simple design that T3D uses, in which inheritance seems to be the solution to everything!
One of my teacher at CS taught me to major lessons: Polymorphism is usually a bad solution in the long-term and you should always design your code such that you add by addition and not by modification!
Which is exactly what I've done with the ParticleSystem.
Originally, all the functionality was packed down into two classes: ParticleData and ParticleEmitters.
Which means that ParticleEmitters had the responsibility of: calculating particles initial position, manage the particle memory pool, render the particles, simulate the particles, update the particles and the list goes on and on.
Now I've split it up into more smaller classes:

It's pretty simple actually, you have the ParticleSystem class, which delegates the work into the other classes. Besides delegating the work out, it's also responsible for being the glue between the components of the ParticleSystem and the rest of the engine, so it handles all external requests (like emitParticles) and sends the appropriate commands to the components.
ParticleRenderers renders the particle, whatever this entails is up to the renderer. It could be Billboards, Pointlights or whatever. By changing how particles are rendered, you can easily accomplish stuff like glowing particles, ribbonParticles etc.
Or even utilize other objects as if they were particles! This is one of the newer IPS features which you can preview in the video below:
The ParticleEmitter changes the pattern which particles are emitted in, this is the good old roots of IPS. This is where you'll create your GraphEmitter, GroundEmitter, MaskEmitter or whatever you need.
Last but not least you have the IParticleBehaviours, which is small components you plug into the system to affect how particle behave (this is actually ripped right out of IPS).
This way you can have attracted particles, sticky particles or particles that can collide with objects without having to touch any of the existing code!
Here is a short video of the ParticleSystem refactor in action:
The discussion
So before we go ahead and mindlessly vote this into T3D here is a pro/con list of:Pros
Adding features is as easy as creating a new class, and include it in your project.. No need to modify any of the existing code. The class is lightweight and easy to understand. SphereEmitter example.The code is cleaner and easier to maintain.
I'll be extending the ParticleSystem with some of the features found in IPS, so this isn't entirely a "behind the scenes" change.
Cons
This will break ALL of your existing datablocks. All of the ParticleEmitterData and ParticleData scripts will be obsolete.This will break the ParticleEditor, since even if we made a patch-solution it is simply not geared to handle this change. (Although the datablock editor still works fine as you can see in the video above, I don't know if the ParticleEditor is necessary in the first place).
More work needs to be done, I'm still working on it but to really polish this refactor, we will at some point need other people to look at the refactor and find bugs and tell me what features are missing.
Finally
The branch can be found here but the interesting changes can be found here.Edit: btw some of the changes that I forgot to mention are:
Instead of specifying the time between particles, you now specify the particles per second. I liked this approach more, since the time between particles doesn't increase the amount of emitted particles linearly.
I also trimmed down the Particle struct a bit, which should save some memory, completely removed the "ParticleData" class and I added a "ParticlePool" class to manage the particle pool, instead of having that code directly in the ParticleSystem class.
About the author
IPS Bundle available at: https://www.winterleafentertainment.com/Products/IPS.aspx
#2
I think it'd be possible to have a component that just calls "emitParticles" on a ParticleSystem object, so the refactor branch could be used with ECS without having the same code in 2 places.
08/04/2014 (4:53 pm)
Oh, I have something different going on for the ECS. Branch here, they are building on the same concepts but the ECS one is in more of a "proof-of-concept" stage than the refactor branch, and uses some other tricks.I think it'd be possible to have a component that just calls "emitParticles" on a ParticleSystem object, so the refactor branch could be used with ECS without having the same code in 2 places.
#3
08/04/2014 (11:19 pm)
Nice work Lukas, thanks for sharing.
#4
08/05/2014 (5:12 am)
Wow nice work man!
#5
Sounds about normal, I'm getting used to it ;)
08/05/2014 (6:33 am)
Quote:
This will break ALL of your existing datablocks.
Sounds about normal, I'm getting used to it ;)
#6
Surprised no one has commented on the loss of ParticleEditor support. I hope that is a sign that this might be making it into stock T3D :P
Latest commit adds support for glowing particles!

08/05/2014 (10:56 am)
Thanks guys.Surprised no one has commented on the loss of ParticleEditor support. I hope that is a sign that this might be making it into stock T3D :P
Latest commit adds support for glowing particles!

#7
08/05/2014 (1:27 pm)
@Lukas The particle editor was cumbersome, having to switch between datablock editor and particle emitter, so no huge loss there.
#8
08/05/2014 (2:28 pm)
Particle editor? What particle editor? :P
#9
08/05/2014 (3:31 pm)
I've always hand wrote particles, never used an editor for 'em.
#10
Also, by Dynamic water, I mean something like this, right?
08/06/2014 (9:49 pm)
I just thought of something: collision particles could be used for water simulations(sorta), and combined with 3D particles, they could be used quite a bit in destructible bits, like if you blow up a concrete barrier, you don't need to make a partially destroyed version with gibs.Also, by Dynamic water, I mean something like this, right?
#12
08/07/2014 (10:30 am)
@Lukas, sure, is there a binary I can download somewhere?
#14
08/07/2014 (7:27 pm)
@Lukas, thanks, but since I'm still using the stock CS files... how is particle formed?
#16
08/08/2014 (10:22 am)
I keep getting an error "Particlepool: negative part count"
#17
08/08/2014 (11:41 am)
@Chris, that's odd, could you show me exactly what you did? Try commenting out all particle emitter datablocks except the ones I sent you
#18
"new ParticleSystemNode()
{
System = DefaultParticleSystem;
dataBlock = DefaultNode;
};"
code in the level .mis file after I had tried typing CreateSystem() into the console.
08/08/2014 (3:47 pm)
I put the"new ParticleSystemNode()
{
System = DefaultParticleSystem;
dataBlock = DefaultNode;
};"
code in the level .mis file after I had tried typing CreateSystem() into the console.
#19
08/09/2014 (1:35 am)
I can't really figure out what's wrong, can't recreate the issue.. Try making sure that the DefaultEmitter isn't defined elsewhere and try setting partlifetime to 1000 on the particle system datablock.
#20
08/10/2014 (12:11 pm)
That got it to not crash, however the particle system does not show up in the missiongroup. 
Torque Owner Daniel Buckmaster
T3D Steering Committee