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

Bug Camera Jitter during Async Scene Load Operations

Discussion in 'Cinemachine' started by martin_twirlbound, Feb 5, 2021.

  1. martin_twirlbound

    martin_twirlbound

    Joined:
    Jul 18, 2017
    Posts:
    11
    Hello,

    We're having an issue where during async scene load operations the Cinemachine camera shows some jitter relative to the follow target.

    I've attached a simple repro project.
    • In this test project, I'm moving a sphere in the Update() (without a rigidbody) by doing transform.position += direction * deltaTime.
    • Every Update(), I'm also loading/unloading an additive scene asynchronously as fast as I can.
      • I am aware that this is quite an unrealistic case but in our real project we're loading/unloading level chunks and this jitter is visible whenever a level chunk is loaded/unloaded.
    • The Cinemachine brain is using Smart Update, though changing it to Late/Fixed/Manual (and calling ManualUpdate after the movement code) does not seem to fix the jitter.
    • Adding random lag via other means, e.g. randomly doing maths with big numbers in the Update (or in a coroutine but after a yield return null/WaitForEndOfFrame/WaitForFixedUpdate to fiddle with code execution order) stutters the framerate but Cinemachine tracks the object as expected.
    • Stepping frame-by-frame in editor does not show any jitter.
    You see it best by moving the sphere from side-to-side (using A or D keyboard keys).
    Disabling the Cinemachine brain and parenting the camera to the moving sphere does not show jitter in the world.

    jitter.gif

    Details:
    Unity 2020.2.0f1
    Cinemachine 2.6.3
    VCam is using a Framing Transposer (but this issue was also visible using a FreeLook VCam) without any softzone or damping.

    I've also attached the only script in the sample project.
     

    Attached Files:

  2. martin_twirlbound

    martin_twirlbound

    Joined:
    Jul 18, 2017
    Posts:
    11
    Updating to Cinemachine 2.7.1 still shows the same issue.
     
  3. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    Hello,

    If you don't activate the scene on load, then there is no jitter.
    Code (CSharp):
    1. sceneLoadHandle = Addressables.LoadSceneAsync( "Scene", UnityEngine.SceneManagement.LoadSceneMode.Additive, activateOnLoad: false );
    So I think your issue might be related to:
    https://forum.unity.com/threads/starting-async-load-causes-massive-lag-spike.288755/

    Unrelated to the jitter:
    In your PlayerMove.cs, calculating the direction is more efficient this way (note the parentheses):
    Code (CSharp):
    1. _direction.normalized * (speed * Time.deltaTime)
     
    Last edited: Feb 5, 2021
  4. martin_twirlbound

    martin_twirlbound

    Joined:
    Jul 18, 2017
    Posts:
    11
    Hi, thanks for getting back to me.

    I'm not sure how relevant that issue is, since I am not getting any noticable lag spikes (visually or through the profiler). I am not having any performance issues related to async scene loading.

    This can be verified by disabling Cinemachine and having the camera just normally parented to the sphere. If you look at the world as you move the sphere I would expect the world to jitter if the async loading was indeed causing game-wide stutters. But it does not.

    Not activating the scene on load does indeed get rid of jitter, but that's presumably because the scene does not finish the loading process (which I believe is the actual cause of the jitter).
     
    Last edited: Feb 5, 2021
  5. martin_twirlbound

    martin_twirlbound

    Joined:
    Jul 18, 2017
    Posts:
    11
    Additionally, as mentioned in the first post, adding random lag spikes through artificial means (by calling an expensive function randomly in Update) does not cause any jitter with Cinemachine (though of course the game itself stutters).

    It's only a combination of scene activation (which by itself does not create a lag spike in this very simple test project) and Cinemachine which causes the jitter (the game itself is not stuttering/lagging).
     
  6. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    The world jitters for me in that case.
     
  7. martin_twirlbound

    martin_twirlbound

    Joined:
    Jul 18, 2017
    Posts:
    11
    Hmm interesting - is it a wrong assumption on my end that a VCam with settings I've screenshot below (so no damping/no softzone) to track the target as if it was parented to the target even in the presence of stutter?
     

    Attached Files:

  8. gaborkb

    gaborkb

    Unity Technologies

    Joined:
    Nov 7, 2019
    Posts:
    856
    That setup is good.

    An alternative would be to create a vcam, set its Body and Aim to Do Nothing, then parent this vcam to your follow target.
     
  9. martin_twirlbound

    martin_twirlbound

    Joined:
    Jul 18, 2017
    Posts:
    11
    Thanks for confirming that the setup is good - however since the project was a minimal test case to reproduce the issue I was seeing in another project, I'm afraid that setting Body and Aim to Do Nothing is something I'd like to avoid since the camera setup in the "real" project is a bit more elaborate than what was in the screenshot above.

    What confuses me is that adding FPS stutter by calling a heavy function makes Cinemachine behave as I would like/expect. Here is a recording of me adding artificial frame stutters to the project.

    RgVZl15q7P.gif

    In the gif above, even though the world is stuttering quite hard, the sphere is still perfectly framed by the Cinemachine camera. This is the source of my main confusion - is there anything specific about loading a scene asynchronously that causes the Cinemachine vcam to have issues when tracking the follow target? I suspect this might be related to when in the frame the additive scene is integrated by the main thread. I'll see if I can hopefully trigger the undesired jitter in other ways, though as mentioned in my first post I have already tried using Coroutines to fiddle around with when my stutter would be called.

    Just to be clear, my issue is:
    Work/lag introduced by loading a scene additively seems to cause the Cinemachine follow behaviour to jitter around the follow target. Work introduced by other means does not affect Cinemachine tracking. The behaviour shown in the gif in this reply is what I want because Cinemachine frames the target without jitter.

    I've attached my updated PlayerMove.cs script so you can experiment with commenting out "DoSceneLoading" and keeping "DoHeavyFunction" and the opposite to see the difference in effect.
     

    Attached Files:

    gaborkb likes this.
  10. martin_twirlbound

    martin_twirlbound

    Joined:
    Jul 18, 2017
    Posts:
    11
    Okay, I've done a bit more digging and managed to find a workaround - though I guess I am still a bit in the dark in regards to the internals of Unity.

    If I patch the Cinemachine package to allow myself to pass in a custom deltaTime to CinemachineBrain.ManualUpdate() then pass in a manually calculated deltaTime using System.Diagnostics.Stopwatch, the jitter disappears.

    Code (CSharp):
    1. ...
    2. transform.position += relativeToCamera.transform.TransformDirection( _direction.normalized * speed * Time.deltaTime );
    3.  
    4. DoSceneLoading();
    5.  
    6. var _s = stopwatch.Elapsed.TotalSeconds;
    7. brain.ManualUpdate( (float)_s );
    8. stopwatch.Restart();
    9. ...
    This raises another question:
    • Does the stutter caused by loading a scene asynchronously not get taken into account with the normal Time.deltaTime from Unity? Since that's what Cinemachine is using internally and I would assume that would work fine.
    I'm not even sure where to go/who to ask for any insight on this issue... any pointers would be appreciated.
     
  11. DeadReckoned

    DeadReckoned

    Joined:
    Jul 4, 2013
    Posts:
    6
    I've encountered this same problem in Unity 2021.1.15f1, using Cinemchine 2.8.0-pre.1.

    Whenever an additive scene is activated after being loaded asynchronously (using Addressables in my case, but same result), any camera using Unity's delta time values to update its position will jitter. As @martin_twirlbound has pointed out, it's as if some of the time cost incurred as part of the scene activation is not being accounted for in the Time.deltaTime/Time.unscaledDeltaTime properties.

    Without resorting to hacking the Cinemachine package myself, I found this solution to work. Set the CinemachineBrain to manual update mode, and execute this inside LateUpdate (ensure it executes last - set the script's execution order to before the CinemachineBrain)

    Code (CSharp):
    1. float deltaTime = (float)m_Stopwatch.Elapsed.TotalSeconds;
    2. CinemachineCore.UniformDeltaTimeOverride = deltaTime;
    3. m_CinemachineBrain.ManualUpdate();
    4. m_Stopwatch.Restart();
     
  12. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,658
    This is a very interesting thread. @martin_twirlbound Thanks for preparing the test project. You have tripped over a bug in Cinemachine. Here is the explanation:

    CinemachineBrain registers sceneLoaded and sceneUnloaded callbacks with SceneManager, which do a ManualUpdate to take care of vcams that have been created/destroyed with the load/unload. The problem is that when these callbacks come in before PlayerMove.Update, they leave the brain in a state where it thinks it has updated the vcams this frame, but in reality the frame data is stale, so you get jitter.

    We will fix this bug for the next release of CM. In the meantime, you can work around the problem by commenting out the place in CinemachineBrain.cs where the callbacks are registered. For CM 2.6.3, that's line 222. Note that you'll have to embed CM into your project before you can patch it. Do that by copying it from the package cache in Library to your project's Packages folder.
     
    Last edited: Jul 19, 2021
    gaborkb likes this.
  13. martin_twirlbound

    martin_twirlbound

    Joined:
    Jul 18, 2017
    Posts:
    11
    Thanks for investigating the issue and for the explanation, I'll keep an eye out for the next version of CM.
     
  14. VincentPaquin

    VincentPaquin

    Joined:
    Sep 20, 2021
    Posts:
    19
    Hello @Gregoryl !
    In CM 2.6.10, I seem to encounter this issue, and your suggested fix works.

    However, since your original post suggests you'd try to fix this bug in the next CM release, I am wondering if this is a new instance of the same glitch, or if the proper fix hasn't been released yet.

    Thank you for your work, and have a good day!
     
  15. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,658
    This glitch has been fixed in 2.6.10.

    If you are still experiencing a problem, could you please file a bug report that includes a repro project? That way the issue will get tracked properly by QA.