Search Unity

Particle Systems, why are they still so hard to use?

Discussion in 'General Discussion' started by Antony-Blackett, May 24, 2019.

  1. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,267
    Is it just me or are particle systems incredibly hard to use from a programming perspective?

    My bugbear with the particle systems is how inefficient they are. If you spawn individual particle system objects for say bullet collisions you end up with about 50 active at any one time when all you really need is a single system that's spawning all the particles. This can be done with the System.Emit() function but it's a complete pain to use.

    For example:
    Why can I not just call ParticleSystem.Emit() and have it look exactly like it does when I instance a particle system object from scratch?

    Instead I need to do this:

    Code (csharp):
    1.  
    2.   ParticleSystem.Burst burst = system.emission.GetBurst( 0 ); // this will fail if there's no burst defined.
    3. // code below only handles bursts that are defined as a constant or a random value between two constants.
    4.   int count = (int)burst.count.constant;
    5.   if( burst.count.mode == ParticleSystemCurveMode.TwoConstants )
    6.   {
    7.       count = Random.Range( (int)burst.count.constantMin, (int)burst.count.constantMax );
    8.   }
    9.   system.Emit( count );
    10.  
    wouldn't this be nicer?

    Code (csharp):
    1.  
    2. system.Emit();
    3.  
    On top of that there are a bunch of simulation space, rotation and culling issues that then present themselves if you use a single particle system and the Emit function as above.

    For Example:
    I've found that if you use either local or world simulation space, you need to move the particle system to the point you're spawning the particles and then move it back to the position it was in before spawning them otherwise you get a bunch of glitchy sometimes invisible particles as your emitter moves around.

    So your code to just emit particles becomes this:

    Code (csharp):
    1.  
    2.             Vector3 originalPosition = system.transform.localPosition;
    3.             Quaternion originalRotation = system.transform.localRotation;
    4.  
    5.             system.transform.position = definition.offsetPosition + position + originalPosition;
    6.             system.transform.rotation = Quaternion.Euler( definition.offsetRotation ) * rotation * originalRotation;
    7.             ParticleSystem.Burst burst = system.emission.GetBurst( 0 );
    8.             int count = (int)burst.count.constant;
    9.             if( burst.count.mode == ParticleSystemCurveMode.TwoConstants )
    10.             {
    11.                 count = Random.Range( (int)burst.count.constantMin, (int)burst.count.constantMax );
    12.             }
    13.             system.Emit( count );
    14.  
    15.             system.transform.localPosition = originalPosition;
    16.             system.transform.localRotation = originalRotation;
    17.  
    wouldn't this be better?

    Code (csharp):
    1.  
    2. system.Emit( transform.position, transform.rotation );
    3.  

    This is only a very simple use case when optimising particles. When you need to override other behaviours like particle speed and other such things depending on gameplay or if you have multiple particle systems combined in a single effect things get even more complex!

    Rant over.
     
    Flurgle likes this.
  2. iamthwee

    iamthwee

    Joined:
    Nov 27, 2015
    Posts:
    1,491
    Admittedly it is not as bad as java.

    A simple hello world program:

    Code (CSharp):
    1. interface Printer {
    2.      void print(Message message);
    3. }
    4. class Message {
    5.      private String message;
    6.      public Message(String message) {
    7.          this.message = message;
    8.      }
    9.      public void print(Printer printer) {
    10.          printer.print(this);
    11.      }
    12.      public String toString() {
    13.          return message;
    14.      }
    15. }
    16. abstract class AbstractPrinterFactory {
    17.      public static AbstractPrinterFactory getFactory() {
    18.          return new SystemOutPrinterFactory();
    19.      }
    20.      public abstract Printer getPrinter();
    21. }
    22. class SystemOutPrinterFactory extends AbstractPrinterFactory {
    23.      public Printer getPrinter() {
    24.          return new SystemOutPrinter();
    25.      }
    26. }
    27. class SystemOutPrinter implements Printer {
    28.      public void print(Message message) {
    29.          System.out.println(message);
    30.      }
    31. }
    32. class HelloWorld {
    33.      public static void main(String[] args) {
    34.          Message message = new Message("Hello, World!");
    35.          AbstractPrinterFactory factory = SystemOutPrinterFactory.getFactory();
    36.          Printer printer = factory.getPrinter();
    37.          message.print(printer);
    38.      }
    39. }
     
  3. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    1,658
    Because ParticleSystem is a black box located on the native side.
    Some hacks are required to pass data back and forth between native and managed sides. This is done for performance reasons.

    Some things may not work as intended, or be plain broken in some cases.
    (Which hopefully would be fixed as time goes).

    Also, do not do system.transform multiple times over and over again. That does external call which eats your performance. At least store the reference on the stack.
    Code (CSharp):
    1. Transform trm = system.transform;
    2. // Do something with trm instead
    3. trm.position = ...
    4. ...

    You're overengineering it. In the end its just System.out.println. Just dump the rest.
    Oh right, you can't. Bus in the ass development.
     
    Antypodish likes this.
  4. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,267
    Yes I know all this. my point is I have to do these hacks in C# to get performance from these poorly performing meant to be fast native particle systems that take a draw and an update call each per instance of the exact same system... This just seems like a system that was not very well thought out built for artists to compose ok looking systems but then be almost unusable from a game code standpoint. It has remained as is for a few versions of Unity now. I don't expect any of these issues will be fixed and I suspect I'll be told to move to VFX particles.
     
    Flurgle likes this.
  5. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    4,297
    The separation of concerns are fubar in your code. The message prints it self. haha. ridiculous
     
    xVergilx and iamthwee like this.
  6. DreReid

    DreReid

    Joined:
    Dec 13, 2015
    Posts:
    333
    Ive tried working with it before but man was it confusing, so sometimes i would watch a tutorial and half assly implement it in a project.