Search Unity

Question Physics World in Collision Job broken in 0.3.1

Discussion in 'Physics for ECS' started by zardini123, Mar 22, 2020.

  1. zardini123

    zardini123

    Joined:
    Jan 5, 2013
    Posts:
    68
    Before updating to 0.3.1, I was able to pass the PhysicsWorld as user data to ICollisionEventsJob. The method of passing the PhysicsWorld into the job is identical to that of a previous post of mine regarding PhysicsWorld passing efficiency. I will echo my code at the bottom of this post.

    Now with Unity Physics 0.3.1, passing PhysicsWorld (read and write) to the job results in an "duplicate data" error:

    InvalidOperationException: The writable NativeArray WheelCollisionJob.UserJobData.world.CollisionWorld.m_Bodies is the same NativeArray as WheelCollisionJob.EventReader.m_Bodies, two NativeArrays may not be the same (aliasing).

    This error did not appear before updating. I'm even more confused now how I am supposed to read/write the world from the collision job especially that EventReader is not accessible from the job Execute function.

    Code:
    Code (CSharp):
    1. [UpdateAfter(typeof(BuildPhysicsWorld)), UpdateBefore(typeof(StepPhysicsWorld))]
    2. unsafe public class ForceOnCollisionSystem : JobComponentSystem
    3. {
    4.   protected override void OnCreate()
    5.   {
    6.     // Get related physics systems here...
    7.   }
    8.   [BurstCompile]
    9.   struct ForceOnCollisionJob : ICollisionEventsJob
    10.   {
    11.     // TODO: REVIEW:  Is passing the entirety of world into a job a extremely poor memory choice?
    12.     public PhysicsWorld world;
    13.     [ReadOnly] public float timeDelta;
    14.     public void Execute(CollisionEvent collisionEvent)
    15.     {
    16.       // Find out what entities are what using collisionEvent
    17.       // Find rigid body associated with a collision entity "wheel"
    18.       int rigidBodyIndex = world.GetRigidBodyIndex(wheel);
    19.       // Math and stuff blah blah blah...
    20.       world.ApplyImpulse(rigidBodyIndex, finalImpulse, details.AverageContactPointPosition);
    21.     }
    22.   }
    23.   protected override JobHandle OnUpdate(JobHandle inputDeps)
    24.   {
    25.     PhysicsWorld world = m_BuildPhysicsWorldSystem.PhysicsWorld;
    26.     // These dependencies are needed due to usage of PhysicsWorld
    27.     inputDeps = JobHandle.CombineDependencies(inputDeps, m_BuildPhysicsWorldSystem.FinalJobHandle);
    28.     JobHandle jobHandle = new ForceOnCollisionJob
    29.     {
    30.       world = world,
    31.       timeDelta = Time.fixedDeltaTime
    32.     }.Schedule(m_StepPhysicsWorldSystem.Simulation, ref world, inputDeps);
    33.  
    34.     return jobHandle;
    35.   }
    36. }
     
    Last edited: Mar 22, 2020
  2. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Thanks for reporting this! I'll take a look and update you with my findings.

    In the meantime, I'd advise you to take a look at ComponentExtensions.cs, they don't need PhysicsWorld and can effectively produce the same result.
     
  3. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    You can disable this error by adding [NativeDisableContainerSafetyRestriction] on CollisionEvents.m_Bodies member. It is safe to do so as the job only reads entities from this buffer, and your collision job applies forces, so they are not interested in the same data.

    We plan to refactor this a bit in the future, I'm just not sure about the timelines, so I hope this workaround will do the trick for you in the meantime. Let me know if you have any more questions!
     
  4. elJoel

    elJoel

    Joined:
    Sep 7, 2016
    Posts:
    125
    I am trying to do this within a ICollisionEventsJob:
    Code (CSharp):
    1.          
    2. PhysicsWorld.CollisionWorld.CalculateDistance(
    3.                 new PointDistanceInput
    4.                 {
    5.                     Position = translation.Value,
    6.                     MaxDistance = catapult.ExplosionRadius * radiusAmpifier,
    7.                     Filter = new CollisionFilter
    8.                     {
    9.                         BelongsTo = (uint) catapult.LayerMask.value,
    10.                         CollidesWith = (uint) catapult.LayerMask.value
    11.                     }
    12.                 },
    13.                 ref distanceHits
    14.             );
    15.  
    Can I do the same with ComponentExtensions.cs?

    How do I go about doing this?

    EDIT:

    Nevermind I got it to work, I was adding [NativeDisableContainerSafetyRestriction] to the wrong member inside CollisionEvents.
     
    Last edited: Mar 28, 2020
    petarmHavok likes this.
  5. zardini123

    zardini123

    Joined:
    Jan 5, 2013
    Posts:
    68
    @petarmHavok I know adding the attribute like this:
    Code (CSharp):
    1. [NativeDisableContainerSafetyRestriction] public PhysicsWorld world;
    in the ICollisionEventsJob results in all the related members to the PhysicsWorld to not have the safety restriction. That seems extremely risky. How can you apply [NativeDisableContainerSafetyRestriction] to only the m_Bodies member of my PhysicsWorld world, and not any other member?

    Also doing this does not fix the issue. I still get spammed with the identical error.
     
    Last edited: Mar 30, 2020
  6. elJoel

    elJoel

    Joined:
    Sep 7, 2016
    Posts:
    125
    Just go into the CollisionEvents struct, it's accessible and add it to the m_Bodies member there. Oh and you have to change it again everytime you load the project...
     
  7. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    What @elJoel said above, just add the attribute to CollisionEvents.m_Bodies. That's safe.

    We are working on a proper fix for this, hopefully we will release it soon.
     
  8. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    You don't if you move package from Library/PackageCache to Packages folder.
     
    elJoel likes this.
  9. zardini123

    zardini123

    Joined:
    Jan 5, 2013
    Posts:
    68
    Thats neat, I didn't know that was how you could make changes to packages be persistent!

    I'm excited to see the fix! Currently I'm just going to down-port to Unity Physics 0.2.5 so I don't have to deal with package manipulation at the moment.
     
  10. zardini123

    zardini123

    Joined:
    Jan 5, 2013
    Posts:
    68
    I've upgraded to Unity Physics 0.3.2, and I see there hasn't been a fix yet. I need the most recent version, so I moved the package to Packages instead of Library/PackageCache, and added [NativeDisableContainerSafetyRestriction] before the member CollisionEvents.m_Bodies. Though, this doesn't fix the error.

    The error is coming from WheelCollisionJob.EventReader.m_Bodies, which is indeed the m_Bodies member in CollisionEvents. @petarmHavok is there something I'm doing wrong?
     
  11. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Yeah sorry, the fix didn't make it to 0.3.2, but it's in master, so expect it in the next release, which should be in the order of weeks away. :)
     
  12. elJoel

    elJoel

    Joined:
    Sep 7, 2016
    Posts:
    125
    In CollisionEvent there are two members called m_Bodies, make sure to add it to the correct one. (Not the one in the Enumerator struct.)
     
  13. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    int rigidBodyIndex = world.GetRigidBodyIndex(wheel);
    also accesses the Bodies array. The CollisionEvent already has the BodyIndex and Entity of each body in the collision so you shouldn't need to call GetRigidBodyIndex at all.
     
  14. zardini123

    zardini123

    Joined:
    Jan 5, 2013
    Posts:
    68
    Actually I found out why it wasn't working for me. It is because I'm using Havok Physics, and it uses a separate struct for its collision events. I put [NativeDisableContainerSafetyRestriction] before m_bodies in HavokCollisionEvents.cs (in the Havok package) instead in CollisionEvents.cs (in the Unity Physics package), which fixes the issue.

    Thats true, but the issue here is passing PhysicsWorld into the CollisionEventsJob. I need the world for collisionEvent.CalculateDetails. Is there a way to get the world from the ICollisionEventsJob? Or should I just keep passing in the PhysicsWorld?