Search Unity

In a previous post, I wrote about the performance considerations when using the various curve modes available in the particle system. This time, we will take a look into particle system culling.

TL;DR

  • Culling is only possible when a system has predictable behaviour.
  • Turning on a single module will not only add to that module’s overhead, but may increase the overall systems impact due to switching from procedural to non-procedural mode.
  • Changing values via script will prevent culling.
  • Using custom culling can provide a performance benefit, but only you the developer can decide if and when it is appropriate. Take into consideration the type of effect, if the player may notice it isn’t animating when invisible, and if it is possible to predict the area it will affect?

Procedural Mode

Internally, each particle system has 2 modes of operating, procedural and non-procedural.

In procedural mode it is possible to know the state of a particle system for any point in time (past and future) whereas a non-procedural system is unpredictable. This means that it is possible to quickly fast forward (and rewind) a procedural system to any point in time.

When a system goes out of the view of any camera, it becomes culled. When this occurs, a procedural system will halt updating.  It will efficiently fast forward to the new point in time when the system becomes visible again. A non-procedural system cannot do this, it must continue updating the system even when invisible due to its unpredictable nature.

For example, the following system is predictable.It’s in local space, so the movement of the particle system’s transform does not matter; the particles are not influenced by any external forces such as collisions, triggers and wind. This means we are able to calculate the total bounds that particles will exist within during the lifetime of the system (yellow box) and can safely cull the system when not visible.

By changing the particle system to world space, it becomes unpredictable. When a particle is spawned it will need to sample the position of the transform at that moment. The position of the transform is unpredictable, its history and future are unknown.,Therefore, the system must continue to update itself even when invisible in order for the particles to be in the correct positions when it becomes visible again.

By changing the system to world space it becomes unpredictable. There is no way for the system to know the location of the particles without continuing to update itself whilst invisible.

What breaks procedural mode, how do I know I have broken it?

When a particle system doesn’t support procedural mode, a small icon is displayed in the Inspector. Mousing over this icon will provide a tooltip that lists the reasons why the system no longer supports procedural mode and cannot be culled. It’s also possible to see that non-procedural mode is in use by looking at the bounding bound of the particle system, a continually changing bounds that only encapsulate the particles are a sign that procedural mode isn’t being used.

The following are examples of conditions that break support for procedural mode.

Module Property What breaks it?
Simulation Space World space
Main Gravity modifier Using curves
Emission Rate over distance Any non zero value
External forces enabled true
Clamp velocity enabled true
Rotation by speed enabled true
Collision enabled true
Trigger enabled true
Sub Emitters enabled true
Noise enabled true
Trails enabled true
Rotation by lifetime Angular Velocity if using a curve and the curve does not support procedural*
Velocity over lifetime X, Y, Z If using a curve and the curve does not support procedural*
Force over lifetime X, Y, Z If using a curve and the curve does not support procedural*
Force over lifetime Randomise enabled

*A curve can not support procedural mode if it has more than 8 segments. A segment is the number of keys plus an additional key if the curve does not start at 0.0 and another if does not end at 1.0.

Invalidating procedural mode in the player

Procedural mode is based on knowing exactly how the system will behave at a specified point in time with no external influences. If a value is changed via script or in the editor during play mode then those assumptions can’t be made and procedural mode is invalidated. This means that even though a system is using all procedurally safe settings, it’s no longer possible to use procedural mode and the system will not be culled anymore.

Changing a value or Emitting via script will invalidate procedural mode, which you can notice by examining the bounds of the system in the scene. If the bounds are continuously changing then the procedural mode is no longer being used.

Sometimes this can be avoided by using the particle system’s built in features to change properties, instead of using a script.

Calling Play on a system that has been stopped will reset the system and re-validate procedural mode.

Performance example

The performance difference between a procedural and a non-procedural system can be significant. This difference is most noticeable when a system is offscreen. In a scene containing 120 default systems, each simulating 1000 particles, the following performance difference is shown between local space (procedural) and world space (non-procedural). The left area shows the performance when not culled, and the right shows when culled.

The blue area represents the work performed by the particle system.

Custom Culling

The following example shows a simple 2D rain effect that uses the collision module (breaking procedural mode).

By using the collision module the system is now unpredictable; colliders could be moved or have their properties changed throughout the life of the system. This means that predicting where particles will be in the future is impossible, and therefore the system must continue to update whilst culled.

A simple rain effect using the collision module to create a splash effect. The yellow boxes represent the bounding areas.

We can see that the collision effect is localised within an area and we will not be moving the transform throughout the life; the particle system has no way to know this though.

