Search Unity

IJobChunk for physics - asking for help

Discussion in 'Entity Component System' started by Fluidmind, Jun 30, 2020.

  1. Fluidmind

    Fluidmind

    Joined:
    Jan 10, 2020
    Posts:
    28
    So I've been trying to solve this problem for a bit now, and every time I keep tripping on some catch I was not aware of in the Job system. A post a year ago that tertle replied to (https://forum.unity.com/threads/get-component-array.629374/) regarding using ArchetypeChunks to write the data I needed (first code spoiler below), but got the exception:
    InvalidOperationException: The NativeArray can not be Disposed because it was not allocated with a valid allocator.
    Unity.Collections.NativeArray`1[T].Dispose () (at <05f2ac9c8847426992765a22ef6d94ca>:0)
    GravitySystem+ApplyGravityJob.Execute (Unity.Entities.ArchetypeChunk emitterChunk, System.Int32 chunkIndex, System.Int32 firstEntityIndex) (at Assets/Scripts/Systems/SphericalGravityEmitter.cs:119)
    The instruction at this mark is the subjects array, which came from an ArchetypeChunk.GetNativeArray(ArchetypeChunkEntityType), so I'm not sure what's happening here? Do I need to initialize it with an allocator before calling the GetNativeArray function?

    Then I switched to trying an entities.ForEach approach (second spoiler), but on entering play mode, the exception at the top of the stack was that entityData needed to be declared [ReadOnly]:InvalidOperationException: The NativeArray <>c__DisplayClass_OnUpdate_LambdaJob0.JobData.entityData must be marked [ReadOnly] in the job GravitySystem:<>c__DisplayClass_OnUpdate_LambdaJob0, because the container itself is marked read only., but I kind of use that variable quite a lot. I use them to write the current data and figure out what needs to be applied.

    So, this is my ask: I want the large, massive bodies to draw objects toward them. I would prefer if each massive object got to the force application of its own subjects. I'm new to the system, and have been trying and failing at this for a while now. What approach can I take to achieve this goal? And if this should be cross posted elsewhere to get code guidance, a referal would be much appreciated.

    Thanks.

    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Collections.LowLevel.Unsafe;
    3. using Unity.Entities;
    4. using Unity.Entities.UniversalDelegates;
    5. using Unity.Jobs;
    6. using Unity.Mathematics;
    7. using Unity.Physics;
    8. using Unity.Physics.Systems;
    9. using Unity.Physics.Extensions;
    10. using Unity.Transforms;
    11. using Unity.Burst;
    12. using System.Diagnostics;
    13. using Unity.Physics.Authoring;
    14. using UnityEngine;
    15. using System;
    16. using UnityEngine.UIElements;
    17. using System.Linq;
    18.  
    19. [GenerateAuthoringComponent]
    20. public struct SphericalGravityEmitter : IComponentData
    21. {
    22.     public float radius;
    23. }
    24.  
    25. [UpdateBefore(typeof(BuildPhysicsWorld))]
    26. public unsafe class GravitySystem : JobComponentSystem
    27. {
    28.     EntityQuery getEmitters;
    29.     EntityQuery getSubjects;
    30.     protected override void OnCreate()
    31.     {
    32.         base.OnCreate();
    33.  
    34.         getEmitters = GetEntityQuery(ComponentType.ReadOnly<SphericalGravityEmitter>());
    35.  
    36.         getSubjects = GetEntityQuery(ComponentType.ReadOnly<GravitySubject>());
    37.     }
    38.  
    39.     protected override void OnStartRunning()
    40.     {
    41.         base.OnStartRunning();
    42.     }
    43.  
    44.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    45.     {
    46.         float _dt = Time.DeltaTime;
    47.        
    48.         NativeArray<ArchetypeChunk> subjects = getSubjects.CreateArchetypeChunkArray(Allocator.TempJob);
    49.         for (int s = 0; s < subjects.Length; s++)
    50.         {
    51.             gravityJob = new ApplyGravityJob
    52.             {
    53.                 dt = Time.DeltaTime,
    54.                 subjectChunk = subjects[s],
    55.                 positionChunkType = GetArchetypeChunkComponentType<Translation>(true),
    56.                 rotationChunkType = GetArchetypeChunkComponentType<Rotation>(true),
    57.                 emitterChunkType = GetArchetypeChunkComponentType<SphericalGravityEmitter>(true),
    58.                 entityChunkType = GetArchetypeChunkEntityType()
    59.             };
    60.             gravityHandle = gravityJob.Schedule(getEmitters, inputDeps);
    61.             inputDeps = JobHandle.CombineDependencies(inputDeps, gravityHandle);
    62.  
    63.         }
    64.  
    65.         subjects.Dispose();
    66.         return inputDeps;
    67.     }
    68.     ApplyGravityJob gravityJob;
    69.     JobHandle gravityHandle;
    70.  
    71.     protected struct ApplyGravityJob : IJobChunk
    72.     {
    73.         [ReadOnly] public float dt;
    74.         [ReadOnly] public ArchetypeChunk subjectChunk;
    75.  
    76.         [ReadOnly] public ArchetypeChunkComponentType<Translation> positionChunkType;
    77.         [ReadOnly] public ArchetypeChunkComponentType<Rotation> rotationChunkType;
    78.         [ReadOnly] public ArchetypeChunkComponentType<SphericalGravityEmitter> emitterChunkType;
    79.         [ReadOnly] public ArchetypeChunkEntityType entityChunkType;
    80.  
    81.         public void Execute(ArchetypeChunk emitterChunk, int chunkIndex, int firstEntityIndex)
    82.         {
    83.             NativeArray<Translation> subjectPositions = subjectChunk.GetNativeArray(positionChunkType);
    84.             NativeArray<Rotation> subjectRotations = subjectChunk.GetNativeArray(rotationChunkType);
    85.            
    86.             NativeArray<Translation> emitterPositions = emitterChunk.GetNativeArray(positionChunkType);
    87.             NativeArray<Rotation> emitterRotations = emitterChunk.GetNativeArray(rotationChunkType);
    88.             NativeArray<SphericalGravityEmitter> emitterData = emitterChunk.GetNativeArray(emitterChunkType);
    89.  
    90.             for (int e = 0; e < emitterChunk.Count; e++)
    91.                 for (int s = 0; s < subjectChunk.Count; s++)
    92.                 {
    93.  
    94.                     float3 direction = subjectPositions[s].Value - emitterPositions[e].Value;
    95.                     float distance = math.length(direction);
    96.  
    97.                     if (distance > emitterData[e].radius) return;
    98.                     else
    99.                     {
    100.                         NativeArray<Entity> subjects = subjectChunk.GetNativeArray(entityChunkType);
    101.                         NativeArray<Entity> emitters = emitterChunk.GetNativeArray(entityChunkType);
    102.                         PhysicsWorld world = World.DefaultGameObjectInjectionWorld.GetExistingSystem<BuildPhysicsWorld>().PhysicsWorld;
    103.  
    104.                         int emitterRigidBody = world.GetRigidBodyIndex(emitters[e]);
    105.                         int thisRigidBody = world.GetRigidBodyIndex(subjects[s]);
    106.  
    107.                         float3 thisCenterOfMass = PhysicsWorldExtensions.GetCenterOfMass(world, thisRigidBody);
    108.                         float thisMass = PhysicsWorldExtensions.GetMass(world, thisRigidBody);
    109.  
    110.                         float emitterMass = PhysicsWorldExtensions.GetMass(world, emitterRigidBody);
    111.  
    112.                         float3 unitDirection = direction / distance;
    113.                         float3 calcGravity = unitDirection * ((emitterMass * thisMass) / math.pow(distance, 2)) * dt;
    114.  
    115.                         if (math.length(calcGravity) < 0.05) calcGravity = float3.zero;
    116.  
    117.                         world.ApplyImpulse(thisRigidBody, calcGravity, thisCenterOfMass);
    118.  
    119.                         subjects.Dispose();
    120.                         emitters.Dispose();
    121.                     }
    122.  
    123.             }
    124.             subjectPositions.Dispose();
    125.             subjectRotations.Dispose();
    126.             emitterPositions.Dispose();
    127.             emitterRotations.Dispose();
    128.             emitterData.Dispose();
    129.         }
    130.     }
    131.  
    132.     protected override void OnStopRunning()
    133.     {
    134.         base.OnStopRunning();
    135.     }
    136.     protected override void OnDestroy()
    137.     {
    138.         base.OnDestroy();
    139.     }
    140. }

    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Collections.LowLevel.Unsafe;
    3. using Unity.Entities;
    4. using Unity.Entities.UniversalDelegates;
    5. using Unity.Jobs;
    6. using Unity.Mathematics;
    7. using Unity.Physics;
    8. using Unity.Physics.Systems;
    9. using Unity.Physics.Extensions;
    10. using Unity.Transforms;
    11. using Unity.Burst;
    12. using System.Diagnostics;
    13. using Unity.Physics.Authoring;
    14. using UnityEngine;
    15. using System;
    16. using UnityEngine.UIElements;
    17. using System.Linq;
    18.  
    19. [UpdateBefore(typeof(BuildPhysicsWorld))]
    20. public unsafe class GravitySystem : JobComponentSystem
    21. {
    22.     EntityQuery getSubjects;
    23.     protected override void OnCreate()
    24.     {
    25.         base.OnCreate();
    26.  
    27.         getSubjects = GetEntityQuery(ComponentType.ReadOnly<Translation>(), ComponentType.ReadOnly<Rotation>(), ComponentType.ReadOnly<PhysicsMass>());
    28.     }
    29.  
    30.     protected override void OnStartRunning()
    31.     {
    32.         base.OnStartRunning();
    33.     }
    34.  
    35.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    36.     {
    37.         float _dt = Time.DeltaTime;
    38.  
    39.  
    40.         NativeArray<ArchetypeChunk> subjects = getSubjects.CreateArchetypeChunkArray(Allocator.TempJob);
    41.         ArchetypeChunkComponentType<Translation> positionData = GetArchetypeChunkComponentType<Translation>();
    42.         ArchetypeChunkComponentType<Rotation> rotationData = GetArchetypeChunkComponentType<Rotation>();
    43.         ArchetypeChunkComponentType<PhysicsMass> massData = GetArchetypeChunkComponentType<PhysicsMass>();
    44.         ArchetypeChunkEntityType entityData = GetArchetypeChunkEntityType();
    45.  
    46.         PhysicsWorld world = World.DefaultGameObjectInjectionWorld.GetExistingSystem<BuildPhysicsWorld>().PhysicsWorld;
    47.  
    48.  
    49.         gravityHandle = Entities.ForEach((ref Translation position, ref Rotation rotation, ref PhysicsMass mass) =>
    50.         {
    51.             if ((1.0f / mass.InverseMass) > 1e+17f)
    52.             {
    53.                 return;
    54.             }
    55.             else
    56.             {
    57.                 NativeArray<Translation> subjectPositions = new NativeArray<Translation>();
    58.                 NativeArray<Rotation> subjectRotations = new NativeArray<Rotation>();
    59.                 NativeArray<PhysicsMass> subjectMasses = new NativeArray<PhysicsMass>();
    60.                 NativeArray<Entity> entities = new NativeArray<Entity>();
    61.  
    62.                 for (int subjctChunkArrayIndex = 0; subjctChunkArrayIndex < subjects.Length; subjctChunkArrayIndex++)
    63.                 {
    64.                     if (subjectPositions.IsCreated)
    65.                     {
    66.                         subjectPositions.Dispose();
    67.                     }
    68.                     if (subjectRotations.IsCreated)
    69.                     {
    70.                         subjectRotations.Dispose();
    71.                     }
    72.                     if (subjectMasses.IsCreated)
    73.                     {
    74.                         subjectMasses.Dispose();
    75.                     }
    76.                     if (entities.IsCreated)
    77.                     {
    78.                         entities.Dispose();
    79.                     }
    80.                     subjectPositions = subjects[subjctChunkArrayIndex].GetNativeArray<Translation>(positionData);
    81.                     subjectRotations = subjects[subjctChunkArrayIndex].GetNativeArray<Rotation>(rotationData);
    82.                     subjectMasses = subjects[subjctChunkArrayIndex].GetNativeArray<PhysicsMass>(massData);
    83.                     entities = subjects[subjctChunkArrayIndex].GetNativeArray(entityData);
    84.  
    85.                     for (int subjectChunkIndex = 0; subjectChunkIndex < subjects[subjctChunkArrayIndex].Count; subjectChunkIndex++)
    86.                     {
    87.                         float3 vectorFromTo = position.Value - subjectPositions[subjectChunkIndex].Value;
    88.                         float distance = math.length(vectorFromTo);
    89.                         float distaneSq = math.pow(distance, 2);
    90.                         float emitterMass = 1.0f / mass.InverseMass;
    91.                         float subjectMass = 1.0f / subjectMasses[subjectChunkIndex].InverseMass;
    92.                         float gravityForce = (emitterMass * subjectMass) / distaneSq;
    93.  
    94.                         if (gravityForce < 0.05f)
    95.                         {
    96.                             continue;
    97.                         }
    98.                         else
    99.                         {
    100.                             int thisRigidBody = world.GetRigidBodyIndex(entities[subjectChunkIndex]);
    101.                             int thisCenterOfMass = world.GetRigidBodyIndex(entities[subjectChunkIndex]);
    102.                             float3 calcGravity = (vectorFromTo / distance) * gravityForce;
    103.                             world.ApplyImpulse(thisRigidBody, calcGravity, thisCenterOfMass);
    104.                         }
    105.                     }
    106.                 }
    107.                 if (subjectPositions.IsCreated)
    108.                 {
    109.                     subjectPositions.Dispose();
    110.                 }
    111.                 if (subjectRotations.IsCreated)
    112.                 {
    113.                     subjectRotations.Dispose();
    114.                 }
    115.                 if (subjectMasses.IsCreated)
    116.                 {
    117.                     subjectMasses.Dispose();
    118.                 }
    119.                 if (entities.IsCreated)
    120.                 {
    121.                     entities.Dispose();
    122.                 }
    123.  
    124.             }
    125.         }).Schedule(inputDeps);
    126.  
    127.         inputDeps = JobHandle.CombineDependencies(gravityHandle, inputDeps);
    128.         return inputDeps;
    129.     }
    130.     //ApplyGravityJob gravityJob;
    131.     JobHandle gravityHandle;
    132.  
    133.     //protected struct ApplyGravityJob : IJobChunk
    134.     //{
    135.     //    [ReadOnly] public float dt;
    136.     //    [ReadOnly] public ArchetypeChunk subjectChunk;
    137.     //
    138.     //    [ReadOnly] public ArchetypeChunkComponentType<Translation> positionChunkType;
    139.     //    [ReadOnly] public ArchetypeChunkComponentType<Rotation> rotationChunkType;
    140.     //    [ReadOnly] public ArchetypeChunkComponentType<SphericalGravityEmitter> emitterChunkType;
    141.     //    [ReadOnly] public ArchetypeChunkEntityType entityChunkType;
    142.     //
    143.     //    public void Execute(ArchetypeChunk emitterChunk, int chunkIndex, int firstEntityIndex)
    144.     //    {
    145.     //        NativeArray<Translation> subjectPositions = subjectChunk.GetNativeArray(positionChunkType);
    146.     //        NativeArray<Rotation> subjectRotations = subjectChunk.GetNativeArray(rotationChunkType);
    147.     //      
    148.     //        NativeArray<Translation> emitterPositions = emitterChunk.GetNativeArray(positionChunkType);
    149.     //        NativeArray<Rotation> emitterRotations = emitterChunk.GetNativeArray(rotationChunkType);
    150.     //
    151.     //        for (int e = 0; e < emitterChunk.Count; e++)
    152.     //            for (int s = 0; s < subjectChunk.Count; s++)
    153.     //            {
    154.     //
    155.     //                float3 direction = subjectPositions[s].Value - emitterPositions[e].Value;
    156.     //                float distance = math.length(direction);
    157.     //
    158.     //                if (distance > emitterData[e].radius) return;
    159.     //                else
    160.     //                {
    161.     //                    NativeArray<Entity> subjects = subjectChunk.GetNativeArray(entityChunkType);
    162.     //                    NativeArray<Entity> emitters = emitterChunk.GetNativeArray(entityChunkType);
    163.     //                    PhysicsWorld world = World.DefaultGameObjectInjectionWorld.GetExistingSystem<BuildPhysicsWorld>().PhysicsWorld;
    164.     //
    165.     //                    int emitterRigidBody = world.GetRigidBodyIndex(emitters[e]);
    166.     //                    int thisRigidBody = world.GetRigidBodyIndex(subjects[s]);
    167.     //
    168.     //                    float3 thisCenterOfMass = PhysicsWorldExtensions.GetCenterOfMass(world, thisRigidBody);
    169.     //                    float thisMass = PhysicsWorldExtensions.GetMass(world, thisRigidBody);
    170.     //
    171.     //                    float emitterMass = PhysicsWorldExtensions.GetMass(world, emitterRigidBody);
    172.     //
    173.     //                    float3 unitDirection = direction / distance;
    174.     //                    float3 calcGravity = unitDirection * ((emitterMass * thisMass) / math.pow(distance, 2)) * dt;
    175.     //
    176.     //                    if (math.length(calcGravity) < 0.05) calcGravity = float3.zero;
    177.     //
    178.     //                    world.ApplyImpulse(thisRigidBody, calcGravity, thisCenterOfMass);
    179.     //
    180.     //                    subjects.Dispose();
    181.     //                    emitters.Dispose();
    182.     //                }
    183.     //
    184.     //        }
    185.     //        subjectPositions.Dispose();
    186.     //        subjectRotations.Dispose();
    187.     //        emitterPositions.Dispose();
    188.     //        emitterRotations.Dispose();
    189.     //        emitterData.Dispose();
    190.     //    }
    191.     //}
    192.  
    193.     protected override void OnStopRunning()
    194.     {
    195.         base.OnStopRunning();
    196.     }
    197.     protected override void OnDestroy()
    198.     {
    199.         base.OnDestroy();
    200.     }
    201.  
    202. }
    203.