Search Unity

Can I get collision events when using Simulation.StepImmediate?

Discussion in 'Physics for ECS' started by Bas-Smit, Feb 24, 2021.

  1. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    To use Simulation.StepImmediate I need to provide a SimulationContext which I can simply create and Reset as needed. To schedule a ICollisionEventsJob I need to provide a Simulation which contains a SimulationContext, but it's internal and I can not Reset it through the Simulation. I'm assuming I need to set up another world with all the physics systems to receive collision events, or can this be made to work?
     
  2. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    You can, but you can't use ICollisionEventsJob, you need to do a foreach through the events in the context - foreach (CollisionEvent collisionEvent in simulationContext.CollisionEvents). That's what ICollisionEventsJob does anyway, so just wrap it in an IJob. :)
     
    Bas-Smit likes this.
  3. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    Cool, now all I need is a public version of ScheduleReset :D
     
  4. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    You can use
    public void Reset(SimulationStepInput stepInput)
    and generally should do it before each StepImmediate (to support changing number of bodies between steps).
     
  5. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    Yeah but that needs to run on the main thread, Im referring to the comment in Simulation.cs, line 90. Im already spending .3 ms on some very simple prediction
     
    Last edited: Feb 24, 2021
  6. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    @petarmHavok resetting is safe as long as the amount of bodies dont change right? I could just make ScheduleReset public?


    internal JobHandle ScheduleReset(SimulationStepInput, JobHandle, bool)


    Edit: well it runs but at 1.2 ms it is about 4 times slower :(
     
    Last edited: Feb 24, 2021
  7. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Rather than exposing ScheduleReset, I'd suggest creating a new public method ScheduleResetEventStreams that will schedule event data allocations and won't touch m_InputVelocities and m_SolverStabilizationMotionData. With that, you can do everything in jobs, but of course need to make sure they depend on each other (reset->step->read event streams) and number of bodies doesn't change.

    We'll definitely look into improving this, so people can do full reset in jobs. Thanks for the feedback!
     
    Bas-Smit likes this.
  8. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Hi @Bas-Smit , I think that you can even support varying number of bodies with ScheduleReset, but only in StepImmediate case. To be safe, you can create a new method (ScheduleReset2) that schedules all native array disposals and allocations (including m_InputVelocities and m_SolverStabilizationMotionData) and returns a combined job handle. Then pass that handle as input dep to the job that will perform StepImmediate.
     
    Bas-Smit likes this.
  9. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    thanks, because I have very few bodies this is what I am seeing in the profiler once the scheduling is done
    upload_2021-2-25_18-56-34.png

    I'll try getting everything to happen in a single job, looks like that could be a lot more efficient?
     
    milos85miki likes this.
  10. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    If I understand correctly all I need to do, provided the number of bodies do not change, is resetting the event streams after stepping. Unfortunately the stream only exposes a job to do so. I also tried just diposing and allocating them again in the job, but I am not allowed to dispose of the streams created outside the job because of conflicting allocators :(
     
    Last edited: Feb 26, 2021
  11. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    :cool:

    upload_2021-2-26_13-4-47.png

    The key is to create a Reset method that can allocate using Temp allocator. After that you can create a ResetStreams method that Disposes of the streams and allocates new ones, also using Temp. Now stepping 2 bodies 30 frames runs at acceptable speed and can run on a background thread. Thanks @milos85miki

    SimulationContext:
    Code (csharp):
    1. public void Reset(SimulationStepInput stepInput, Allocator allocator = Allocator.Persistent)
    Code (csharp):
    1. public void ResetStreams()
    2. {
    3.     CollisionEventDataStream = new NativeStream(WorkItemCount[0], Allocator.Temp);
    4.     TriggerEventDataStream = new NativeStream(WorkItemCount[0], Allocator.Temp);
    5. }
    Job:
    Code (CSharp):
    1. public void Execute()
    2. {
    3.     var simulationContext = new SimulationContext();
    4.     simulationContext.Reset(StepInput, Allocator.Temp);
    5.  
    6.     for (int i = 0; i < Steps; i++)
    7.     {
    8.         // ...
    9.  
    10.         simulationContext.ResetStreams();
    11.     }
    12. }
    Shame it takes 6.5 ms on mono though :eek:

    EDIT: remove Dispose
     
    Last edited: Feb 26, 2021
  12. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Just be careful with event streams on Temp allocator, if you wanted to iterate through them on the next frame (not saying you do, just raising awareness), that memory will not be available.

    Also, you shouldn't need to dispose Temp memory, it will be done for you at the end of frame.
     
    Bas-Smit likes this.