Search Unity

ParticleSystem.Emit stops working after a while

Discussion in 'General Graphics' started by Manufacture43, Oct 10, 2018.

  1. Manufacture43


    Apr 21, 2017
    I'm here with what looks like a very weird bug.

    In the process of optimizing our game, I transformed all the particle effect instances we had into manual emissions in one single particle system. This yields massive performance improvements as particles (especially the mesh ones) are now batched.

    There's only 3 drawbacks to this:
    - I can't rotate particle effects anymore (I tried manipulating velocity but that broke many effects. I still have to try manipulating shape.rotation before every emit call, not sure what kind of effect that will have on the whole system...)
    - particles can't follow objects anymore since they're not child of it (I could add velocity in the EmitParams but then I loose the velocity set in the inspector by the various modules... it would be nice to have a applyShapeToVelocity here, or an extraVelocity or something)
    - and, the bug, particles stop being emitted after a while !

    It's not all particles, it's just some, and it's always when I reach a boss. So I think it has to do with something I do but I'm not sure what... I tried having a particle system attached to a camera moving forward forever to see if it would stop emitting, but that didn't happen... I was thinking of maybe some kind of bound optimization in the renderer.

    Sometimes, particles don't stop emitting but their placement is completely broken. I verified in the debugger and, for two nearly identical system used by two different weapons, both get similar positions in EmitParams and one works the other doesn't. The only difference I can think of is that I used one weapon more than the other while playing...

    Something very surprising : if I hit the stop button on the particle effect window in the scene view, particles start emitting again! I tried calling Stop() in the update whenever there was 0 particles in the system, just to see, but it doesn't fix anything...

    Here's my code to emit particle system hierarchies to random places, as if there were many systems but it's instead just one really :
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    5. [RequireComponent(typeof(ParticleSystem))]
    6. public class BatchedEffect : MonoBehaviour
    7. {
    8.     public bool PlayExplosionSound;
    10.     struct Instance
    11.     {
    12.         public ParticleSystem Particles;
    13.         public ParticleSystem.EmitParams Params;
    14.         public float Scale;
    15.         public int Count;
    16.         public int Repeat;
    17.         public float Delay;
    19.         public Transform Follow;
    20.         public Vector3 Position;
    22.         public float Timer;
    23.     };
    25.     public ParticleSystem ParticleSystem { get; private set; }
    27.     List<ParticleSystem> emitters;
    28.     List<Instance> instances = new List<Instance>(512);
    30.     void Awake()
    31.     {
    32.         ParticleSystem = GetComponent<ParticleSystem>();
    33.         ParticleSystem[] all = transform.GetComponentsInChildren<ParticleSystem>();
    34.         emitters = new List<ParticleSystem>(all.Length);
    35.         foreach (ParticleSystem p in all)
    36.             if (p.main.maxParticles > 0 && p.GetComponent<ParticleSystemRenderer>().enabled && !"_sub"))
    37.                 emitters.Add(p);
    38.     }
    40.     void Update()
    41.     {
    42.         for (int i = 0; i < instances.Count; i++)
    43.         {
    44.             Instance instance = instances[i];
    46.             instance.Timer -= Time.deltaTime;
    47.             if (instance.Timer <= 0f)
    48.             {
    49.                 ParticleSystem.EmitParams p = instance.Params;
    50.                 p.startSize = instance.Particles.main.startSize.Evaluate(0f) * instance.Scale;
    51.                 if (instance.Follow != null)
    52.                 {
    53.                     Vector3 worldPosition = instance.Follow.TransformPoint(instance.Position);
    54.                     p.position = instance.Particles.transform.InverseTransformPoint(worldPosition);
    55.                 }
    56.                 instance.Particles.Emit(p, instance.Count);
    58.                 instance.Timer += instance.Delay;
    59.                 instance.Repeat--;
    60.             }
    62.             if (instance.Repeat > 0)
    63.             {
    64.                 instances[i] = instance;
    65.             }
    66.             else
    67.             {
    68.                 instances.RemoveSwap(i);
    69.                 i--;
    70.             }
    71.         }
    72.     }
    74.     public void Play(Transform follow, Vector3 localPosition)
    75.     {
    76.         Play(follow.TransformPoint(localPosition));
    78.         for (int i = 0; i < emitters.Count; i++)
    79.         {
    80.             int idx = emitters.Count - 1 - i;
    81.             Instance instance = instances[idx];
    82.             instance.Follow = follow;
    83.             instance.Position = localPosition;
    84.             instances[idx] = instance;
    85.         }
    86.     }
    88.     public void Play(Vector3 worldPosition)
    89.     {
    90.         if (PlayExplosionSound)
    91.             Factory.Instance.PlayExplosionSound(worldPosition);
    93.         Vector3 camera = Playspace.Instance.CameraFollower.CameraWorldPosition;
    94.         Vector3 projected;
    95.         float scale;
    96.         if (Playspace.Instance.WorldProject(worldPosition, out projected))
    97.             scale = Mathf.Sqrt((camera - worldPosition).sqrMagnitude / (camera - projected).sqrMagnitude);
    98.         else
    99.             scale = 1f;
    101.         foreach (ParticleSystem emitter in emitters)
    102.         {
    103.             float delay, initDelay;
    104.             int repeat, count;
    105.             if (emitter.emission.burstCount > 0)
    106.             {
    107.                 ParticleSystem.Burst burst = emitter.emission.GetBurst(0);
    108.                 delay = burst.repeatInterval;
    109.                 repeat = burst.cycleCount;
    110.                 count = Mathf.RoundToInt(burst.count.constant);
    111.                 initDelay = burst.time;
    112.             }
    113.             else
    114.             {
    115.                 delay = 1f / emitter.emission.rateOverTime.constant;
    116.                 repeat = Mathf.RoundToInt(emitter.main.duration / delay);
    117.                 count = 1;
    118.                 initDelay = 0f;
    119.             }
    121.             ParticleSystem.EmitParams parameters = new ParticleSystem.EmitParams();
    122.             parameters.position = emitter.transform.InverseTransformPoint(worldPosition);
    123.             parameters.applyShapeToPosition = true;
    125.             instances.Add(new Instance()
    126.             {
    127.                 Particles = emitter,
    128.                 Params = parameters,
    129.                 Scale = scale,
    130.                 Delay = delay,
    131.                 Count = count,
    132.                 Repeat = repeat,
    133.                 Timer = initDelay,
    134.             });
    135.         }
    136.     }
    137. }
    Any idea of what I could be missing?
    Last edited: Oct 10, 2018
  2. richardkettlewell


    Unity Technologies

    Sep 9, 2015
    I didn’t look closely yet, but a simple suggestion: maybe you hit the max particles limit in the main module settings?

    Also: changing shape.rotation between each Emit call sounds fine to me :)
  3. Manufacture43


    Apr 21, 2017
    Max particles is for the active number of particles right? Not the particles ever emitted? Because I have no particles running at that point.

    I'm making a video of the issue :)
  4. Manufacture43


    Apr 21, 2017
    A video of the issue :

    In the beginning, you can see the green impacts properly being played, the red impacts being missing, the blue impacts being played far from the enemy, at the bottom of the screen.
    Then I stop/play on the red impact particle system and they start playing properly.
    I then do the same thing on the blue impacts

    The particle system :
  5. Manufacture43


    Apr 21, 2017
    Oh, wow! So, okay, I noticed when doing the video that it was hitting play that would make things to start working again, and not stop. So I went full stupid and called Play() after 20s without any emission of a particle system. It fixes the issue!

    But it also plays the particle system in some place I don't want so that's not really a hacky fix... I could maybe place the effects off-screen by default but that sucks a bit, right ? :(

    Edit: well, and I would have to do that every 100ms to avoid any noticeable lag...
  6. richardkettlewell


    Unity Technologies

    Sep 9, 2015
    Maybe because loop is disabled and the duration is short, it’s getting confused after a long play time? (It doesn’t expect to be playing for many seconds)

    Failing that, can you report a bug?
  7. Manufacture43


    Apr 21, 2017
    I wish but I don't have a repro scene yet and I don't know what to report really... It's really confusing

    edit: setting looping an all emitters doesn't change anything
    and it's not always the same particle systems who start being messed up. But as far as I can tell, it's always when I get to a boss. It's really strange...
    Last edited: Oct 11, 2018
  8. unity_0fmczLs2vNuMTQ


    Jun 6, 2018
    I have a very similar issue with my particle system. I fixed displacement problem by changing localPosition of the system after Play() for a little bit (transform.localPosition += * 0.001f). This updates my system's position to the right place. But I still have the issue when it just stops emitting particles after several calls of Play() function. I tried to call Emit() and even made it PlayOnAwake and tried to activate gameObject but got the same behavior. It plays OK for a dozen of times and after that just stops working. Logs show that isStopped property of my system is TRUE even right after (and on the next frames) I call Play() method. I'm starting to lose my mind, guys. I'm using Unity 2018.1.7f1.
    Last edited: Oct 12, 2018
  9. unity_0fmczLs2vNuMTQ


    Jun 6, 2018
    OK, looks like I managed to fix it. I think my problem was that I used my particle system inside of a coroutine. I got rid of coroutines and it works like a charm. At least I couldn't reproduce it in a while.
  10. Quakeulf


    Mar 26, 2013
    I have an issue in Unity 2018.3.5f1 with a simple looping particle system that emits over distance. When I hit the Play-button it stops working even though I am logging isPlaying and isEmitting where I see them set to true.

    It displays two different behaviours:

    - One behaviour when I am editing it. (Working as intended)
    - One behaviour after I hit "Play" to inspect it in the context I want to use it. (Broken)

    Why is this inconsistent?

    There is no code involved.
  11. richardkettlewell


    Unity Technologies

    Sep 9, 2015
    Perhaps you are hitting this bug, which is fixed in Unity 2018.3.6f1:

    If it's still broken in 2018.3.6f1, please report a bug, thanks.
  12. Quakeulf


    Mar 26, 2013
    How and why do these things happen?