Search Unity

ParticleSystem: Ring buffer support

Discussion in 'General Graphics' started by Peter77, Mar 3, 2018.

  1. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    @richardkettlewell
    I use the ParticleSystem not just for traditional particle effects, but also as a "generic fast renderer". For example, I use the ParticleSystem to emit footprints and bullet impacts. Using a particle system to render hundreds of these objects is a lot faster than using a MeshRenderer for each single "decal".

    I use the "Max Particles" property to limit the particle system to e.g. 100. Now I walk around with the player and emit lots of footprint particles in the world.

    If the particle system contains 100 particles, no further particles will be emitted, unless old ones die.

    I would like to have an option that a new particle is emitted always, BUT it replaces the oldest particle, like a ring-buffer concept. This has a big advantage for rendering these kind of things.

    So far, I need to specify a particle lifetime to make sure there is always room for a new particle. However, if the player does not move and is just looking around, it's very noticeable that older footprints vanish due to the lifetime. (no matter whether they fade out or just hide immediately)

    If the particle system supports to replace the oldest particle with a new one, particles can have an infinite lifetime, while maintaining the "Max Particles" budget. In my case, the problem with obvious vanishing of footprints would be minimized as well, because old particles get replaced while the player is moving only, which is hiding this issue. The same applies to bullet impacts.

    Several games seem to use that "ring buffer" concept for these things. For example, I noticed this recently in Call of Duty Modern Warfare Remastered.

    I believe this mode is generic and could be used for a lot of things, not only for what I use it in my game. That's why I suggest it here for the ParticleSystem, rather than coming up with a custom solution.

    I could probably use DrawMeshInstancedIndirect for that as well, but it feels a bit overkill for just a quad to use GPU instancing for that. The ParticleSystem also comes with a lot of useful other options, that would require a tremendous effort to reimplement in an own system.

    What do you think?
     
    karl_jones likes this.
  2. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    It’s a good suggestion, and one that has been made a few times before :) it’s just never quite made it to the top of the feature request pile..

    I think we could add it.

    I wonder how all the Lifetime-based properties should behave though. Should they all just pause at the end, so particles can still have lifetimes in the current sense, but simply don’t die at the end of their life, and instead hang around until overwritten?

    What do you think?

    Also, DrawMeshInstancedIndirect should actually be a very efficient way to solve this, although maybe the additional c# code required to manage the ringbuffer might have some non-negligible cost.
     
    karl_jones and Peter77 like this.
  3. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Also, I bet you’d like your footprints to fade out, rather than pop, ideally, when they need to be replaced? (I know I would, if I were you!) I don’t have any ideas right now for how that might work...
     
    karl_jones likes this.
  4. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Just adding own experiences:

    I used a technique of setting Particle from a local array for mobile when it turned out to be far too slow with other options, and that point sprites weren't guaranteed to function well. This was awesome and I was able to handle several thousand on a mobile where otherwise I'd have had to construct some form of elaborate shader system. I did not actually use any of the features of the particle system except as a dumb renderer.

    I also had to hack in some form of time code for changing the image of the particle as the wasn't any API support properly for it back then (this was Unity 4).

    But these days I'd probably just go with DrawMeshInstancedIndirect, unless quads are much faster under a GPU particle system in the future.
     
  5. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    Good point, I didn't think of that. This is where it gets more complicated. :) I first thought was they all just pause at the end. But this feels like a harsh limitation. It would certainly work for my case, but this wouldn't make it as generic as I though it would be.

    Another idea that comes to mind is to use loop-markers. I know this from audio systems, where you specify attack (fade-in), sustain (loop) and release (fade-out) markers (see ADSR). This makes it enormously easy to play looping sounds with proper fade-in and fade-out, audio designers love it.

    Theoretically, the same concept could work with particles. If you can specify a "loop range" in a particle system, a particle could fade-in, loop until something signals "please die" and then fade-out. The loop-range would be specified using a time range. I imagine the "lifetime" of a particle would "freeze" while it's in the loop-range. A loop range is also easy to understand when authoring a particle effect.

    If a particle has a "fade-out" in this example, it can't be replaced immediately with the new particle as I suggested in my initial post. The PS would probably need some kind of "buffer" in the particle array to allow these particles to fade-out, but not exceeding the Max Particles property.

    Thanks for the info, perhaps I should just give it a try. But I like the particle system so much, that makes it hard to replace :)

    PS: Thanks for your support even on a Saturday! I certainly didn't except a response to rapidly.

    PS2: Having loop-markers would actually solve quite a few issues. I had to mimic this in various projects actually, where our VFX artist had to create separate fade-in, loop and fade-out particle effects and I had to implement code to glue them together. I remember a flamethrower was one of it. With loop-markers, the VFX artist could create one effect that contains everything and he/she could actually test it properly.
     
    Last edited: Mar 3, 2018
    richardkettlewell likes this.
  6. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    Any thoughts on the loop-marker idea?
     
  7. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Loop markers sound good.. but would probably be quite a large change, as it’s quite different from how the curves are currently evaluated. Though we do have loop/ping-pong modes, so maybe we could add a new one. It would need a bunch of new UI stuff too. All doable, but I’m thinking this makes it a bigger task that we wouldn’t be able to get in a public version for quite some time.

    Any fading means its impossible to constrain to max-particles, exactly, too. (If you are already at your limit, and you want to spawn a new one, you cannot fade old ones out without temporarily allowing more than max-particles to be alive at once.

    Overall, I think we could add a ring buffer mode with no fading, very quickly and easily.

    To do fading via a simple “fade out time” property which reduced the alpha over time before removing, would also be quite simple.

    The loop marker thing, whilst I agree is the most powerful, would take a lot longer to develop.
     
    Peter77 likes this.
  8. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    I did imagine it would be quite a large change, but wanted mention it anyway, because I thought it might solve the Lifetime-based properties handling issue you mentioned. Perhaps it's something to keep in mind for a future particle system iteration.

    If you believe it's a good idea and won't cause issues in the long-run, due to its limitations, then I'm all in for that new mode. It certainly would help with what I'm trying to solve here.
     
  9. mh114

    mh114

    Joined:
    Nov 17, 2013
    Posts:
    295
    I second the need for a wrapping / ring buffer. All the particle systems I've made for my own engines have always just looped over an array overwriting the oldest (really just wrapping the index) when new particles are spawned, it is a very common and useful tactic. Especially with more hectic situations where there are lots of effects going on, it will always look worse when no particles are emitted when expected, than when old effects vanish to make room for new particles, IMHO.
     
    richardkettlewell likes this.
  10. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Hey all,

    We've had a go at implementing this :)

    Please take a look at this preview build: https://forum.unity.com/threads/release-ringbuffer-mode.523963/
    Let us know what you think here: https://forum.unity.com/threads/feedback-ringbuffer-mode.523964/

    It has 2 modes - one replaces particles instantly, and the other uses a ADSR (ish) approach, close to what Peter suggested: The particle lifetimes will Attack (fade-in), then Sustain (loop), and when they need to be replaced, they will Release (fade out). This is achieved simply by modifying their current lifetime of each particle, so you only get one setting applied to all curves that use particle lifetimes. You can specify the loop range in the main particle settings.