It is safe for an effect like this to not be updated whilst invisible; it could benefit from custom culling.

The CullingGroup can be used to integrate into Unity’s culling system, using it we can create a culling area using bounding spheres. When the spheres go in and out of visibility a notification is sent; we can use this to pause the particle system when it is not visible and resume it when it becomes visible again. One downside is that off-screen particles will appear motionless, which can be noticeable in some effects. It’s possible to hide this issue by simulating the system forward a little so as to give the illusion that the system was still active whilst not visible.

A custom bounding sphere encapsulates the area the rain effect will influence.

Performance when using 100 rain systems.

Not all effects are suited to custom culling. The system on the left is custom culled and can be seen to clearly go out of sync whilst the system on the right isn’t culled. This illustrates why non-procedural systems must be updated when not visible.

Комментарии закрыты.

  1. I think the test code should add updae code for test:

  2. I have the request :)
    Can you add uv support for each particle in ParticleSystem.Particle struct to have control on each particle texture. Now it’s impossible, but this feature will be the great improvement in ParticleSystem control. Thanks.

  3. thanks for this info:)

  4. Hi, I have a question. When a particle system is culled, is it not rendering or not simulating or neither?

    1. It won’t be rendered when culled but simulating is dependent on procedural Mode.

  5. Extremely well written and useful article. Thank you!

  6. Now this is a great blog post,
    Might be helpfull to change the inspector icon into a warning icon or something, just to make more clearer to user, for me personally i never notice that icon before.
    Also can i request another blog post regarding culling group. it seems very usefull but the documentation are bit unclear.

    1. Thanks. I do plan to Improve the warning icon. I’ll make a note to improve the docs on the CullingGroup or maybe write another blog post on it 😀

      1. Awesome, great to hear that.
        Oh and how about also adding a expandable note box just above the particle system module to contain the warning message rather than tooltip?

      2. I’d love to read more about culling groups and best practices too!

  7. Does the animator culling work the same way? By which I mean : if I call ‘play animation’ via script, will I break procedural mode?

    1. Procedural Mode is a particle only feature. I’m not aware of such limitations on the animator but you do have more control of culling mode on the skinned mesh renderer via the drop down.

  8. Hey Karl, lovely blog post. This is info I really needed.

    However I do have a suggestion. I’m sure you’ll agree that there’s just too many variables for a typical end-user to track to get it to be procedural. Artists will need to constantly refer to a table and double check.

    So I thought: This is back to front. As the desire would be there to be procedural why not have a «procedural» tickbox at the top and this greys out all elements which would prevent it being procedural.

    Just a thought for ease-of-use :)

    1. (or clamps etc)

      It just seems too stressful to reach optimisation without help in this case. And people wanting optimisation will accept the limitations.

      1. Thanks Robert. It could be possible to disable them although having a non procedural system is perfectly fine. I would not want people to think they should not use these features, it’s more just about being aware of the implications and picking the right tool for the job. I do plan to improve the warning icon so it’s clearer though.

        1. How about instead of disabling properties then, you simply indicate if the system is currently procedural or not in the editor?

        2. We already do! Read the bit What breaks procedural mode, how do I know I have broken it?

  9. Is anyone noticed if you’re working with the particle editor for a longer time it becomes painfully slow to change parameters without restarting the editor?

    1. That’s not something I have heard before. Try running the profiler in editor mode and see if something shows up. Could you file a bug report please?

  10. Very nice, clear, post on particle systems perf.

    I’d like to see a bit more on the Simulate-forward approach — this seems essential in most games, and yet it’s often almost useless.

    In most engines, you would give Simulate a «start from» time and a «simulate to» time, or you’d give it a «rewind backwards time». Simulate accepts none of these — you can reset to 0, or … go into the future. In practice, it seems you can’t keep it in synch unless you’re willing to take a large, unnecessary, performance hit when it comes on screen? (becaue you can only rewind all the way to zero!).

    …so far we’ve always ignored it and written our own solution. I’d be much happier to see some explanation of how to use it efficiently!

    1. (I hit submit too soon, I meant to preface that with «on the surface, it appears that…». I’m sure there are simple workarounds that make Simulate work better, I’d like to see those in the post.

      The particle system is much better now than it used to be, and I’m trying to stop using the proprietary replacements we’ve used in the past, I’d prefer to move everything across to stock Unity particle system.)

      1. Thanks. Yes the Simulate function can be a little confusing at times. I’ll look into improving the scripting docs for it, perhaps add some additional examples.