Search Unity

Timeline Notifications aren't sent in PlayableDirector Manual Mode

Discussion in 'Timeline' started by Kleptine, Jul 16, 2019.

  1. Kleptine

    Kleptine

    Joined:
    Dec 23, 2013
    Posts:
    282
    I'm using the following script to step my Timeline in alignment with physics (so that physics can nicely be affected by animations).
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Playables;
    3.  
    4. /// <summary>
    5. /// Simply steps a <see cref="PlayableDirector"/> once every FixedUpdate, rather than on the display frame, which is the default.
    6. /// </summary>
    7. [RequireComponent(typeof(PlayableDirector))]
    8. public class FixedUpdatePlayableDirector : MonoBehaviour
    9. {
    10.     private void FixedUpdate()
    11.     {
    12.         PlayableDirector playableDirector = GetComponent<PlayableDirector>();
    13.         if (playableDirector != null)
    14.         {
    15.             playableDirector.playableGraph.Evaluate(Time.fixedDeltaTime);
    16.         }
    17.     }
    18. }

    This does update the animation, but doesn't send any signals. The Unity blog post also mentions that Signals/Notifys aren't set when using Evaluate.

    Is there a way to manually send signals to workaround this? Or can an API be added that properly sends notifies when calling Evaluate (ie. a boolean in that function?).
     
  2. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    Unfortunately there is no way to do this right now. The notification playable that sends the trigger explicitly ignores Evaluate calls.

    It sounds like the solution you want is really a FixedUpdate timeline update.
     
    huulong likes this.
  3. Kleptine

    Kleptine

    Joined:
    Dec 23, 2013
    Posts:
    282
    Thanks for the information. Yes, a FixedUpdate option would be fantastic, although the better solution is just a specialized method for manually stepping an PlayableGraph that doesn't conflict with scrubbing. Seems like notifications are disabled to avoid scrubbing notifies (makes sense), but scrubbing should just use a different flag.

    I've worked around all of this by just disabling the check in the TimeNotificationBehaviour (after pulling timeline into a custom package):

    Code (CSharp):
    1. ...
    2.         /// <summary>
    3.         /// This method is called during the PrepareFrame phase of the PlayableGraph.
    4.         /// </summary>
    5.         /// <remarks>
    6.         /// Called once before processing starts.
    7.         /// </remarks>
    8.         /// <param name="playable">The reference to the playable associated with this PlayableBehaviour.</param>
    9.         /// <param name="info">Playable context information such as weight, evaluationType, and so on.</param>
    10.         public override void PrepareFrame(Playable playable, FrameData info)
    11.         {
    12.             // Never trigger on scrub
    13.             // ASG: Only check for scrubbing when in the editor. This is technically incorrect, as you can scrub at playtime,
    14.             // but this is a workaround to allow a manually stepped timeline in FixedUpdate to send notifications of markers.
    15.             if (!Application.isPlaying && info.evaluationType == FrameData.EvaluationType.Evaluate)
    16.             {
    17.                 return;
    18.             }
    19.  
    20.             SyncDurationWithExternalSource(playable);
    21. ...
    It obviously going to break if I try scrubbing in PlayMode, but seems to work fine for my purposes? I now manually step the timeline in FixedUpdate and notifies are sent as expected.
     
  4. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    Spot on. As long as you aren't using AudioTracks that should work just fine.

    Manually evaluating the graph is considered a 'scrub', but having a way to advance the graph as a 'playback' is definitely needed.
     
  5. Kleptine

    Kleptine

    Joined:
    Dec 23, 2013
    Posts:
    282
    What are the complexities / consequences if we end up using AudioTracks? We haven't yet, but just curious.

    Is the audio system a bit more complex because it needs to inject audio events into the audio system (which has its own time, etc)?
     
  6. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    Audio doesn't play back on an Evaluate call. The audio system is more complicated because it is always scheduled against the DSP clock, and an evaluate call doesn't guarantee the timeline is actually playing. Evaluate is great for discrete systems like Animation, but complex for continuous systems.

    A timeline playing on the game clock can have longer audio clips 'drift' for that reason, and we included the DSP clock on playable director in the cases where audio tracks need to sync perfectly (i.e. make everything else match the audio).
     
  7. Kleptine

    Kleptine

    Joined:
    Dec 23, 2013
    Posts:
    282
    Gotcha, makes sense. Thanks for the info and help!

    (You folks should consider moving Timeline open source like InputSystem and SRP! :))
     
  8. ribbanya

    ribbanya

    Joined:
    Feb 28, 2019
    Posts:
    9
    Any plans to change/fix this? I'd rather not have to modify the Timeline source code and my custom editor relies on signals being sent when scrubbing (in both Edit and Play modes).
     
  9. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    There is no current plan in place to change that right now - which of course, can change with user feedback.
     
    LinnPeder likes this.
  10. ribbanya

    ribbanya

    Joined:
    Feb 28, 2019
    Posts:
    9
    Is this the proper channel to submit that feedback, or is there an issue tracker or something?
     
  11. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    The forums are the proper channel now.
     
    ribbanya likes this.
  12. whitexroft

    whitexroft

    Joined:
    Oct 22, 2012
    Posts:
    48
    we are running our entire game on manual playable directors.
    how come there is no way to manuallly emit signals?
     
  13. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    We didn't implement signal emission on an Evaluate call because it is difficult to determine user intent - Signals require a delta time, and Evaluate is used in many different ways. That makes even the last evaluate time vs current evaluate time not dependable as a deltaTime.

    In hindsight, we probably should have added someway to advance the playable director manually with a given delta time. (Similar to playableGraph.Evaluate()).
     
    huulong likes this.
  14. Kleptine

    Kleptine

    Joined:
    Dec 23, 2013
    Posts:
    282
    Yeah, something like PlayableDirector.Advance() would be fantastic.

    When you say 'in hindsight', does that mean the Timeline is somewhat finished, in terms of folks who are working on it? If there's no plans to push further on this kind of thing, it'd be fantastic if the Timeline package were open source. Then it'd be easy for someone to start a PR that kicked off this change.

    You can setup Github to disable most of the other features (like Issues, etc) if you're worried about maintenance burden.
     
  15. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    'In hindsight', I just meant when we implemented signals - Timeline itself is still in active development.

    As for open source, the problem (in this case) is the playable director/playableGraph is native code. The advance feature would be a Unity addition, not a timeline package addition.

    However, your point is noted :) It would be an advantage for the timeline package to be open source, or at least available on a public github.
     
  16. Kleptine

    Kleptine

    Joined:
    Dec 23, 2013
    Posts:
    282
    Ah, that's a bummer, but makes sense. I guess you'll just have to jobify it. ;)

    Yeah, even just a public mirror would be great. It'd make it much easier to keep our changes rebased on top of the latest.
     
  17. AmazingRuss

    AmazingRuss

    Joined:
    May 25, 2008
    Posts:
    933
    >Yeah, something like PlayableDirector.Advance() would be fantastic.

    Agreed.

    A PlayableDirector.timeScale value would also be very useful in this context.

    Any updates on this? It's got me completely stopped, as I need both Signals and Audio Tracks.

    Is it possible to search the graph for the Signals and Audio tracks, and manage them manually?
     
  18. DavidGeoffroy

    DavidGeoffroy

    Unity Technologies

    Joined:
    Sep 9, 2014
    Posts:
    542
    Audio tracks currently support Time.timeScale.
    Do you need your Timeline to play on a different time scale than the rest of your game?
     
  19. Peter-Dijkstra

    Peter-Dijkstra

    Joined:
    Feb 15, 2013
    Posts:
    8
    +1 for adding an Advance() call that fires notifications

    I like to run my own update loop for similar reasons as OP.
     
  20. TimHeijden2

    TimHeijden2

    Joined:
    Aug 11, 2016
    Posts:
    86
    +! for advance(), I want to play a director using network time which requires me to manually update the director but also want to raise event
     
    Shonnyy likes this.
  21. learner_CL

    learner_CL

    Joined:
    Dec 23, 2016
    Posts:
    6
    We really need signal to be triggered in manual mode too~
     
    LinnPeder likes this.
  22. Andrew-Carvalho

    Andrew-Carvalho

    Joined:
    Apr 22, 2013
    Posts:
    44
    Just hit a wall in some custom tooling due to this as well. While an alternate PlayableGraph.Update or PlayableGraph.Advance would work, so would a new enum value in EvaluationType that distinguishes between Evaluation at editor time vs runtime, which may be a much simpler and safer solution to implement?
     
  23. smg-sean

    smg-sean

    Joined:
    Feb 9, 2022
    Posts:
    3
    Also hit a wall on this. An Advance() method is a must!
     
  24. huulong

    huulong

    Joined:
    Jul 1, 2013
    Posts:
    224
  25. Duane_Nomad

    Duane_Nomad

    Joined:
    Mar 13, 2019
    Posts:
    3
    Just ran into similar issue with Timeline playback where I simply want it to update by a fixed rate because we control/pause the timeline at various points via signals but using the manual flow doesn't trigger the signals etc. and the game update method is a little too unreliable.

    We are using Unity 2021.3.5f1 so I was wondering if a FixedUpdate option or some way to manually advance the timeline with a custom framerate that triggers the signals was on the radar or not?
     
  26. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    345
    playableDirector.Evaluate(deltaTime) does in fact advance the timeline's time. Don't know when this was added but it works. The update mode has to be set to Manual to really use this though.
    Using evaluate() does open a whole bunch of other problems though (like audio and anim rigging not playing nicely with it).
     
  27. huulong

    huulong

    Joined:
    Jul 1, 2013
    Posts:
    224
    I got this issue again today, as I had another timeline-related issue: in case of frame lag, the director skips multiple frames at once and "batch" all the signals contained, calling all bound signal callbacks in the same frame (but still in order).

    This caused an issue as some of my signal callbacks call playableDirector.Pause() precisely to stop the timeline flow until I'm done with some animation. The callbacks contain async/await calls so they would run in the background before calling Resume(). But the director would chain calls to the multiple signal callbacks, as soon as one async method awaits and leaves hand to main thread, so it would unexpectedly play both animations/effects in parallel, and if the signal was just at the end of timeline, it would even call director stopped event before I'm done with the effects/animations.

    So, I thought a ManualMode + Evaluate would be nice to control that flow and make sure I follow Fixed Update timing, without ever batching two frames together. But I forgot it didn't work with signals...

    At this point, I may as well use an Animator in FixedUpdate mode with animation events...
     
  28. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    345

    We have a similar situation in a project. My personal opinion is timeline is not well suited for gameplay logic. What you can try is having one PlayableDirector in ManualMode for logic stuff and another for visual stuff in GameTimeMode.
    Fun side note, fixed update behaves exactly the same way as you described above for timeline. If the update loop skips frames or timeSinceLastFixedUpdate accumulates to more than one fixed time step unity catches up fixed time by executing multiple fixed updates before the next update call. Fixed update is not accurate in it's timing, only in it's count of executions.

    Being able to decide if signals would be called by evaluate on a per signal basis would be quite nice.
     
  29. LinnPeder

    LinnPeder

    Joined:
    Jul 6, 2022
    Posts:
    3
    is it too late to join the thread?
    +1 for firing signals in manual mode, please :3