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

Unity Physics runs at diffrent speeds depending on editor game window size and if its a build

Discussion in 'Physics for ECS' started by Filtiarn_, Jan 6, 2020.

  1. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    Unity Physics runs at different speeds depending on
    -size of editor window (smaller window runs smaller)
    -Build runs about 5-75 percent faster than fullscreen in build.

    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Collections;
    3. using Unity.Entities;
    4. using Unity.Jobs;
    5. using Unity.Mathematics;
    6. using Unity.Transforms;
    7. using Unity.Physics;
    8. using UnityEngine;
    9.  
    10. namespace DOTSActor
    11. {
    12.     public class ActorMovementSystem : JobComponentSystem
    13.     {
    14.         //Player Input Variables
    15.         private PlayerInputActions playerInputActions;
    16.         private float3 playerMoveInput;
    17.         private bool bPlayerDoSprint;
    18.         private bool bPlayerDoJump;
    19.  
    20.         //Crete And Bind Player Actions
    21.         protected override void OnCreate()
    22.         {
    23.             //Create Player Input Actions
    24.             playerInputActions = new PlayerInputActions();
    25.             playerInputActions.Enable();
    26.  
    27.             //Bind Player Actions
    28.             playerInputActions.PlayerActionMap.Move.performed += ctx => playerMoveInput = new float3(ctx.ReadValue<Vector2>().x, 0, ctx.ReadValue<Vector2>().y);
    29.             playerInputActions.PlayerActionMap.Move.canceled += ctx => playerMoveInput = float3.zero;
    30.             playerInputActions.PlayerActionMap.Sprint.performed += ctx => bPlayerDoSprint = true;
    31.             playerInputActions.PlayerActionMap.Sprint.canceled += ctx => bPlayerDoSprint = false;
    32.             playerInputActions.PlayerActionMap.Jump.started += ctx => bPlayerDoJump = true;
    33.             playerInputActions.PlayerActionMap.Jump.canceled += ctx => bPlayerDoJump = false;
    34.         }
    35.  
    36.         //Disable Player Actions
    37.         protected override void OnDestroy()
    38.         {
    39.             playerInputActions.Disable();
    40.         }
    41.  
    42.         //Movement Job
    43.         [BurstCompile]
    44.         struct ActorMovementSystemJob : IJobForEach<Translation, Rotation, PhysicsVelocity, PhysicsMass, ActorActionMovementComponent>
    45.         {
    46.             public float deltaTime;
    47.             private float3 input;
    48.             private float3 originalVelocity;
    49.             private float3 newVelocity;
    50.             private float3 movementDirection;
    51.             private quaternion newRotation;
    52.  
    53.             public void Execute(ref Translation translation, ref Rotation rotation, ref PhysicsVelocity physicsVelocity, ref PhysicsMass physicsMass, ref ActorActionMovementComponent action)
    54.             {
    55.                 //Read Input Once | Clear Out Input
    56.                 input = action.moveInput;
    57.        
    58.                 //Update Sprint State
    59.                 {
    60.                     //Cancel Out Sprint If Input Is Zero
    61.                     if (input.x == 0 && input.z == 0)
    62.                         action.bDoSprint = false;
    63.                 }
    64.  
    65.                 //Jump
    66.                 {
    67.                     action.bDidJustStartJump = false;
    68.                     if (action.bDoJump && action.bIsGrounded)
    69.                     {
    70.                         physicsVelocity.Linear.y = action.jumpForce;
    71.                         action.bDidJustStartJump = true;
    72.                     }
    73.                 }
    74.        
    75.                 //Movement
    76.                 if (action.bIsGrounded && physicsVelocity.Linear.y <= 0.1f)
    77.                 {
    78.                     originalVelocity = physicsVelocity.Linear;
    79.                     newVelocity = originalVelocity;
    80.  
    81.                     //Read Movement Input
    82.                     newVelocity.x = input.x;
    83.                     newVelocity.z = input.z;
    84.  
    85.                     //Multiply Our Velocity By Our Movement Characters Speed
    86.                     newVelocity *= action.walkRunSpeed;
    87.                     if (action.bDoSprint)
    88.                         newVelocity = math.normalizesafe(newVelocity, float3.zero) * action.sprintSpeed;
    89.  
    90.                     //Apply Back Our Original Velocity Y
    91.                     newVelocity.y = originalVelocity.y;
    92.  
    93.                     //Set Linar Physics Velocity
    94.                     physicsVelocity.Linear = newVelocity;
    95.                 }
    96.  
    97.                 //Rotation
    98.                 if (action.bIsGrounded && physicsVelocity.Linear.y <= 0.1f)
    99.                 {
    100.                     //Rotate Twords Movement Direction
    101.                     if (input.x != 0 || input.z != 0)
    102.                     {
    103.                         movementDirection = math.normalize(input);
    104.                         movementDirection.y = 0;
    105.                         newRotation = quaternion.LookRotation(input, new float3(0, 1, 0));
    106.                         rotation.Value = math.nlerp(rotation.Value, newRotation, action.rotationSpeed * 10 * deltaTime);
    107.                     }
    108.  
    109.                     //Constrain Physics Rotation So We Don't Fall Over
    110.                     physicsMass.InverseInertia = float3.zero;
    111.                 }
    112.             }
    113.         }
    114.  
    115.         //Player Input Job
    116.         [BurstCompile]
    117.         [RequireComponentTag(typeof(ActorPlayerComponentTag))]
    118.         struct ActorMovementPlayerInputSystemJob : IJobForEach<ActorActionMovementComponent>
    119.         {
    120.             public float3 moveInput;
    121.             public float deltaTime;
    122.             public bool bDoSprint;
    123.             public bool bDoJump;
    124.  
    125.             public void Execute(ref ActorActionMovementComponent actionMovementComponent)
    126.             {
    127.                 //Set Inputs
    128.                 actionMovementComponent.moveInput = moveInput;
    129.                 actionMovementComponent.bDoSprint = bDoSprint;
    130.                 actionMovementComponent.bDoJump = bDoJump;
    131.             }
    132.         }
    133.  
    134.         //Create And Schedule Jobs
    135.         protected override JobHandle OnUpdate(JobHandle inputDependencies)
    136.         {
    137.             //Player Input Job
    138.             JobHandle inputJobHandle;
    139.             {
    140.                 //Get Camrea Vector Properties
    141.                 var cameraForward = (Camera.main.transform.TransformDirection(Vector3.forward).normalized);
    142.                 cameraForward.y = 0;
    143.                 var cameraRight = new Vector3(cameraForward.z, 0, -cameraForward.x);
    144.  
    145.                 //Normalize Camera Forward And Right
    146.                 cameraForward.Normalize();
    147.                 cameraRight.Normalize();
    148.  
    149.                 //Get New Input DONT CHANGE playerMoveInput HERE OR INPUT WONT WORK PROPERLY
    150.                 var newInput = playerMoveInput.x * cameraRight + playerMoveInput.z * cameraForward;
    151.  
    152.                 //Scheduale Job
    153.                 var playerInputJob = new ActorMovementPlayerInputSystemJob() { moveInput = newInput,deltaTime = Time.DeltaTime, bDoSprint = bPlayerDoSprint, bDoJump = bPlayerDoJump };
    154.                 inputJobHandle = playerInputJob.Schedule(this, inputDependencies);
    155.  
    156.                 //Cancel Jump Input
    157.                 bPlayerDoJump = false;
    158.             }
    159.  
    160.             //Movement Job
    161.             var movementJob = new ActorMovementSystemJob();
    162.             movementJob.deltaTime = Time.DeltaTime;
    163.             return movementJob.Schedule(this, inputJobHandle);
    164.         }
    165.     }
    166. }
     
  2. Flipps

    Flipps

    Joined:
    Jul 30, 2019
    Posts:
    51
    Maybe i am wrong but i think unity physics runs like this atm (please correct me if this is true).

    All physic systems are called with the framerate. Therefore if you have a higher framerate all objects are moving faster.

    The physic timestemp which is simulated (in one frame) is calculated in the BuildPhysicsWorld

    Code (CSharp):
    1. #if !UNITY_DOTSPLAYER
    2.                 float timeStep = UnityEngine.Time.fixedDeltaTime;
    3. #else
    4.                 float timeStep = Time.DeltaTime;
    5. #endif
    It uses the UnityEngine.Time.fixedDeltaTime by default.
    So the simulation depends on two things: framerate + fixedDeltaTime.

    If you want to have an independent simulation you have to multiple your Linear / Angular velocity by:

    velocity = yourVelocity * Time.Delta / UnityEngine.Time.fixedDeltaTime

    Again i am not really sure if this is correct but works for me.
     
  3. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    No good. Still has speed differences but its less.
     
  4. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
  5. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    So I found this workaround but Its still not working. I tried fixedDeltaTime and no deltaTime in movement as well.

    Code (CSharp):
    1. using Unity.Entities;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4.  
    5. namespace DOTSActor
    6. {
    7.  
    8.     public class FixedTimestepWorkaroundBehaviour : MonoBehaviour
    9.     {      
    10.         private ActorActionMovementSystem actorActionMovementSystem;
    11.         public float fixedDeltaTime = 0.01333f;
    12.  
    13.         void FixedUpdate()
    14.         {
    15.             if (actorActionMovementSystem == null)
    16.             {
    17.                 actorActionMovementSystem = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem<ActorActionMovementSystem>();
    18.             }
    19.  
    20.             Time.fixedDeltaTime = fixedDeltaTime;
    21.             actorActionMovementSystem.Enabled = true;
    22.             actorActionMovementSystem.Update();
    23.             actorActionMovementSystem.Enabled = false;
    24.         }
    25.     }
    26. }
    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Collections;
    3. using Unity.Entities;
    4. using Unity.Jobs;
    5. using Unity.Mathematics;
    6. using Unity.Transforms;
    7. using Unity.Physics;
    8. using UnityEngine;
    9.  
    10. namespace DOTSActor
    11. {
    12.     [DisableAutoCreation]
    13.     public class ActorActionMovementSystem : JobComponentSystem
    14.     {
    15.         //Job
    16.         [BurstCompile]
    17.         [RequireComponentTag(typeof(ActorGroundedComponentTag))]
    18.         struct ActorMovementSystemJob : IJobForEach<Rotation, LocalToWorld, PhysicsVelocity, PhysicsMass, ActorActionMovementComponent, ActorInputComponent>
    19.         {
    20.             //Time
    21.             public float deltaTime;
    22.  
    23.             //Input
    24.             private float3 input;
    25.             private float3 rawInput;
    26.  
    27.             //Movement
    28.             private float3 originalVelocity;
    29.             private float3 newVelocity;
    30.             private float movementDot;
    31.             private float movementRate;
    32.             private float movementMagnitude;
    33.  
    34.             //Rotation
    35.             private quaternion newRotation;
    36.             private float3 movementDirection;
    37.             private float targetSpeed;
    38.  
    39.             private float inputMagnitude;
    40.  
    41.             public void Execute(ref Rotation rotation, ref LocalToWorld localToWorld, ref PhysicsVelocity physicsVelocity, ref PhysicsMass physicsMass, ref ActorActionMovementComponent action, ref ActorInputComponent actorInputComponent)
    42.             {
    43.                 //Read Input Once | Clear Out Input
    44.                 if (!action.isPivoting)
    45.                 {
    46.                     input = action.moveInput = math.lerp(action.moveInput, actorInputComponent.moveInput, action.accleration * deltaTime);
    47.                     rawInput = actorInputComponent.moveInput;
    48.                     inputMagnitude = ((Vector3)input).magnitude;
    49.                 }
    50.  
    51.  
    52.                 originalVelocity = physicsVelocity.Linear;
    53.                 newVelocity = originalVelocity;
    54.  
    55.                 movementDot = math.dot(rawInput, localToWorld.Forward);
    56.                 movementRate = ((Vector3)originalVelocity).magnitude / action.walkRunSpeed;
    57.                 movementMagnitude = ((Vector3)originalVelocity).magnitude;
    58.  
    59.                 //Idle Walk Run Sprint
    60.                 {
    61.                     if (!action.isPivoting)
    62.                     {
    63.                         //Cancel Out Of Sprinting If We Are Not Going Fast Enough
    64.                         if (rawInput.x == 0 && rawInput.z == 0)
    65.                             actorInputComponent.doSpeedUp = false;
    66.  
    67.                         if (actorInputComponent.doSpeedUp)
    68.                             actorInputComponent.doCrouch = false;
    69.  
    70.                         targetSpeed = actorInputComponent.doSpeedUp ? action.sprintSpeed : action.walkRunSpeed;
    71.                         if (actorInputComponent.doCrouch)
    72.                             targetSpeed *= 0.5f;
    73.  
    74.                         var c = 0.0f;
    75.                         if (rawInput.x != 0 || rawInput.z != 0)
    76.  
    77.                             c = Vector3.Angle(rawInput, localToWorld.Forward);
    78.                         if (action.turnPenalty != 0 && c >= action.trunPenaltyAngleMin)
    79.                         {
    80.  
    81.                             targetSpeed -= c * action.turnPenalty * 0.001f;
    82.                             if (targetSpeed <= 0)
    83.                                 targetSpeed = 0;
    84.                         }
    85.  
    86.                         if (rawInput.x != 0 || rawInput.z != 0)
    87.                         {
    88.                             newVelocity = targetSpeed * input;
    89.                             newVelocity.y = originalVelocity.y;
    90.                             physicsVelocity.Linear = newVelocity;
    91.                         }
    92.                         else
    93.                         {
    94.                             newVelocity = math.lerp(originalVelocity, new float3(0,0,0), 15 * deltaTime);
    95.                             newVelocity.y = originalVelocity.y;
    96.                             physicsVelocity.Linear = newVelocity;
    97.                         }
    98.    
    99.                         if ((rawInput.x != 0 || rawInput.z != 0))
    100.                         {
    101.                             movementDirection = math.normalize(input);
    102.                             movementDirection.y = 0;
    103.                             newRotation = quaternion.LookRotation(input, new float3(0, 1, 0));
    104.                             rotation.Value = math.nlerp(rotation.Value, newRotation, (actorInputComponent.doSpeedUp ? action.sprintRotationSpeed : action.walkRunRotationSpeed) * 4 * deltaTime);
    105.                         }
    106.                     }
    107.                 }
    108.  
    109.  
    110.                 //Pivoting
    111.                 {
    112.                     action.pivotTime -= deltaTime;
    113.                     if (movementRate >= 0.5f && movementDot <= -0.75f && !action.isPivoting && action.pivotTime <= -0.3f)
    114.                     {
    115.                         action.isPivoting = true;
    116.                         action.pivotTime = 0.5f;
    117.                     }
    118.                     if (action.isPivoting && movementRate <= 0.2f && action.pivotTime <= 0)
    119.                     {
    120.                         action.isPivoting = false;
    121.                         action.pivotTime = 0;
    122.                     }
    123.                 }
    124.  
    125.                 //Jump
    126.                 {
    127.                     action.didJustJump = false;
    128.                     action.jumpInterval -= deltaTime;
    129.                     if (actorInputComponent.doJump && action.jumpInterval <= 0)
    130.                     {
    131.                         physicsVelocity.Linear.y = action.jumpForce;
    132.                         action.jumpInterval = 0.25f;
    133.                         action.didJustJump = true;
    134.  
    135.                         if (input.x != 0 || input.z != 0)
    136.                         {
    137.                             var direction = math.normalize(input);
    138.                             direction.y = 0;
    139.                             rotation.Value = quaternion.LookRotation(direction, new float3(0, 1, 0));
    140.                             action.pivotTime = 0;
    141.                         }
    142.                     }
    143.                 }
    144.  
    145.                 //Constrain Physics Rotation So We Don't Fall Over
    146.                 physicsMass.InverseInertia = float3.zero;
    147.             }
    148.         }
    149.  
    150.  
    151.         //Create And Schedule Jobs
    152.         protected override JobHandle OnUpdate(JobHandle inputDependencies)
    153.         {
    154.             //Movement Job
    155.             var movementJob = new ActorMovementSystemJob();
    156.             movementJob.deltaTime = Time.DeltaTime;
    157.             return movementJob.Schedule(this, inputDependencies);
    158.         }
    159.     }
    160. }
     
  6. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    I also tried the link steveeHavok sent me and that did not work eather.

    [UpdateBefore(typeof(Unity.Physics.Systems.BuildPhysicsWorld))]
    MyMovementSystem

    Code (CSharp):
    1. using Unity.Entities;
    2. using UnityEngine;
    3. using Unity.Physics.Systems;
    4.  
    5. [UpdateBefore(typeof(BuildPhysicsWorld))]
    6. public class PrePhysicsSetDeltaTimeSystem : ComponentSystem
    7. {
    8.     public bool isRealTimeStep = false;
    9.     public float timeScale = 1;
    10.     public float previousDeltaTime = UnityEngine.Time.fixedDeltaTime;
    11.  
    12.     protected override void OnUpdate()
    13.     {
    14.         previousDeltaTime = Time.fixedDeltaTime;
    15.  
    16.         if (isRealTimeStep)
    17.             UnityEngine.Time.fixedDeltaTime = Time.DeltaTime * timeScale;
    18.         else
    19.             UnityEngine.Time.fixedDeltaTime = Time.fixedDeltaTime * timeScale;
    20.     }
    21. }
    22.  
    23. [UpdateAfter(typeof(ExportPhysicsWorld))]
    24. public class PostPhysicsResetDeltaTimeSystem : ComponentSystem
    25. {
    26.     public PrePhysicsSetDeltaTimeSystem preSystem;
    27.  
    28.     protected override void OnCreate()
    29.     {
    30.         preSystem = World.Active.GetOrCreateSystem<PrePhysicsSetDeltaTimeSystem>();
    31.     }
    32.  
    33.     protected override void OnUpdate()
    34.     {
    35.         UnityEngine.Time.fixedDeltaTime = preSystem.previousDeltaTime;
    36.     }
    37. }
     
    Last edited: Jan 12, 2020
  7. apaxnid

    apaxnid

    Joined:
    Nov 18, 2012
    Posts:
    35
    1. Move SimulationSystemGroup to FixedUpdate Loop( copy WorldBootStrap.cs somewhere in assets folder )
    2. Create custom transofrm system(you read about overriding transofrm components hera https://docs.unity3d.com/Packages/c...tem.html#section-6-custom-transforms-advanced)
    3. Create some kind of interpolation system(something like in here https://www.kinematicsoup.com/news/2016/8/9/rrypp5tkubynjwxhxjzd42s3o034o8).
    This is my naive aproach, it kinda works and probably buggy as hell.So just wait until Unity guys will release their way to deal with this problem :) Just put IterpolatedEntityAuthoring script to object with Physics components you want to interpolate

    WorldBootStrap.cs
    Code (CSharp):
    1. using System.Reflection;
    2. using Unity.Entities;
    3. using UnityEngine;
    4. using UnityEngine.LowLevel;
    5. using UnityEngine.PlayerLoop;
    6.  
    7. public class WorldBootStrap : ICustomBootstrap
    8. {
    9.  
    10.     static MethodInfo insertManagerIntoSubsystemListMethod = typeof(ScriptBehaviourUpdateOrder).GetMethod("InsertManagerIntoSubsystemList", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
    11.  
    12.     public bool Initialize(string defaultWorldName)
    13.     {
    14.         Debug.Log("Executing World Bootstrap");
    15.         var world = new World("Custom World");
    16.         World.DefaultGameObjectInjectionWorld = world;
    17.         var systems = DefaultWorldInitialization.GetAllSystems(WorldSystemFilterFlags.Default);
    18.  
    19.         DefaultWorldInitialization.AddSystemsToRootLevelSystemGroups(world, systems);
    20.         UpdatePlayerLoop(world);
    21.         return true;
    22.     }
    23.  
    24.     public static void UpdatePlayerLoop(World world)
    25.     {
    26.         var playerLoop = PlayerLoop.GetDefaultPlayerLoop();
    27.         if (ScriptBehaviourUpdateOrder.CurrentPlayerLoop.subSystemList != null)
    28.             playerLoop = ScriptBehaviourUpdateOrder.CurrentPlayerLoop;
    29.         if (world != null)
    30.         {
    31.             for (var i = 0; i < playerLoop.subSystemList.Length; ++i)
    32.             {
    33.                 int subsystemListLength = playerLoop.subSystemList[i].subSystemList.Length;
    34.                 if (playerLoop.subSystemList[i].type == typeof(FixedUpdate))
    35.                 {
    36.                     var newSubsystemList = new PlayerLoopSystem[subsystemListLength + 1];
    37.                     for (var j = 0; j < subsystemListLength; ++j)
    38.                         newSubsystemList[j] = playerLoop.subSystemList[i].subSystemList[j];
    39.                     var mgr = world.GetOrCreateSystem<SimulationSystemGroup>();
    40.                     var genericMethod = insertManagerIntoSubsystemListMethod.MakeGenericMethod(mgr.GetType());
    41.                     genericMethod.Invoke(null, new object[] { newSubsystemList, subsystemListLength + 0, mgr });
    42.                     playerLoop.subSystemList[i].subSystemList = newSubsystemList;
    43.                 }
    44.                 else if (playerLoop.subSystemList[i].type == typeof(PreLateUpdate))
    45.                 {
    46.                     var newSubsystemList = new PlayerLoopSystem[subsystemListLength + 1];
    47.                     for (var j = 0; j < subsystemListLength; ++j)
    48.                         newSubsystemList[j] = playerLoop.subSystemList[i].subSystemList[j];
    49.                     var mgr = world.GetOrCreateSystem<PresentationSystemGroup>();
    50.                     var genericMethod = insertManagerIntoSubsystemListMethod.MakeGenericMethod(mgr.GetType());
    51.                     genericMethod.Invoke(null, new object[] { newSubsystemList, subsystemListLength + 0, mgr });
    52.                     playerLoop.subSystemList[i].subSystemList = newSubsystemList;
    53.                 }
    54.                 else if (playerLoop.subSystemList[i].type == typeof(Initialization))
    55.                 {
    56.                     var newSubsystemList = new PlayerLoopSystem[subsystemListLength + 1];
    57.                     for (var j = 0; j < subsystemListLength; ++j)
    58.                         newSubsystemList[j] = playerLoop.subSystemList[i].subSystemList[j];
    59.                     var mgr = world.GetOrCreateSystem<InitializationSystemGroup>();
    60.                     var genericMethod = insertManagerIntoSubsystemListMethod.MakeGenericMethod(mgr.GetType());
    61.                     genericMethod.Invoke(null, new object[] { newSubsystemList, subsystemListLength + 0, mgr });
    62.                     playerLoop.subSystemList[i].subSystemList = newSubsystemList;
    63.                 }
    64.             }
    65.         }
    66.  
    67.         ScriptBehaviourUpdateOrder.SetPlayerLoop(playerLoop);
    68.     }
    69. }
    IterpolatedEntityAuthoring.sc
    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Mathematics;
    3. using Unity.Transforms;
    4. using UnityEngine;
    5.  
    6. [WriteGroup(typeof(LocalToWorld))]
    7. public struct NewTimeIndex : IComponentData
    8. {
    9.     public int Value;
    10. }
    11.  
    12. [InternalBufferCapacity(2)]
    13. public struct LastFixedUpdatePositions :IBufferElementData
    14. {
    15.     public float3 Value;
    16. }
    17.  
    18. [InternalBufferCapacity(2)]
    19. public struct LastFixedUpdateRotations : IBufferElementData
    20. {
    21.     public quaternion Value;
    22. }
    23.  
    24. [InternalBufferCapacity(2)]
    25. public struct LastFixedUpdateTimes : IBufferElementData
    26. {
    27.     public float Value;
    28. }
    29.  
    30. public class IterpolatedEntityAuthoring : MonoBehaviour, IConvertGameObjectToEntity
    31. {
    32.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    33.     {
    34.         var bufferT = dstManager.AddBuffer<LastFixedUpdatePositions>(entity);
    35.         bufferT.Add(new LastFixedUpdatePositions());
    36.         bufferT.Add(new LastFixedUpdatePositions());
    37.  
    38.         var bufferR = dstManager.AddBuffer<LastFixedUpdateTimes>(entity);
    39.         bufferR.Add(new LastFixedUpdateTimes());
    40.         bufferR.Add(new LastFixedUpdateTimes());
    41.  
    42.         var bufferDT = dstManager.AddBuffer<LastFixedUpdateRotations>(entity);
    43.         bufferDT.Add(new LastFixedUpdateRotations());
    44.         bufferDT.Add(new LastFixedUpdateRotations());
    45.  
    46.         dstManager.AddComponentData(entity, new NewTimeIndex { });
    47.     }
    48. }
    InterpolationSystems.cs
    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Collections;
    3. using Unity.Entities;
    4. using Unity.Jobs;
    5. using Unity.Mathematics;
    6. using Unity.Rendering;
    7. using Unity.Transforms;
    8. using UnityEngine;
    9.  
    10. [UpdateInGroup(typeof(PresentationSystemGroup))]
    11. [UpdateBefore(typeof(RenderBoundsUpdateSystem))]
    12. public class TransformInterpolationSystem : JobComponentSystem
    13. {
    14.     [BurstCompile]
    15.     struct TRInterpolationJob : IJobForEachWithEntity_EBBBCC<
    16.         LastFixedUpdatePositions,
    17.         LastFixedUpdateRotations,
    18.         LastFixedUpdateTimes,
    19.         LocalToWorld,
    20.         NewTimeIndex>
    21.     {
    22.         public float time;
    23.  
    24.         public void Execute(
    25.             Entity entity,
    26.             int index,
    27.             DynamicBuffer<LastFixedUpdatePositions> lastFixedUpdatePositions,
    28.             DynamicBuffer<LastFixedUpdateRotations> lastFixedUpdateRotations,
    29.             DynamicBuffer<LastFixedUpdateTimes> lastFixedUpdateTimes,          
    30.             ref LocalToWorld localToWorld,
    31.             ref NewTimeIndex newTimeIndex)
    32.         {
    33.  
    34.             int newerTimeIndex = newTimeIndex.Value;
    35.             int olderTimeIndex = OldTimeIndex(newTimeIndex);
    36.  
    37.             float newerTime = lastFixedUpdateTimes[newerTimeIndex].Value;
    38.             float olderTime = lastFixedUpdateTimes[olderTimeIndex].Value;
    39.  
    40.             float3 newerPos = lastFixedUpdatePositions[newerTimeIndex].Value;
    41.             float3 olderPos = lastFixedUpdatePositions[olderTimeIndex].Value;
    42.  
    43.             var newerRot = lastFixedUpdateRotations[newerTimeIndex].Value;
    44.             var olderRot = lastFixedUpdateRotations[olderTimeIndex].Value;
    45.  
    46.             float t;
    47.  
    48.             if (newerTime != olderTime)
    49.             {
    50.                 t = (time - newerTime) / (newerTime - olderTime);
    51.             }
    52.             else
    53.             {
    54.                 t = 1;
    55.             }
    56.  
    57.             var interpolatedPosition = math.lerp(olderPos, newerPos, t);
    58.             var interpolatedRotation = math.slerp(olderRot, newerRot, t);
    59.  
    60.             localToWorld.Value =
    61.                 new float4x4(interpolatedRotation, interpolatedPosition);
    62.  
    63.         }
    64.  
    65.         private int OldTimeIndex(NewTimeIndex newTimeIndex)
    66.         {
    67.             return (newTimeIndex.Value == 0 ? 1 : 0);
    68.         }
    69.     }
    70.  
    71.     protected override JobHandle OnUpdate(JobHandle inputDependencies)
    72.     {
    73.         var job = new TRInterpolationJob()
    74.         {
    75.             time = UnityEngine.Time.time
    76.         };
    77.         return job.Schedule(this, inputDependencies);
    78.     }
    79.    
    80. }
    81.  
    82. [UpdateInGroup(typeof(LateSimulationSystemGroup))]
    83. public class BufferTranslationRotationSystem : JobComponentSystem
    84. {
    85.     [BurstCompile]
    86.     struct BufferTRJob : IJobForEachWithEntity_EBBBCCC<
    87.         LastFixedUpdatePositions,
    88.         LastFixedUpdateRotations,
    89.         LastFixedUpdateTimes,
    90.         NewTimeIndex,
    91.         Translation,
    92.         Rotation>
    93.     {
    94.         public float time;
    95.  
    96.         public void Execute(
    97.             Entity entity,
    98.             int index,
    99.             DynamicBuffer<LastFixedUpdatePositions> lastFixedUpdatePositions,
    100.             DynamicBuffer<LastFixedUpdateRotations> lastFixedUpdateRotations,
    101.             DynamicBuffer<LastFixedUpdateTimes> lastFixedUpdateTimes,
    102.             ref NewTimeIndex newTimeIndex,
    103.             [ReadOnly]ref Translation pos,
    104.             [ReadOnly]ref Rotation rot)
    105.         {
    106.             newTimeIndex.Value = OldTimeIndex(newTimeIndex);
    107.             lastFixedUpdateTimes[newTimeIndex.Value] =
    108.                 new LastFixedUpdateTimes { Value = time };
    109.  
    110.             lastFixedUpdatePositions[newTimeIndex.Value] =
    111.                 new LastFixedUpdatePositions { Value = pos.Value };
    112.  
    113.             lastFixedUpdateRotations[newTimeIndex.Value] =
    114.                 new LastFixedUpdateRotations { Value = rot.Value };
    115.  
    116.         }
    117.         private int OldTimeIndex(NewTimeIndex newTimeIndex)
    118.         {
    119.             return (newTimeIndex.Value == 0 ? 1 : 0);
    120.         }
    121.     }
    122.  
    123.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    124.     {
    125.  
    126.         var job = new BufferTRJob()
    127.         {
    128.             time = UnityEngine.Time.fixedTime
    129.         };
    130.         return job.Schedule(this, inputDeps);
    131.     }
    132. }
     
    psuong, rz_0lento and steveeHavok like this.
  8. MarcoLebdech

    MarcoLebdech

    Joined:
    Nov 26, 2016
    Posts:
    1
    Hey guys, I had problems with above solutions not working.
    My MeshRenders are always (or at least often) children of Unity.Physics entity.

    My solution is something between interpolation and extrapolation. As it knows where it's heading, but doesn't expect collisions.
    Only thing you need to do, is adding "PhysicsInterpolation" component to some physics based entity. My renderers are children of physics Entity, as I am rendering multiple subMeshes. Theoretically, MeshRender should work also when hooked to physics object.

    So I need to interploate only physics-based entites. I changed implementation a bit. I am not using buffers, only Translation, Rotation, PhysicsMass and PhysicsVelocity to interpolate. I have problems with "bumps" only when colliding. I get bumps at only very low fixedUpdate rates.

    I am still bit confused by transformation matrices and I am still debugging rotation around center of mass.

    EDIT: I fixed rotation implementation aroung centre of mass

    PhysicsInterpolation.cs
    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Collections;
    3. using Unity.Entities;
    4. using Unity.Jobs;
    5. using Unity.Mathematics;
    6. using Unity.Physics;
    7. using Unity.Rendering;
    8. using Unity.Transforms;
    9.  
    10. namespace Lebdev.Core
    11. {
    12.     [WriteGroup(typeof(LocalToWorld))]
    13.     public struct PhysicsInterpolation : IComponentData
    14.     {
    15.         public float4x4 LocalToWorld;
    16.         public float3 CenterOfMass;
    17.         public float3 LinearVelocity;
    18.         public float3 AngularVelocity;
    19.     }
    20.  
    21.     [UpdateInGroup(typeof(LateSimulationSystemGroup))]
    22.     public class InterpolationFixedUpdateSystem : JobComponentSystem
    23.     {
    24.         [BurstCompile]
    25.         struct UpdateInterpolationData : IJobForEach<PhysicsInterpolation, Translation, Rotation, PhysicsVelocity, PhysicsMass>
    26.         {
    27.             public float fixedTime;
    28.  
    29.             public void Execute(ref PhysicsInterpolation physicsInterpolation, ref Translation position, ref Rotation rotation, ref PhysicsVelocity velocity, ref PhysicsMass mass)
    30.             {
    31.                 physicsInterpolation.FixedTime = fixedTime;
    32.                 physicsInterpolation.LocalToWorld = new float4x4(rotation.Value, position.Value);
    33.  
    34.                 physicsInterpolation.LinearVelocity = velocity.Linear;
    35.                 physicsInterpolation.AngularVelocity = velocity.Angular;
    36.                 physicsInterpolation.CenterOfMass = mass.CenterOfMass;
    37.             }
    38.         }
    39.  
    40.         protected override JobHandle OnUpdate(JobHandle inputDependencies)
    41.         {
    42.             return new UpdateInterpolationData { fixedTime = UnityEngine.Time.fixedTime }
    43.                 .Schedule(this, inputDependencies);
    44.         }
    45.     }
    46.  
    47.     [UpdateInGroup(typeof(PresentationSystemGroup))]
    48.     [UpdateBefore(typeof(RenderBoundsUpdateSystem))]
    49.     public class InterpolationUpdateSystem : JobComponentSystem
    50.     {
    51.         [BurstCompile]
    52.         struct InterpolationTransformJob : IJobForEach<PhysicsInterpolation, LocalToWorld, PhysicsVelocity>
    53.         {
    54.             public float time;
    55.  
    56.             private quaternion IntegrateQuaternion(quaternion from, float3 angularVelocity, float time)
    57.             {
    58.                 quaternion dq = new quaternion(new float4(angularVelocity * new float3(time * 0.5f), 1.0f));
    59.                 return math.normalize(math.mul(from, dq));
    60.             }
    61.  
    62.             public void Execute(ref PhysicsInterpolation physicsInterpolation, ref LocalToWorld localToWorld, ref PhysicsVelocity velocity)
    63.             {
    64.                 float timeStep = time - physicsInterpolation.FixedTime; // time in seconds since last fixedUpdate
    65.                 float4x4 massToLocal = new float4x4(quaternion.identity, physicsInterpolation.CenterOfMass);
    66.                 float4x4 rotation = new float4x4(IntegrateQuaternion(quaternion.identity, physicsInterpolation.AngularVelocity, timeStep), float3.zero);  
    67.                 float4x4 localTransform = new float4x4(quaternion.identity, math.lerp(float3.zero, physicsInterpolation.LinearVelocity, timeStep));
    68.                 float4x4 localToWorld = math.mul(localTransform, physicsInterpolation.LocalToWorld);
    69.                 localToWorldComponent.Value = math.mul(math.mul(math.mul(localToWorld, massToLocal), rotation), math.fastinverse(massToLocal));
    70.             }
    71.         }
    72.  
    73.         override protected JobHandle OnUpdate(JobHandle inputDependencies)
    74.         {
    75.             return new InterpolationTransformJob { time = UnityEngine.Time.time }
    76.                 .Schedule(this, inputDependencies);
    77.         }
    78.  
    79.     }
    80.  
    81.     [UpdateInGroup(typeof(PresentationSystemGroup))]
    82.     [UpdateAfter(typeof(InterpolationUpdateSystem)), UpdateBefore(typeof(RenderBoundsUpdateSystem))]
    83.     public class InterpolationParentSystem : LocalToParentSystem
    84.     {
    85.     }
    86.  
    87. }
    and just a bit updated `WorldBootStrap.cs` from @apaxnid
    Code (CSharp):
    1. using System.Reflection;
    2. using Unity.Entities;
    3. using UnityEngine.LowLevel;
    4. using UnityEngine.PlayerLoop;
    5.  
    6. namespace Lebdev.Core
    7. {
    8.     public class CustomWorldBootstrap : ICustomBootstrap
    9.     {
    10.  
    11.         static MethodInfo InsertManagerIntoSubsystemList = typeof(ScriptBehaviourUpdateOrder).GetMethod("InsertManagerIntoSubsystemList", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
    12.  
    13.         public bool Initialize(string defaultWorldName)
    14.         {
    15.             var world = new Unity.Entities.World("Custom World");
    16.  
    17.             Unity.Entities.World.DefaultGameObjectInjectionWorld = world;
    18.             var systems = DefaultWorldInitialization.GetAllSystems(WorldSystemFilterFlags.Default);
    19.  
    20.             DefaultWorldInitialization.AddSystemsToRootLevelSystemGroups(world, systems);
    21.             UpdatePlayerLoop(world);
    22.  
    23.             return true;
    24.         }
    25.  
    26.         protected static PlayerLoopSystem[] ReplaceSystems<T>(Unity.Entities.World world, in PlayerLoopSystem[] subSystems)
    27.             where T : ComponentSystemBase
    28.         {
    29.             var newSubSystems = new PlayerLoopSystem[subSystems.Length + 1];
    30.             for (var j = 0; j < subSystems.Length; ++j)
    31.                 newSubSystems[j] = subSystems[j];
    32.  
    33.             T system = world.GetOrCreateSystem<T>();
    34.  
    35.             InsertManagerIntoSubsystemList.MakeGenericMethod(system.GetType())
    36.                 .Invoke(null, new object[] { newSubSystems, subSystems.Length + 0, system });
    37.  
    38.             return newSubSystems;
    39.         }
    40.  
    41.         public static void UpdatePlayerLoop(Unity.Entities.World world)
    42.         {
    43.             var playerLoop = PlayerLoop.GetDefaultPlayerLoop();
    44.  
    45.             if (ScriptBehaviourUpdateOrder.CurrentPlayerLoop.subSystemList != null)
    46.                 playerLoop = ScriptBehaviourUpdateOrder.CurrentPlayerLoop;
    47.  
    48.             if (world != null)
    49.             {
    50.                 PlayerLoopSystem[] playerLoopSystems = playerLoop.subSystemList;
    51.  
    52.                 for (var i = 0; i < playerLoopSystems.Length; ++i)
    53.                 {
    54.                     if (playerLoopSystems[i].type == typeof(FixedUpdate))
    55.                     {
    56.                         playerLoopSystems[i].subSystemList = ReplaceSystems<SimulationSystemGroup>(world, playerLoopSystems[i].subSystemList);
    57.                     }
    58.                     else if (playerLoopSystems[i].type == typeof(PreLateUpdate))
    59.                     {
    60.                         playerLoopSystems[i].subSystemList = ReplaceSystems<PresentationSystemGroup>(world, playerLoopSystems[i].subSystemList);
    61.                     }
    62.                     else if (playerLoopSystems[i].type == typeof(Initialization))
    63.                     {
    64.                         playerLoopSystems[i].subSystemList = ReplaceSystems<InitializationSystemGroup>(world, playerLoopSystems[i].subSystemList);
    65.                     }
    66.                 }
    67.             }
    68.  
    69.             ScriptBehaviourUpdateOrder.SetPlayerLoop(playerLoop);
    70.         }
    71.     }
    72. }
    73.  
     
    Last edited: Feb 8, 2020
    NotaNaN likes this.
  9. zardini123

    zardini123

    Joined:
    Jan 5, 2013
    Posts:
    68
    I have a fairly similar solution to the update rate problem in my thread here. It's a much simpler approach of just moving the entire simulation system group from Update to FixedUpdate, so Unity Physics works well, but it doesn't have any interpolation. I bet it can be extended by adding a system group back into update to then add interpolation like you all have been implementing.