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

ICollisionEventsJob slow

Discussion in 'Physics for ECS' started by argibaltzi, Jun 7, 2020.

  1. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    220
    Hi
    I have a scene with lots of objects and trying to get some collision between specific objects but its very slow....
    it takes like 40% of the proccessing for doing nothing

    If i remove the jobHandle.Complete(); which some samples seem to do so i get dependency error when it runs
    Code (CSharp):
    1. InvalidOperationException: The previously scheduled job ExplosivesCollisionSystem:DetectCollisionsSystemJob reads from the NativeArray DetectCollisionsSystemJob.EventReader.m_InputVelocities. You are trying to schedule a new job Solver:ParallelApplyGravityAndCopyInputVelocitiesJob, which writes to the same NativeArray (via ParallelApplyGravityAndCopyInputVelocitiesJob.InputVelocities). To guarantee safety, you must include ExplosivesCollisionSystem:DetectCollisionsSystemJob as a dependency of the newly scheduled job.
    Code (CSharp):
    1. [UpdateAfter(typeof(EndFramePhysicsSystem))]
    2. public class ExplosivesCollisionSystem : JobComponentSystem
    3. {
    4.     private BuildPhysicsWorld buildPhysicsWorld;
    5.     private StepPhysicsWorld stepPhysicsWorld;
    6.  
    7.     protected override void OnCreate()
    8.     {
    9.         base.OnCreate();
    10.         buildPhysicsWorld = World.GetOrCreateSystem<BuildPhysicsWorld>();
    11.         stepPhysicsWorld = World.GetOrCreateSystem<StepPhysicsWorld>();
    12.     }
    13.  
    14.     [BurstCompile]
    15.     struct DetectCollisionsSystemJob : ICollisionEventsJob
    16.     {
    17.         public ComponentDataFromEntity<ExplosivesComponent> explosivesGroup;
    18.         [ReadOnly] public ComponentDataFromEntity<BlockComponent> blocksGroup;
    19.  
    20.         public void Execute(CollisionEvent collisionEvent)
    21.         {
    22.             Entity entityA = collisionEvent.Entities.EntityA;
    23.             Entity entityB = collisionEvent.Entities.EntityB;
    24.  
    25.             bool isBlockA = blocksGroup.Exists(entityA);
    26.             bool isExplosivesA = explosivesGroup.Exists(entityA);
    27.             bool isBlockB = blocksGroup.Exists(entityB);
    28.             bool isExplosivesB = explosivesGroup.Exists(entityB);
    29.  
    30.             if (isExplosivesA && isBlockB)
    31.             {
    32.                 ExplosivesComponent modifiedData = explosivesGroup[entityA];
    33.                 if (!modifiedData.DetectedCollision)
    34.                 {
    35.                     modifiedData.DetectedCollision = true;
    36.                     explosivesGroup[entityA] = modifiedData;
    37.                 }
    38.             }
    39.  
    40.             if (isBlockA && isExplosivesB)
    41.             {
    42.                 ExplosivesComponent modifiedData = explosivesGroup[entityB];
    43.                 if (!modifiedData.DetectedCollision)
    44.                 {
    45.                     modifiedData.DetectedCollision = true;
    46.                     explosivesGroup[entityB] = modifiedData;
    47.                 }
    48.             }
    49.         }
    50.     }
    51.  
    52.     protected override JobHandle OnUpdate(JobHandle inputDependencies)
    53.     {
    54.         JobHandle jobHandle = new DetectCollisionsSystemJob
    55.         {
    56.             explosivesGroup = GetComponentDataFromEntity<ExplosivesComponent>(false),
    57.             blocksGroup = GetComponentDataFromEntity<BlockComponent>(true),
    58.  
    59.         }.Schedule(stepPhysicsWorld.Simulation, ref buildPhysicsWorld.PhysicsWorld, inputDependencies);
    60.  
    61.         jobHandle.Complete();
    62.  
    63.         return jobHandle;
    64.     }
    65. }
     
  2. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    If you are scheduling something after EndFramePhysicsSystem, there's no guarantee that it would finish before BuildPhysicsWorld of the next frame. Now, you never really need to schedule it after this system, instead, schedule it after ExportPhysicsWorld and before EndFramePhysicsSystem, and also add the job handle of your job to HandlesToWaitFor list of the EndFramePhysicsSystem.

    In the next release we will add the ability to define your job handle as a dependency of any of the physics systems, so at that point you could schedule stuff after EndFramePhysicsSystem and before the next BuildPhysicsWorld. Let me know if this works in the meantime!

    That's regarding the scheduling. Now back to it being slow. Can you share more context on that? What's the scene, how slow is it, what's the setup?
     
    argibaltzi likes this.
  3. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    220
    It seems the problem is the [UpdateAfter(typeof(EndFramePhysicsSystem))],
    i saw it in some tutorial somewhere.... there is a lot of wrong code out there apparently....

    i changed to
    [UpdateBefore(typeof(EndFramePhysicsSystem))]

    the collision now takes almost no cpu time like it should

    Thanks!!
     
  4. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Make sure to add UpdateAfter(typeof(ExportPhysicsWorld)) so that it triggers at the exact point. Glad it helped!
     
  5. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    220
    when i add UpdateAfter(typeof(ExportPhysicsWorld)) it makes it slow again but not as slow as before, not sure why
    i see like 20% cpu usage there

    the only time where it goes down to 1-2% is if i have [UpdateBefore(typeof(EndFramePhysicsSystem))] only
     
  6. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    That is a bit strange. Are you getting correct results? If you only update before the end, it can run any time, including before the step where there are no events at all. So I'd investigate more if this thing is working correctly with that code. You ca also try update after StepPhysicsWorld, it's safe immediately after step, no need to wait for export.
     
  7. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    220
    with
    [UpdateAfter(typeof(StepPhysicsWorld))]
    11% is spent on WaitForJobGroupId and under it with 7.8% is havoksimulation:stepjob

    the big problem is this line
    jobHandle.Complete();

    this doesn't make things very parallel.... which is the whole point
    i think the reason it runs faster when i update before EndFramePhysicsSystem is because the complete doesn't wait
     
    Last edited: Jun 13, 2020
  8. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    The HavokSimulation::StepJob is the actual physics simulation step, so that shouldn't count as cost of the collision events... And that's why events need to come after this, to get fresh events of the current step. So if you had update after ExportPhysicsWorld, and before EndFramePhysicsSystem (with HandlesToWaitFor), you most definitely don't need the jobHandle.Complete().
     
    argibaltzi likes this.