Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Dynamic body velocities

Discussion in 'Physics for ECS' started by snacktime, Aug 11, 2020.

  1. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    So setting velocities in a system that runs between BuildPhysicsWorld and StepPhysicsWorld ends up with velocities being overwritten. Quick glance it looks like motion datas are setup in BuildPhysicsWorld and that's likely the issue. Is that the case or something else I'm missing?
     
  2. TRS6123

    TRS6123

    Joined:
    May 16, 2015
    Posts:
    246
    ExportPhysicsWorld is the system that writes back to the PhysicsVelocity components. You should set velocities either before BuildPhysicsWorld or after ExportPhysicsWorld.
     
  3. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    I don't think there is really a set way of doing things here. Both of your suggestions have pretty big caveats that might or might not matter depending on the game. Run your logic before BuildPhysicsWorld and any significant amount of work will stall the main thread. After export and you are now a frame behind. Throw in interpolation and two frames.

    Between build and step is better in several ways. BVH is up to date, BuildPhysicsWorld won't force complete your work, and it's before export so immediately visible to gamelogic later in simulation.
     
  4. romeo_ftv

    romeo_ftv

    Joined:
    Oct 20, 2009
    Posts:
    36
    Code (CSharp):
    1.  
    2. protected override void OnUpdate()
    3.         {
    4.             Dependency = JobHandle.CombineDependencies(m_BuildPhysicsWorldSystem.GetOutputDependency(), Dependency);
    5.  
    6.             float timeStep = Time.DeltaTime;
    7.  
    8.             Entities
    9.                 .WithAll<Car>()
    10.                 .ForEach((ref CarNative carNative) =>
    11.                 {
    12.                     Native.CX_ProcessCar(carNative.Value, timeStep, math.rcp(timeStep));
    13.                 })
    14.                 .ScheduleParallel();
    15.  
    16.             SimulationCallbacks.Callback applyImpulsesCallback = (ref ISimulation simulation, ref PhysicsWorld world, JobHandle inDeps) =>
    17.             {
    18.                 return new ApplyImpulsesJob
    19.                 {
    20.                     EntityType = GetEntityTypeHandle(),
    21.                     NativeCarType = GetComponentTypeHandle<CarNative>(true),
    22.                     World = world
    23.                 }
    24.                 .ScheduleParallel(m_CarsQuery, inDeps);
    25.             };
    26.  
    27.             m_StepPhysicsWorld.EnqueueCallback(SimulationCallbacks.Phase.PostSolveJacobians, applyImpulsesCallback, Dependency);
    28.         }
    29.  
    30.         [BurstCompile]
    31.         struct ApplyImpulsesJob : IJobChunk
    32.         {
    33.             [ReadOnly] public EntityTypeHandle EntityType;
    34.             [ReadOnly] public ComponentTypeHandle<CarNative> NativeCarType;
    35.             public PhysicsWorld World;
    36.  
    37.             public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
    38.             {
    39.                 var entities = chunk.GetNativeArray(EntityType);
    40.                 var chunkNativeCars = chunk.GetNativeArray(NativeCarType);
    41.  
    42.                 for (var i = 0; i < chunk.Count; i++)
    43.                 {
    44.                     Native.CX_CarGetTotals(chunkNativeCars[i].Value, out var linearImpulse, out var angularImpulse);
    45.  
    46.                     int rigidBodyIndex = World.GetRigidBodyIndex(entities[i]);
    47.  
    48.                     if (rigidBodyIndex != - 1 && rigidBodyIndex < World.NumDynamicBodies)
    49.                     {
    50.                         MotionData md = World.MotionDatas[rigidBodyIndex];
    51.                         float3 angularImpulseInertiaSpace = math.rotate(math.inverse(md.WorldFromMotion.rot), angularImpulse);
    52.  
    53.                         var motionVelocities = World.MotionVelocities;
    54.                         MotionVelocity mv = motionVelocities[rigidBodyIndex];
    55.                         mv.ApplyLinearImpulse(linearImpulse);
    56.                         mv.ApplyAngularImpulse(angularImpulseInertiaSpace);
    57.                         motionVelocities[rigidBodyIndex] = mv;
    58.                     }
    59.                 }
    60.             }
    61.         }
     
  5. romeo_ftv

    romeo_ftv

    Joined:
    Oct 20, 2009
    Posts:
    36
    but this method is not supported by hawok :(
     
  6. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    That makes me wonder if there is a reason to not just set the motion data before StepPhysicsWorld. That fits the actual flow I have better although the above would definitely work.
     
  7. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Yeah, Havok syncs the velocities after BuildPhysicsWorld and writes back to them as part of the StepPhysicsWorld (at the very end). So in post solve callback you can't really change motion velocities because that's not seen by Havok and it will be overwritten.

    There is a good reason for not touching motion data before step and after build - BVH is built with velocities in mind, changing them afterwards can result in contact pairs not being detected and tunneling/penetration. The correct place to change velocities is after step and before build. Unfortunately that's the full list of safe places at the moment.
     
    snacktime likes this.
  8. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Did not realize that good to know.
     
    petarmHavok likes this.