Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to use IJobParallelForTransform now that ComponentDataArray is removed?

Discussion in 'Entity Component System' started by davenirline, Apr 17, 2019.

  1. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    I have this existing system that uses a Transform to transform the vertices of a sprite.

    Code (CSharp):
    1. public class TransformGameObjectSpriteVerticesSystem : JobComponentSystem {
    2.     private EntityQuery query;
    3.  
    4.     [BurstCompile]
    5.     private struct OldJob : IJobParallelForTransform {
    6.         public ComponentDataArray<Sprite> sprites;
    7.        
    8.         public void Execute(int index, TransformAccess transform) {
    9.             Sprite sprite = this.sprites[index];
    10.             float4x4 rotationTranslationMatrix = new float4x4(transform.rotation, transform.position);
    11.             float4x4 scaleMatrix = float4x4.Scale(transform.localScale);
    12.             float4x4 matrix = math.mul(rotationTranslationMatrix, scaleMatrix);
    13.             sprite.Transform(ref matrix);
    14.  
    15.             this.sprites[index] = sprite; // Modify the data
    16.         }
    17.     }
    18.  
    19.     protected override void OnCreateManager() {
    20.         // All entities with Sprite and Transform, but without Static (non Static sprites)
    21.         this.query = GetEntityQuery(typeof(Sprite), typeof(Transform), ComponentType.Exclude<Static>());
    22.     }
    23.  
    24.     protected override JobHandle OnUpdate(JobHandle inputDeps) {
    25.         OldJob oldJob = new OldJob() {
    26.             sprites = this.query.GetComponentDataArray<Sprite>()
    27.         };
    28.        
    29.         return oldJob.Schedule(this.query.GetTransformAccessArray(), inputDeps);
    30.     }
    31. }
    Now that ComponentDataArray is removed, how do I do something like this now?
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,683
    ToComponentDataArray -> job -> FromComponentDataArray
     
  3. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Sorry, I don't get it. Mind explaining it?
     
  4. frankfringe

    frankfringe

    Joined:
    Feb 9, 2019
    Posts:
    105
    This was posted yesterday on discord, I guess it does what you want

    Code (CSharp):
    1. struct AddForces : IJobForEachWithEntity<PhysicsVelocity, PhysicsMass>
    2. {
    3.     [ReadOnly][DeallocateOnJobCompletion] public NativeArray<Impulse> Impulses;
    4.            
    5.     public void Execute(Entity entity, int index, ref PhysicsVelocity c0, ref PhysicsMass c1) {
    6.         for (int i = 0; i < Impulses.Length; i++) {
    7.             if (Impulses[i].Target.Equals(entity)) {
    8.                  c0.Linear += Impulses[i].Force / c1.InverseMass;
    9.             }
    10.         }
    11.     }
    12. }
    13.  
    14. //OnCreate
    15. m_Impulses = GetEntityQuery(typeof(Impulse));
    16. //OnUpdate
    17. var job = new AddForces
    18. {
    19.     Impulses = m_Impulses.ToComponentDataArray<Impulse>(Allocator.TempJob)
    20. };
     
  5. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    You call ToComponentDataArray on an EntityQuery to get a NativeArray of components to pass to the job. But those are a copy, so when the job is done you need to copy the array back using CopyFromComponentDataArray on the same EntityQuery. Both copies are on the main thread and the second one will I'm pretty sure force a sync point.

    Basically don't use IJobParallelForTransform for anything but writing to the transform. For transform read access it's going to be better using GetTransformAccessArray and then pass that to say an IJobForEachWithEntity so you have the index into the transform array. That will avoid some extra copying and syncing.
     
    frankfringe and davenirline like this.
  6. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    I tried this but I'm getting this error. Even adding the mentioned attribute did not work.

    InvalidOperationException: Job.Data.transforms.m_TransformArray uses unsafe Pointers which is not allowed. Unsafe Pointers can lead to crashes and no safety against race conditions can be provided.
    If you really need to use unsafe pointers, you can disable this check using [NativeDisableUnsafePtrRestriction].


    Code (CSharp):
    1. [BurstCompile]
    2. private struct Job : IJobForEachWithEntity<Sprite> {
    3.     [NativeDisableUnsafePtrRestriction]
    4.     public TransformAccessArray transforms;
    5.  
    6.     public void Execute(Entity entity, int index, ref Sprite sprite) {
    7.         Transform transform = this.transforms[index];
    8.         float4x4 rotationTranslationMatrix = new float4x4(transform.rotation, transform.position);
    9.         float4x4 scaleMatrix = float4x4.Scale(transform.localScale);
    10.         float4x4 matrix = math.mul(rotationTranslationMatrix, scaleMatrix);
    11.         sprite.Transform(ref matrix);
    12.     }
    13. }
    Maybe because it's using Transform and not TransformAccess. However, I can't find any accessor of TransformAccess from TransformAccessArray.
     
    Last edited: Apr 20, 2019
  7. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    This works but it's not multithreaded. Still better than nothing:
    Code (CSharp):
    1. protected override void OnUpdate() {
    2.     NativeArray<Sprite> sprites = this.query.ToComponentDataArray<Sprite>(Allocator.TempJob);
    3.     TransformJob transformJob = new TransformJob() {
    4.         sprites = sprites
    5.     };
    6.     transformJob.Schedule(this.query.GetTransformAccessArray()).Complete();
    7.    
    8.     this.query.CopyFromComponentDataArray(sprites);
    9.    
    10.     sprites.Dispose();
    11. }
    12.  
    13. [BurstCompile]
    14. private struct TransformJob : IJobParallelForTransform {
    15.     public NativeArray<Sprite> sprites;
    16.    
    17.     public void Execute(int index, TransformAccess transform) {
    18.         Sprite sprite = this.sprites[index];
    19.         float4x4 rotationTranslationMatrix = new float4x4(transform.rotation, transform.position);
    20.         float4x4 scaleMatrix = float4x4.Scale(transform.localScale);
    21.         float4x4 matrix = math.mul(rotationTranslationMatrix, scaleMatrix);
    22.         sprite.Transform(ref matrix);
    23.  
    24.         this.sprites[index] = sprite; // Modify the data
    25.     }
    26. }
     
  8. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Look at the out JobHandle version of ToComponentDataArray/CopyFromComponentDataArray. You can use those, combine them and chain the entire thing.
     
  9. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    I'm not doing a copy back in my case, but this is from a working example that illustrates what I mean.

    Code (csharp):
    1.  
    2. var proxies = TransformGroup.ToComponentDataArray<CombatEntityProxy>(Allocator.TempJob, out JobHandle proxyHandle);
    3. var steerings = TransformGroup.ToComponentDataArray<AgentSteering>(Allocator.TempJob, out JobHandle steeringHandle);
    4. inputDeps = JobHandle.CombineDependencies(inputDeps, proxyHandle, steeringHandle);
    5.  
    6.             var transforms = TransformGroup.GetTransformAccessArray();
    7.             CombatProxyTransformSyncJob tjob = new CombatProxyTransformSyncJob
    8.             {
    9.                 DeltaTime = Time.deltaTime,
    10.                 Time = Time.time,
    11.                 Proxies = proxies,
    12.                 AgentSteerings = steerings,
    13.             };
    14.             inputDeps = tjob.Schedule(transforms, inputDeps);
    15.  
     
    davenirline likes this.
  10. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    969
    Thanks!