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 Timeline releasing Cinemachine override too late

Discussion in 'Cinemachine' started by mrtenda, Aug 23, 2023.

  1. mrtenda

    mrtenda

    Joined:
    Jun 6, 2017
    Posts:
    72
    When I call PlayableDirector.Stop, I would expect the camera override set up by the timeline's Cinemachine track to be released immediately. However, the camera override is not released immediately and is instead released later in the frame. In fact, it's released after our game's LateUpdate function happens.

    This is causing problems because our game is calling CinemachineBrain.ManualUpdate in our LateUpdate function (CinemachineBrain's update method is set to Manual Update). As a result, when the PlayableDirector stops, the camera lingers on the final frame of the timeline for one extra frame, which isn't what we want.

    In other words, here's step-by-step what we're observing happening:
    1. Our game's logic calls PlayableDirector.Stop
    2. Our game's LateUpdate function calls CinemachineBrain.ManualUpdate
    3. CinemachineMixer.OnPlayableDestroy is finally called, which in turn calls CinemachineBrain.ReleaseCameraOverride (but it's too late now, because CinemachineBrain has already updated)

    What's the best way for us to ensure that the CinemachineBrain camera override is released before our game's LateUpdate() function happens? (For example, is there something we can call after PlayableDirector.Stop() that would immediately release all camera overrides?) Thanks!

    (On Unity 2021.3.27f1 with Cinemachine 2.8.9 and Timeline 1.6.5)
     
    Last edited: Aug 25, 2023
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,233
    The Brain's ManualUpdate function expects to be called AFTER all relevant inputs have been updated in the frame. In this case, that would include CinemachineMixer.OnPlayableDestroy, which is called by the timeline infrastructure (not by Cinemachine).

    Normally, ManualUpdate is called from CinemachineBrain.LateUpdate. Because CinemachineBrain has a late execution order, this is usually enough to ensure that all inputs have been previously updated. Can you try giving a late execution order to your script that calls ManualUpdate? Does that fix the issue?
     
    Last edited: Aug 25, 2023
  3. mrtenda

    mrtenda

    Joined:
    Jun 6, 2017
    Posts:
    72
    Thanks for the reply. Unfortunately that did not work. I tried creating a new MonoBehaviour called GameEngineLateExecutionOrder and using its LateUpdate to trigger CinemachineBrain.ManualUpdate. However, LateUpdate is still happening before OnPlayableDestroy. See screenshots below.

    Would really appreciate any more help in solving this. Thanks.

    upload_2023-8-25_16-41-12.png

    upload_2023-8-25_16-40-47.png
     
  4. grahamsaulnier

    grahamsaulnier

    Unity Technologies

    Joined:
    Apr 10, 2018
    Posts:
    17
    When you call
    PlayableDirector.Stop
    it queues a call to
    PlayableGraph.Destroy
    . (note : a few playable outputs will have their targets cleared : animation, audio and texture).

    When the graph destruction is handled it will call
    IPlayableBehaviour.OnPlayableDestroy
    .

    Now, when the dequeuing of the destroy occurs is a bit unpredictable, because it can happen at several times.
    • FixedUpdate
    • Update
    • PreLateUpdate (beginning of LateUpdate)
    • PostLateUpdate (end of LateUpdate)

    Essentially, there's a method that dequeues and invokes all the graph operations that have been queued and it's called in each of those phases (sometimes multiple times).

    Are you calling
    PlayableDirector.Stop
    during LateUpdate? It's possible that cinemachine is being called before we dequeue the graph operations at the end of LateUpdate. (Greg's on vacation for a week now so we'll have to wait to confirm).
     
    antoinecharton likes this.
  5. grahamsaulnier

    grahamsaulnier

    Unity Technologies

    Joined:
    Apr 10, 2018
    Posts:
    17
    Something else to consider is that
    PlayableDirector 
    has an event called
    stopped
    . It's invoked immediately when the director is stopped (when you call
    Stop
    ) so you could subscribe to that, and disconnect your camera manually there.
     
  6. mrtenda

    mrtenda

    Joined:
    Jun 6, 2017
    Posts:
    72
    I thought about this but I can't find any way to remove the CinemachineBrain camera override manually in our game's logic. The CinemachineBrain.ReleaseCameraOverride method takes an override ID as input, and our game's logic doesn't have access to that ID as it's stored in the CinemachineMixer.

    Thanks. This has helped me understand the problem more.

    After testing, I've confirmed that the "lingering on the final frame" issue we're seeing doesn't have anything to do with using Manual Update as the CinemachineBrain update method. I've confirmed that the issue also happens with other CinemachineBrain update methods.

    I've submitted a bug report with a small repro project so the team can more easily see what I'm talking about (IN-53123).

    From what I can tell it seems like this is an issue inherent to how Cinemachine and Timeline are interacting.

    It's extremely undesirable to have Cinemachine linger on the timeline's last vcam for an extra frame, so we'd really appreciate any solutions on how to deal with this. It's making many of the cutscenes in our game linger on the last shot of a cutscene for an extra frame after the timeline is over, making the player see the timeline's final shot with incorrect lighting for a single frame after the cutscene (as in the repro example provided).
     
    Last edited: Aug 29, 2023
    antoinecharton likes this.
  7. grahamsaulnier

    grahamsaulnier

    Unity Technologies

    Joined:
    Apr 10, 2018
    Posts:
    17
    Thanks for the bug report! I looked at your test project and can see that the graph is destroyed during PostLateUpdate which removes the camera override, but the camera isn't updated until the next frame (during CinemachineBrain.ManualUpdate I believe). I'll discuss with Greg further next week when he's back.
     
    mrtenda and antoinecharton like this.
  8. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,233
    Just catching up here. Have not seen the bug report yet, but I thought of a possible workaround for you. If your cutscene has a frame at the end with no active Cinemachine clips anywhere, you could seek to that frame before calling Stop(). That would render the override track harmless until it gets deleted.
     
  9. mrtenda

    mrtenda

    Joined:
    Jun 6, 2017
    Posts:
    72
    Thanks for the suggestion. Yes, the problem does happen only when a Cinemachine clip is present on the final frame of the timeline, so the idea of adding an empty extra frame to every single cutscene did occur. However, our game is extremely cutscene-heavy, with many, many cutscenes that have been developed over the course of multiple years, each with dozens of tracks.

    This approach would take quite a lot of time and effort for us to implement, between going through every single cutscene in the game and adding an extra blank frame, making sure not to mess up any of the other tracks in each cutscene, making sure the activation tracks are all reverting properly, re-testing all the cutscenes, etc.

    Given that this issue seems like a core aspect of how Cinemachine should be working with timeline, is a more proper solution possible, or at least one that doesn't involve modifying every single timeline in our game?
     
  10. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,233
    I hear you, but to be realistic it's unlikely that such a deep architectural interaction between 2 Unity subsystems is going to change in the near term. So we're looking at either modifying your content to be a little more frame-tolerant, or finding some other kind of workaround. We've covered the first option. Here is an idea for the second option: when you stop the timeline, disable/enable the CinemachineBrain component. That will force it to forget all its overrides. Could that work for you?
     
    Last edited: Sep 26, 2023
  11. mrtenda

    mrtenda

    Joined:
    Jun 6, 2017
    Posts:
    72
    Disabling then enabling the CinemachineBrain seems work great! We're not seeing the problem anymore. Thank you for helping us out with this.
     
  12. mrtenda

    mrtenda

    Joined:
    Jun 6, 2017
    Posts:
    72
    Posting this for anyone in the future reading this who might be wondering where my bug report went:

    upload_2023-9-25_23-41-50.png