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

Resolved Sync GameObject and Entity position (ECS 1.0.11)

Discussion in 'Entity Component System' started by RaveOnTheGrave, Aug 17, 2023.

  1. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    26
    For Cinemachine to work, I need to synchronize the position of the GameObject (target for the camera) and the Entity. Everything seems to be working, but there are some lags in the movement of the camera. I tried to calculate the position of the target for the camera in the world using TransformHelpers.ComputeWorldTransformMatrix(), but this did not work.

    Code I am using:

    Code (CSharp):
    1.  
    2.     public partial class EntityGameObjectSyncSystem : SystemBase
    3.     {
    4.         protected override void OnUpdate()
    5.         {
    6.             var followedTagEntity = SystemAPI.GetSingletonEntity<FollowedEntityTag>();
    7.             var localTransformLookup = SystemAPI.GetComponentLookup<LocalTransform>();
    8.             var parentLookup = SystemAPI.GetComponentLookup<Parent>();
    9.             var postTransformLookup = SystemAPI.GetComponentLookup<PostTransformMatrix>();
    10.            
    11.             TransformHelpers.ComputeWorldTransformMatrix(
    12.                 followedTagEntity, out float4x4 matrix, ref localTransformLookup,
    13.                 ref parentLookup, ref postTransformLookup
    14.                 );
    15.  
    16.             // Get Camera target gameObject
    17.             var followerSingleton = EntityFollower.Instance;
    18.  
    19.             followerSingleton.transform.position = matrix.Translation();
    20.             followerSingleton.transform.rotation = matrix.Rotation();
    21.         }
    22.     }
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    I don't think you really need to compute TRS manually. Usually, to sync it you'd use setup like this:
    1. Set Cinemachine to LateUpdate only;
    2. Compute positions & rotations as usual (via TransformSystem or otherwise). This should be at "Update" step.
    3. Apply position / rotation computed for the entity to the transform target. TRS should be in world space.

    If done correctly, it would sync just fine.
    Issues crop up when you need to read & write both camera & target in the same frame (like for example with First Person camera). Then you'd need to set Cinemachine update mode to manual, and perform camera updates in a separate managed system.

    TL;DR:
    1. "Update" - Compute TRS for Entity
    2. "Before LateUpdate" - Apply data to the target
    3. "LateUpdate" - Cinemachine update.
     
  3. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    26
    I set LateUpdate in Cinemachine.
    If I understand correctly, Update is SymulationSystemGroup and Before LateUpdate is a PresentationSystemGroup, or i must to do sync in Monobehaviour?

    Code (CSharp):
    1.  
    2.     // Compute TRS
    3.     [UpdateInGroup(typeof(SimulationSystemGroup))]
    4.     public partial class EntityGameObjectSyncSystem : SystemBase
    5.     {
    6.         protected override void OnUpdate()
    7.         {
    8.             var followedTagEntity = SystemAPI.GetSingletonEntity<FollowedEntityTag>();
    9.             var localTransformLookup = SystemAPI.GetComponentLookup<LocalTransform>();
    10.             var parentLookup = SystemAPI.GetComponentLookup<Parent>();
    11.             var postTransformLookup = SystemAPI.GetComponentLookup<PostTransformMatrix>();
    12.      
    13.             TransformHelpers.ComputeWorldTransformMatrix(
    14.                 followedTagEntity, out float4x4 matrix, ref localTransformLookup,
    15.                 ref parentLookup, ref postTransformLookup
    16.                 );
    17.      
    18.             var localToWorld = SystemAPI.GetComponentRW<LocalToWorld>(followedTagEntity);
    19.             localToWorld.ValueRW.Value = matrix;
    20.         }
    21.     }
    22.  
    23.     // Sync gameobject
    24.     [UpdateInGroup(typeof(PresentationSystemGroup))]
    25.     public partial class EntityGameObjectSyncSystem2 : SystemBase
    26.     {
    27.         protected override void OnUpdate()
    28.         {
    29.             var followedTagEntity = SystemAPI.GetSingletonEntity<FollowedEntityTag>();
    30.             var localToWorld = SystemAPI.GetComponent<LocalToWorld>(followedTagEntity);
    31.             var followerSingleton = EntityFollower.Instance;
    32.  
    33.             followerSingleton.transform.position = localToWorld.Position;
    34.             followerSingleton.transform.rotation = localToWorld.Rotation;
    35.         }
    36.     }
     
    Last edited: Aug 17, 2023
  4. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    PresentationSystemGroup runs after MonoBehaviour's LateUpdate.
    Which will cause a frame delay in this case, which results in stuttering.

    Naming is really missleading, since PlayerLoop doesn't actualy have a "LateUpdate" phase.
    It has PreLateUpdate & PostLateUpdate phases.
    LateUpdate for MonoBehaviours executes in PreLateUpdate.

    E.g.
    upload_2023-8-17_18-54-8.png

    So overall, you need to order systems to run after TRS computation e.g. TransformGroup, but before PresentationSystemGroup.

    You could also use LateSimulationSystemGroup, since it runs after SimulationGroup jobs but be aware that it runs before EndSimulationECBSystem. Or, you could add extra system group that runs after simulation group like this.

    Usually I use AfterSimulationGroup for this kind of managed systems. This allows any change done via ECB also propagate to the MonoBehaviours in the same frame / time period. Alike Update.
     
    Last edited: Aug 17, 2023
  5. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    Parent cinemachine camera directly to the target without cinemachine component for the test.
    Check if it stutters.

    If it does - then computed target object TRS is not correct (e.g. not interpolated correctly);
    If it doesn't - then interpolation values on the cinemachine vcam component is incorrect.

    Alternatively, you could also check which object is actually stuttering in the scene view.
    Double check the order of the systems (via Systems or Profiler's Timeline).
     
  6. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    26
    The problem persisted, I uploaded a video where it is presented:


    I did the above steps and came up with this code:
    Code (CSharp):
    1.  
    2.     // Custom Group
    3.     [UpdateInGroup(typeof(AfterSimulationGroup))]
    4.     public partial class EntityGameObjectSyncSystem : SystemBase
    5.     {
    6.         protected override void OnUpdate()
    7.         {
    8.             var followedTagEntity = SystemAPI.GetSingletonEntity<FollowedEntityTag>();
    9.             var localToWorld = SystemAPI.GetComponent<LocalToWorld>(followedTagEntity);
    10.             var followerSingleton = EntityFollower.Instance;
    11.  
    12.             followerSingleton.transform.position = localToWorld.Position;
    13.             followerSingleton.transform.rotation = localToWorld.Rotation;
    14.         }
    15.     }
     
  7. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
  8. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    26


    This is image with group order:

    https://yourimageshare.com/ib/F7kLndItnS.webp

    Removed cinemachine, it seems that the problem is gone, probably)
     
    Last edited: Aug 17, 2023
  9. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    Then its probably incorrect values set in the Cinemachine vCam. (e.g. 0's could cause that)
     
  10. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    26
    Do you know if there are ready-made solutions on how to use cinemachine and ecs? I searched the internet and didn't find anything useful.
     
  11. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    You're almost there.
    If parenting camera to the target works stutter free - fix your cinemachine vcam setup, and it should run just fine.

    There isn't anything extra, because Cinemachine doesn't require anything extra on top. Just proper setup.
    And its identical to just using MonoBehaviours once you've passed data to the target transform.

    As far as I know, there is some Cinemachine integration with Entities, but its wip / experimental.
     
    RaveOnTheGrave likes this.
  12. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    26
    I don't know for sure, at the moment I'm translating the script to ecs and all the camera settings on GameObjects worked fine. Maybe the problem is something else.
     
  13. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    Might be some other scripts, like CinemachineTargetGroup's update is in wrong place.
    With systems you'd have to write custom group for example, and update it manually
    (Cinemachine is designed a bit funky when it comes to extensions).

    Hard to tell without seeing an actual full setup.
     
    Last edited: Aug 18, 2023
  14. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    26
    The problem of the lag camera appears only in the editor, everything is fine in the build. There is a 60 fps limit in the build, by the way. So thanks for your help.