Search Unity

Upgrading to 0.5

Discussion in 'Physics for ECS' started by manpower13, Oct 13, 2020.

  1. manpower13

    manpower13

    Joined:
    Dec 22, 2013
    Posts:
    140
    Hi!

    I recently updated to Physics 0.5. I have various systems that perform raycasts, or modify the velocity component of an entity.

    While the change to FixedStepSimulationSystemGroup makes sense, I can't fully figure out how to make my code work in 0.5.

    Adding
    Code (CSharp):
    1. [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
    to existing systems that have
    Code (CSharp):
    1. [UpdateAfter(typeof(BuildPhysicsWorld))]
    or
    Code (CSharp):
    1. [UpdateBefore(typeof(EndFramePhysicsSystem))]
    attributes does not solve all errors.

    I still get the following error:
    Code (CSharp):
    1. InvalidOperationException: The previously scheduled job Jobs:RecordDynamicBodyIntegrity reads from the ComponentTypeHandle<Unity.Physics.PhysicsVelocity> RecordDynamicBodyIntegrity.JobData.PhysicsVelocityType. You must call JobHandle.Complete() on the job Jobs:RecordDynamicBodyIntegrity, before you can write to the ComponentTypeHandle<Unity.Physics.PhysicsVelocity> safely.
    But I'm not sure where to start with this.
    The following error does mention my own code (MouseOverSystem, which does a raycast to detect where our mouse is currently hovering):
    Code (CSharp):
    1. InvalidOperationException: The previously scheduled job MouseOverSystem:MouseRayJob reads from the Unity.Collections.NativeArray`1[Unity.Physics.CollisionFilter] MouseRayJob.collisionWorld.Broadphase.m_StaticTree.BodyFilters. You are trying to schedule a new job Broadphase:PrepareStaticBodyDataJob, which writes to the same Unity.Collections.NativeArray`1[Unity.Physics.CollisionFilter] (via PrepareStaticBodyDataJob.FiltersOut). To guarantee safety, you must include MouseOverSystem:MouseRayJob as a dependency of the newly scheduled jo
    Disabling Burst also shows the following error afterwards:
    Code (CSharp):
    1. InvalidOperationException: Adding/removing components or changing position/rotation/velocity/collider ECS data on dynamic entities during physics step
    . This does not mention any system that is responsible for doing this.

    To reduce my confusion, maybe a few answers to the following questions might already help:
    - A job that does a simple raycast without changing the physics world (no velocity/physics component changes), should only add
    Code (CSharp):
    1. [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))][UpdateAfter(typeof(BuildPhysicsWorld))]
    and combine its dependency with
    Code (CSharp):
    1. _buildPhysicsWorld.GetOutputDependency()
    ?
    - Should a job that does a raycast and changes velocity component do the same?
    - Should a job that only changes velocity components also be part of the
    Code (CSharp):
    1. [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
    ? Or does it not need this?

    Thank you very much! Let me know if my question is unclear!
     
  2. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Modifying any components on an entity is allowed only before BuildPhysicsWorld or after ExportPhysicsWorld. Keep in mind that sometimes UpdateBefore and UpdateAfter is not enough, but also add AddInputDependency() to next system and incorporate GetOutputDependency() from previous system.

    Now your raycast is a specific example. It is correct it can run any time after BuildPhysicsWorld (and also use its GetOutputDependency()). But you also need to make sure it finishes before end of frame, and I think easiest is to schedule it before EndFramePhysicsSystem. If it changes simulation stuff, then schedule it before StepPhysicsWorld. Again, in this job you are not allowed to change component data, since it is after the BuildPhysicsWorld system.

    Let me know if this makes things a bit clearer!
     
    manpower13 likes this.
  3. manpower13

    manpower13

    Joined:
    Dec 22, 2013
    Posts:
    140
    Thanks for the useful information!

    When you say 'in this job you are not allowed to change component data', does that refer to 'physics' components? Or all components?

    If I have my MouseOverSystem, which uses the following job:
    Code (CSharp):
    1. [BurstCompile]
    2.     private struct MouseRayJob : IJob
    3.     {
    4.         [ReadOnly] public CollisionWorld collisionWorld;
    5.         public RaycastInput raycastInput;
    6.         public EntityCommandBuffer.ParallelWriter entityCommandBuffer;
    7.         [ReadOnly] public ComponentDataFromEntity<MouseOverTarget> mouseOverTargetData;
    8.        
    9.         public void Execute()
    10.         {
    11.             if (collisionWorld.NumBodies <= 0)
    12.             {
    13.                 return;
    14.             }
    15.             NativeList<RaycastHit> hits = new NativeList<RaycastHit>(Allocator.Temp);
    16.             AllHitsCollector<RaycastHit> allHitsCollector = new AllHitsCollector<RaycastHit>(1, ref hits);
    17.             if (collisionWorld.CastRay(raycastInput, ref allHitsCollector))
    18.             {
    19.                 // We hit something!
    20.                 // Sort based on distance.
    21.                 hits.Sort(new RaycastHitComparer());
    22.                
    23.                 for (int i = 0; i < hits.Length; i++)
    24.                 {
    25.                     Entity hitEntity = collisionWorld.Bodies[hits[i].RigidBodyIndex].Entity;
    26.                     if (mouseOverTargetData.HasComponent(hitEntity))
    27.                     {
    28.                         entityCommandBuffer.AddComponent<MouseOver>(1, hitEntity);
    29.                         break;
    30.                     }
    31.                 }
    32.             }
    33.             hits.Dispose();
    34.         }
    35.     }
    We can see that we are running a CastRay on the collision world, so it should be after BuildPhysicsWorld. However, it also adds a component, so should it run after ExportPhysicsWorld?

    I've tried multiple things, but cannot seem to run it without errors:
    • Use
      [UpdateBefore(typeof(BuildPhysicsWorld))]
      and call
      _buildPhysicsWorld.AddInputDependency(inputDeps);
      . This results in
      Code (CSharp):
      1. InvalidOperationException: The previously scheduled job MouseOverSystem:MouseRayJob reads from the Unity.Collections.NativeArray`1[Unity.Physics.RigidBody] MouseRayJob.collisionWorld.m_Bodies. You must call JobHandle.Complete() on the job MouseOverSystem:MouseRayJob, before you can deallocate the Unity.Collections.NativeArray`1[Unity.Physics.RigidBody] safely.
    • Use
      [UpdateAfter(typeof(ExportPhysicsWorld))]
      and call
      JobHandle.CombineDependencies(inputDeps, _buildPhysicsWorld.GetOutputDependency())

    Other combinations don't work (but those make sense).
     
  4. manpower13

    manpower13

    Joined:
    Dec 22, 2013
    Posts:
    140
    The strange thing to me is the fact that my code worked before updating to 0.5. If the only change made is the fact that systems moved to a different group, why does simply adding
    [UpdateInGroup((FixedStepSimulationSystemGroup))]
    to those systems not fix it?

    Before updating, I used the following attributes:
    Code (CSharp):
    1. [UpdateAfter(typeof(BuildPhysicsWorld)), UpdateBefore(typeof(EndFramePhysicsSystem))]
    and used
    _buildPhysicsWorld.GetOutputDependency()
     
    Last edited: Oct 14, 2020
  5. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Ok so looking back at your errors, I noticed you are missing EndFramePhysicsSystem.AddInputDependency(mouseJob) for sure to make sure it gets finished before next BuildPhysicsWorld.

    Furthermore, our integrity checks system did catch your job doing stuff with component data on physics entities. That's the error "Adding/removing components..." you are seeing. Unfortunately, adding/removing components can reorder entities, but Export system needs to have them in the same order as Build.
     
    manpower13 likes this.
  6. cultureulterior

    cultureulterior

    Joined:
    Mar 15, 2015
    Posts:
    68
    @petarmHavok but those changes look like they are via EntityCommandBuffer- are you saying that no changes that happen, even via ECB can be done during that time? Isn't this what ECBs are for, to delay changes to after data is used? Or is this dependent on which EntityCommandBufferSystem you are using? Which ones can we use?

    Personally I'm generally using EndSimulation (except for deletes)...

    I'm going to be upgrading to 0.5.0 soon as well and having UI raytracing only run during FixedStepSimulationSystemGroup seems like a problem...
     
  7. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    No changes that can cause the reorder of entities in chunks can happen. I know it's a bit vague, but it's the best I can give at this point.

    Regarding ray tracing, it's perfectly fine not to have it in FixedStepSimulationSystemGroup, you can have it before or after it, this is mostly for cases where you need a system to run in between physics systems.
     
  8. manpower13

    manpower13

    Joined:
    Dec 22, 2013
    Posts:
    140
    @petarmHavok Thanks! That helped a lot.
    Even though it still feels a little vague, it makes more sense now :)

    I moved my MouseOver system to after the
    FixedStepSimulationSystemGroup
    .
     
  9. cultureulterior

    cultureulterior

    Joined:
    Mar 15, 2015
    Posts:
    68
    @manpower13 how does your dependency structure look like now?
     
  10. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    I'm here to explain further the stuff that is vague. :) Just ask.
     
  11. manpower13

    manpower13

    Joined:
    Dec 22, 2013
    Posts:
    140
    My MouseOverSystem is responsible of doing a raycast and adding a MouseOver component to those that entities that are currently being hovered.
    Since this uses raycasts, I want it to run after the physics world is done building. I used
    [UpdateAfter((typeof(FixedStepSimulationSystemGroup)))]
    for the MouseOverSystem. MouseOver components are added using an EntityCommandBuffer. (After writing this, I tested whether adding a Dependency on the
    _buildPhysicsWorld.GetOutputDependency()
    would also work instead of using
    UpdateAfter
    ; that's the case. Both options work).

    I've used the same solutions for other Systems that are doing raycasts. Next to this, I converted all my systems to SystemBase. I don't know why, but it solved some of my dependency problems that you saw in my earlier errors.

    Hope this is what you meant with the dependency structure, otherwise let me know! Happy to clarify!

    Thanks! I was wondering, what kind of system would 'run in between physics systems'? Do you have an example for this? All raycasting jobs can run after, right?
    I was also wondering whether there is any preferred way of solving the dependency issue I had before?
    [UpdateAfter((typeof(FixedStepSimulationSystemGroup)))]
    vs combining Dependency with
    _buildPhysicsWorld.GetOutputDependency()
    ?
     
    cultureulterior likes this.
  12. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Well one example is a system you would plug in between StepPhysicsWorld and ExportPhysicsWorld. You could override results of the physics simulation before they are written back to the ECS data. For example, you could decide to zero out velocity of a body (for whatever reason). It's mostly around that, even for raycast jobs.

    Regarding dependencies, I think I'm becoming boring with repeating this, but:
    1. Make sure you have a proper simulation group
    2. Make sure you have UpdateBefore and UpdateAfter
    3. Make sure you link to the GetOutputDependency() of the last job of the previous system (the one in UpdateAfter) and also AddInputDependency() to the first job in the next system (UpdateBefore).

    And that's about it, always have this and you are good to go. If you don't have the "next" system in your logic, you should always link to the EndFramePhysicsSystem.