Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question XR Pose / Input System BeforeRender System Group Equivalent in ECS

Discussion in 'Entity Component System' started by Jonathan_L, Sep 13, 2023.

  1. Jonathan_L

    Jonathan_L

    Joined:
    Jan 26, 2016
    Posts:
    38
    I recently started learning DOTS/ECS and right now I am working on an XR pose tracker ECS managed component. I am processing the Input System manually with calling InputSystem.Update and have a system that updates LocalTransforms once during the Initialization System Group based on InputActionReference's binded to XR devices. I am able to get tracking but it is jittery because XR devices need to be updated twice, one for regular input system update, and again before render (this is for smoothness).

    I currently update a managed component that keeps track of position/rotation by adding a callback to InputAction.performed to update these values. However, I am unable to update any RefRW<LocalTransforms> in the same callback or I'll get execptions (such as InvalidOperationException). I have also tried to use InputSystem.onAfterUpdate += (some Job.Run()) but I get similar errors. I think it makes sense in my head why I would get these errors, it doesn't seem like attaching an IJobEntity to run in one of these callbacks would work but I have no other idea on how to approach this. I also tried updating in "PresentationSystemGroup" (also with OrderFirst and OrderLast) on a system that pulls in the tracked values from the managed component and updates LocalTransforms but I am still experiencing the jitter.

    So my question: Is there a system group that I can update in or before/after to fix this issue? I assume this group would run around the same time as the "BeforeRender" mentioned in the InputSystem. Or maybe is there another approach to get this working with systems?

    Input System update type reference:
    https://docs.unity3d.com/Packages/c...ine.InputSystem.InputSettings.UpdateMode.html

    Here is some code for reference (I'll remove references to quaternion Rotation and int TrackingState to make a bit concise):
    Code (CSharp):
    1. public class PoseTrackerAuthoring : MonoBehaviour
    2.     {
    3.         public TrackingType Tracking;
    4.         public InputActionReference PositionInput;
    5.  
    6.         class Baker : Baker<PoseTrackerAuthoring>
    7.         {
    8.             public override void Bake(PoseTrackerAuthoring authoring)
    9.             {
    10.                 Entity entity = GetEntity(TransformUsageFlags.Dynamic);
    11.  
    12.                 AddComponentObject(entity, new PoseTracker
    13.                 {
    14.                     TrackingType = (uint)authoring.Tracking,
    15.                     PositionAction = GetInputAction(authoring.PositionInput),
    16.                 });
    17.             }
    18.         }
    19.     }
    20.  
    21.     public class PoseTracker : IComponentData
    22.     {
    23.         public uint TrackingType;
    24.  
    25.         public InputAction PositionAction;
    26.  
    27.         public float3 Position;
    28.  
    29.         public Action<CallbackContext> PositionPerformedAction;
    30.         public Action<CallbackContext> PositionCanceledAction;
    31.     }
    32.  
    33.     [UpdateBefore(typeof(TransformSystemGroup))]
    34.     public partial class PoseTrackerSystem : SystemBase
    35.     {
    36.         protected override void OnStartRunning()
    37.         {
    38.             new PoseTrackerEnable().Run();
    39.         }
    40.  
    41.         protected override void OnUpdate()
    42.         {
    43.             CompleteDependency();
    44.             new PoseTrackerJob().Run();
    45.         }
    46.  
    47.         protected override void OnStopRunning()
    48.         {
    49.             new PoseTrackerDisable().Run();
    50.  
    51.         }
    52.     }
    53.  
    54.     [UpdateInGroup(typeof(PresentationSystemGroup), OrderLast = true)]
    55.     public partial class PoseTrackerBeforeRenderSystem : SystemBase
    56.     {
    57.         protected override void OnUpdate()
    58.         {
    59.             CompleteDependency();
    60.             new PoseTrackerJob().Run();
    61.         }
    62.     }
    63.  
    64.     public partial struct PoseTrackerEnable : IJobEntity
    65.     {
    66.         public void Execute(PoseTracker tracker)
    67.         {
    68.             if (tracker.PositionAction != null)
    69.             {
    70.                 tracker.PositionAction.Enable();
    71.  
    72.                 tracker.PositionPerformedAction = (context) => tracker.Position = context.ReadValue<Vector3>();
    73.                 tracker.PositionAction.performed += tracker.PositionPerformedAction;
    74.  
    75.                 tracker.PositionCanceledAction = (context) => tracker.Position = float3.zero;
    76.                 tracker.PositionAction.canceled += tracker.PositionCanceledAction;
    77.             }
    78.         }
    79.     }
    80.  
    81.     public partial struct PoseTrackerDisable : IJobEntity
    82.     {
    83.         public void Execute(PoseTracker tracker)
    84.         {
    85.             if (tracker.PositionAction != null)
    86.             {
    87.                 tracker.PositionAction.Disable();
    88.  
    89.                 tracker.PositionAction.performed -= tracker.PositionPerformedAction;
    90.                 tracker.PositionAction.canceled -= tracker.PositionCanceledAction;
    91.             }
    92.         }
    93.     }
    94.  
    95.     public partial struct PoseTrackerJob : IJobEntity
    96.     {
    97.         public void Execute(PoseTracker tracker, RefRW<LocalTransform> transform)
    98.         {
    99.             TrackTransform(tracker, transform);
    100.         }
    101.  
    102.         public static void TrackTransform(PoseTracker tracker, RefRW<LocalTransform> transform)
    103.         {
    104.                 if (tracker.PositionAction != null)
    105.                 {
    106.                     transform.ValueRW.Position = tracker.Position;
    107.                 }
    108.         }
    109.     }
     
  2. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    262
    You are never going to track many entities, why not leave it as an Game Object and have it update in the 'normal' unity lifecycle?
    Especially for the HMD the input data timing is really important.
     
  3. Jonathan_L

    Jonathan_L

    Joined:
    Jan 26, 2016
    Posts:
    38
    I think that's what I am just going to do. I originally wanted to do as much as possible in ECS as part of me getting familiar with DOTS and also thought this would be a good case for that since I couldn't find an authoring component for tracking. But I'll leave it alone and do game object sync.

    However, I am still curious about this problem. System ordering and job scheduling are easy to grasp but I don't really know much about the 'normal' unity lifecycle, especially how it works with systems. I feel like an explanation for this would help me gain a bit more intuition on how everything works.
     
  4. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    262
    Yes scheduling and system dependencies are things that go wrong from time to time.

    Every piece of unity is its own mess with its own work arounds and issues. ECS is great for game logic and large amount of 'entities' doing the same thing. Also the rendering in ECS is good to use.

    I keep VFX graph, Input, audio (with object pooling), Terrain, camera and VR tracking all in the Mono/normal unity lifecycle.
    I copy the input to ECS to be used every frame, but I sample it in Mono. The ECS update does run in sync with normal unity update, so they will both run 1 time per frame. For most input 1 frame difference does not matter too much. The HMD does matter but its on the camera that is in Mono/normal unity.
     
    Jonathan_L likes this.