Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice
  2. We've opened up a space to discuss, share feedback, and showcase everything related to the Unity Shader Graph! Come show us what you've made.
    Dismiss Notice

A more efficient Job that controls all particles in many ParticleSystems.

Discussion in 'Scripting' started by WakeupFive, Feb 12, 2019.

  1. WakeupFive

    WakeupFive

    Joined:
    Nov 1, 2016
    Posts:
    2
    I have implemented the ability to control the height and color of many particles.

    I have implemented the necessary functions using the Job system, but there is a time-consuming problem in reading and writing particles.

    Is there anything I can do to improve my code?

    There are 1000 ParticleSystems and each with 50 particles, controlling a total of 50,000 particles.
    Version is 2018.2.20f1.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using Unity.Collections;
    4. using Unity.Jobs;
    5. using UnityEngine;
    6.  
    7. public class LEDController : MonoBehaviour
    8. {
    9.     [SerializeField]
    10.     private ParticleSystem[] particles;
    11.  
    12.     private ParticleSystem.Particle[][] all;
    13.     private int[] lengths;
    14.  
    15.     private void Start()
    16.     {
    17.         all = new ParticleSystem.Particle[particles.Length][];
    18.  
    19.         for (int i = 0; i < all.Length; i++)
    20.         {
    21.             all[i] = new ParticleSystem.Particle[particles[i].main.maxParticles];
    22.         }
    23.  
    24.         lengths = new int[particles.Length];
    25.     }
    26.  
    27.     private void Update()
    28.     {
    29.         // Total time : 22ms
    30.         //
    31.         int psLength = all.Length;
    32.         float time = (Time.time % 0.25f) / 0.25f;
    33.         int allCount = 0;
    34.  
    35.         // get particles
    36.         // time : 2.5ms
    37.         for (int i = 0; i < psLength; i++)
    38.         {
    39.             int length = particles[i].GetParticles(all[i]);
    40.             allCount += length;
    41.             lengths[i] = length;
    42.         }
    43.  
    44.         var info = new NativeArray<Info>(allCount, Allocator.Temp);
    45.      
    46.         // get particles info
    47.         // time : 5.5ms
    48.         int count = 0;
    49.         for (int i = 0; i < psLength; i++)
    50.         {
    51.             for (int j = 0; j < lengths[i]; j++)
    52.             {
    53.                 var infoA = new Info();
    54.                 infoA.pos = all[i][j].position;// = new Info(all[i][j]);
    55.                 infoA.color = all[i][j].startColor;// = new Info(all[i][j]);
    56.  
    57.                 info[count] = infoA;
    58.  
    59.                 count++;
    60.             }
    61.         }
    62.  
    63.         // execute job
    64.         // time : 3ms
    65.         VerticalJob job = new VerticalJob();
    66.  
    67.         job.info = info;
    68.         job.time = time;
    69.  
    70.         var handle = job.Schedule(allCount, 1);
    71.         handle.Complete();
    72.  
    73.         // set particles info
    74.         // time : 7.5ms
    75.         count = 0;
    76.         for (int i = 0; i < psLength; i++)
    77.         {
    78.             for (int j = 0; j < lengths[i]; j++)
    79.             {
    80.                 all[i][j].position = info[count].pos;
    81.                 all[i][j].startColor = info[count].color;
    82.  
    83.                 count++;
    84.             }
    85.         }
    86.  
    87.         // set particles
    88.         // time : 3.5ms
    89.         for (int i = 0; i < psLength; i++)
    90.         {
    91.             particles[i].SetParticles(all[i], lengths[i]);
    92.         }
    93.  
    94.         // End
    95.         info.Dispose();
    96.     }
    97.  
    98.     public struct VerticalJob : IJobParallelFor
    99.     {
    100.         [ReadOnly]
    101.         public float time;
    102.  
    103.         public NativeArray<Info> info;
    104.  
    105.         public void Execute(int index)
    106.         {
    107.             Info i = info[index];
    108.  
    109.             Vector3 p = i.pos;
    110.             float alpha = (p.x + time) % 100f;
    111.  
    112.             Color32 c = i.color;
    113.             c.a = (byte)(255 * (alpha / 100f));
    114.             i.color = c;
    115.  
    116.             p.y = alpha;
    117.             i.pos = p;
    118.  
    119.             info[index] = i;
    120.         }
    121.     }
    122.  
    123.     public struct Info
    124.     {
    125.         public Vector3 pos;
    126.         public Color color;
    127.     }
    128. }
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    1,392
    You can postpone .Complete on the job, simply by storing a handle and calling complete in .LateUpdate(). This should give the job some time in background without hanging main thread.

    Also, note that there's an actual ParticleJob available exactly for that, and should elliminate .Get/.Set on the particle system and scheduling / completing.

    https://forum.unity.com/threads/release-particle-system-c-job-system-support.529284/

    Example from that link:
    Code (CSharp):
    1. using Unity.Collections;
    2. using UnityEngine;
    3. using UnityEngine.Experimental.ParticleSystemJobs;
    4. public class ParticleJob : MonoBehaviour
    5. {
    6.     void Start ()
    7.     {
    8.         var job = new UpdateParticlesJob();
    9.         job.color = Color.red;
    10.         job.size = 0.35f;
    11.         GetComponent<ParticleSystem>().SetJob(job);
    12.     }
    13.     struct UpdateParticlesJob : IParticleSystemJob
    14.     {
    15.         [ReadOnly]
    16.         public Color color;
    17.         [ReadOnly]
    18.         public float size;
    19.         public void ProcessParticleSystem(JobData particles)
    20.         {
    21.             var startColors = particles.startColors;
    22.             var sizes = particles.sizes.x;
    23.             for (int i = 0; i < particles.count; i++)
    24.             {
    25.                 startColors[i] = color;
    26.                 sizes[i] = size;
    27.             }
    28.         }
    29.     }
    30. }
     
  3. WakeupFive

    WakeupFive

    Joined:
    Nov 1, 2016
    Posts:
    2
    Thanks, but I moved "JobHandle.Complate ()" to "LateUpdate", but there was little difference in performance ...

    And when IParticleSystemJob is not found in the 2018.3 version, when is it available?
     
  4. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    1,392
    If it's not a part of Jobs package (maybe an upgrade?) then I'd say it's 2019 feature.