Search Unity

Mathematics.Random with in IJobProcessComponentData

Discussion in 'Entity Component System' started by Vacummus, Dec 14, 2018.

  1. Vacummus

    Vacummus

    Joined:
    Dec 18, 2013
    Posts:
    191
    I am very puzzled on how to use Mathematics.Random in a IJobProcessComponentData system. In the sample code below, I am trying to output a random value. However, the value here always outputs to 294.0988. How do you get a random value within a job?

    Code (CSharp):
    1. [BurstCompile]
    2. struct Job: IJobProcessComponentData<RandomTest>
    3. {
    4.     public void Execute([WriteOnly] ref RandomTest random)
    5.     {
    6.         random.value = new Random(0x6E624EB7u).NextFloat(0, 360);
    7.     }
    8. }
     
    Last edited: Dec 14, 2018
  2. Soaryn

    Soaryn

    Joined:
    Apr 17, 2015
    Posts:
    328
    Random takes a seed. In this case, you are always using the same seed and then calling the first value. Indstead, either send a random seed to the job each startup or send the same random to all jobs
     
    Vacummus and Tony_Max like this.
  3. Vacummus

    Vacummus

    Joined:
    Dec 18, 2013
    Posts:
    191
    I see, thanks! For others struggling with this, here is a working solution based on the answer from @Soaryn :
    Code (CSharp):
    1. public class RandomTestSystem: JobComponentSystem
    2. {
    3.     [BurstCompile]
    4.     struct Job: IJobProcessComponentData<RandomTest>
    5.     {
    6.         public Unity.Mathematics.Random random;
    7.  
    8.         public void Execute([WriteOnly] ref RandomTest randomTest)
    9.         {
    10.             randomTest.value = random.NextFloat(0, 360);
    11.         }
    12.     }
    13.  
    14.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    15.     {
    16.         var random = new Unity.Mathematics.Random((uint)UnityEngine.Random.Range(1, 100000));
    17.    
    18.         return new Job { random = random }.Schedule(this, inputDeps);
    19.     }
    20. }
     
    Kemorno and LukePammant like this.
  4. Soaryn

    Soaryn

    Joined:
    Apr 17, 2015
    Posts:
    328
    As a note, you can still use the same set seed (which may be better) and just store the random in the system rather than onUpdate. This way you have no need to recreate every frame :)
    See the method override of OnCreateManager
     
  5. Vacummus

    Vacummus

    Joined:
    Dec 18, 2013
    Posts:
    191
    That won't work. Well... you can do it but you won't get the results you are expecting. Random is a struct, which gets passed by value and not by reference. This means that every time you try to pass Random to a job, it always gets recreated. And if you are passing a Random to the job with the same seed, then every frame it will always start off with the same values, which is not so random.
     
  6. Soaryn

    Soaryn

    Joined:
    Apr 17, 2015
    Posts:
    328
    Fair!

    My only other recommendation then is just use the same random type to generate the seed. More for consistency but not rquired :)
     
  7. Vacummus

    Vacummus

    Joined:
    Dec 18, 2013
    Posts:
    191
    Hmmm, not sure I follow. What do you mean by same random type?
     
  8. If you have an approximation how many random numbers you will need, you can prepare a NativeArray of random values ahead of time and pass it in the jobs. You can even read it from multiple thread if it's readonly. I created noise this way and read curves (take the curve, probe it at N points and store the numbers in an array).
     
  9. Soaryn

    Soaryn

    Joined:
    Apr 17, 2015
    Posts:
    328
    When you create the random in the update, you are currently utilizing the UnityEngine.Random variant, which is ok, but I'd recommend consistency for any design ;) even in a mock up example
     
  10. iam2bam

    iam2bam

    Joined:
    Mar 9, 2016
    Posts:
    36
    Thanks to this post I figured a way to work out this in parallel this way:

    Keep some persistent random number generators (RNG):
    Code (CSharp):
    1.    
    2. using Unity.Collections.LowLevel.Unsafe;
    3. using Unity.Jobs.LowLevel.Unsafe;
    4.  
    5. //...
    6.    NativeArray<Unity.Mathematics.Random> _rngs;
    7.  
    8.     protected override void OnCreateManager() {
    9.         _rngs = new NativeArray<Unity.Mathematics.Random>(JobsUtility.MaxJobThreadCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
    10.         for(int i = 0; i < JobsUtility.MaxJobThreadCount; i++)
    11.             _rngs[i] = new Unity.Mathematics.Random((uint)UnityEngine.Random.Range(int.MinValue, int.MaxValue));
    12.     }
    13.  
    14.     protected override void OnDestroyManager() {
    15.         _rngs.Dispose();
    16.     }
    And here's the code
    Code (CSharp):
    1.     struct RandomizeParallelComponentDataJob : IJobProcessComponentData<Dat_RenderProps>
    2.     {
    3.         [NativeDisableContainerSafetyRestriction]
    4.         public NativeArray<Unity.Mathematics.Random> rngs;
    5.  
    6.         [NativeSetThreadIndex]
    7.         int threadId;
    8.  
    9.         public void Execute(ref Dat_RenderProps props) {
    10.             var rng = rngs[threadId];
    11.             props.color = new float4(rng.NextFloat3(), 1);
    12.             rngs[threadId] = rng;        //This is necessary to update the state of the element inside the array.
    13.         }
    14.     }
    15.  
    16. //...
    17.  
    18.         var job = new RandomizeParallelComponentDataJob {
    19.             rngs = _rngs
    20.         };
    21.         return job.Schedule(this, inputDeps);




    Or if you need IJobParallelFor:

    Code (CSharp):
    1.         var job = new RandomizeParallelJob {
    2.             rngs = _rngs
    3.             , propsArray = _group.propsArray
    4.         };
    5.         return job.Schedule(_group.Length, 64, inputDeps);
    6.  
    7. //...
    8.  
    9.  
    10.     struct RandomizeParallelJob : IJobParallelFor
    11.     {
    12.         public ComponentDataArray<Dat_RenderProps> propsArray;
    13.  
    14.         [NativeDisableContainerSafetyRestriction]
    15.         public NativeArray<Unity.Mathematics.Random> rngs;
    16.  
    17.         [NativeSetThreadIndex]
    18.         int threadId;
    19.  
    20.         public void Execute(int index)
    21.         {
    22.             var props = propsArray[index];
    23.  
    24.             var rng = rngs[threadId];
    25.             props.color = new float4(rng.NextFloat3(), 1);
    26.             rngs[threadId] = rng;    //This is necessary to update the state of the element inside the array.
    27.  
    28.             propsArray[index] = props;
    29.         }
    30.     }
     
    atadev1, mikaelK, Haneferd and 13 others like this.