Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question Blend two identical timelines with multiple Animator bindings

Discussion in 'Timeline' started by fleity, Sep 24, 2021.

  1. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    361
    Hi everyone

    I have been searching the forums for days but though I have come close I still can't seem to entirely manage the following.

    I want to be able to blend between different times in a timeline therefore when entering playmode I create another playable instance of the playableAsset of my director.
    Buffer the animationOutput in a variable
    Connect the clone timelinePlayable and the original to a mixer and connect the mixer's output to the original animationOutput. This all works nice and perfect for one Animation track and the bound animator.
    However I fail to connect that single mixer (because one should be enough right? it blends all outputs coming from the timelinePlayble?) to multiple animation outputs. With what I currently have it plays mostly the animation of track 1 but on some frames it flickers to track2 :-/


    Screenshot 2021-09-24 095127.jpg

    (The code is loosely based on jeffvella's Timelord github repository)
    This is the function that modifies the graph:
    Code (CSharp):
    1.  
    2. private void BuildOutput()
    3.         {
    4.             PlayableDirector.Evaluate();
    5.  
    6.             if (PlayableDirector.playableGraph.IsValid())
    7.             {
    8.                 var trackCount = (PlayableDirector.playableAsset as TimelineAsset)?.outputTrackCount;
    9.                 _outputs.Clear();
    10.  
    11.                 Debug.Log("trackcount " + trackCount);
    12.  
    13.                 for (int i = 0; i < trackCount; i++)
    14.                 {
    15.                     var originalOutput = (AnimationPlayableOutput)PlayableDirector.playableGraph.GetOutputByType<AnimationPlayableOutput>(i);
    16.                     if (originalOutput.IsOutputValid())
    17.                     {
    18.                         _outputs.Add(originalOutput);
    19.                     }
    20.                 }
    21.  
    22.                 Debug.Log("output count " + _outputs.Count);
    23.  
    24.                 if (_outputs.Count > 0)
    25.                 {
    26.                     _clone = PlayableDirector.playableAsset.CreatePlayable(PlayableDirector.playableGraph, PlayableDirector.gameObject);
    27.                     _mixer = AnimationMixerPlayable.Create(PlayableDirector.playableGraph, 2);
    28.                     var originalSourcePlayable = _outputs[0].GetSourcePlayable();
    29.                     _mixer.ConnectInput(_cloneIndex, _clone, 0, 0f);
    30.                     _mixer.ConnectInput(_originalIndex, originalSourcePlayable, 0, 1f);
    31.  
    32.                     for (int i = 0; i < _outputs.Count; i++)
    33.                     {
    34.                         if (_outputs[i].IsOutputValid() && _outputs[i].GetTarget() != null)
    35.                         {
    36.                             var port = _outputs[i].GetSourceOutputPort();
    37.                             _outputs[i].SetSourcePlayable(_mixer, port);
    38.                         }
    39.                     }
    40.                     Debug.Log("TimelineLoop Blendgraph has been build.");
    41.                 }
    42.                 else
    43.                 {
    44.                     Debug.Log("Original Director Output is invalid");
    45.                 }
    46.             }
    47.             else
    48.             {
    49.                 Debug.Log("Timeline Asset has no animation output");
    50.             }
    51.  
    52.         }

    I thought that this would be the solution or if not the original port just using i as the next possible output port. But both create the same behaviour

    Code (CSharp):
    1.  
    2. var port = _outputs[i].GetSourceOutputPort();
    3. _outputs[i].SetSourcePlayable(_mixer, port);
    4.  
    So yeah, apparently I am not getting something right, I'd be very thankful for your help
    kind regards

    outputPortIndex on the mixer does not seem to have any effect...
    using multiple mixers does not work either because I can not connect the same timeline Playable port to multiple outputs and when I try to explicetely select another output port unity tells me that port does not exist ("attempting to explicitly set an output connection to a non-existing port") although it looks to as this is what the animation output nodes do...
    setting sub tree index on a mixer does nothing and the fact that first track works is a happy accident?
     
    Last edited: Sep 24, 2021
  2. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    361
    I have an additional question.
    As an alternative solution I tried cloning the graph and taking it apart in order to get mixer nodes in before the timelinePlayable. At least this allows me to connect everything the way it should but the animationOffset nodes in the graph copy do not pass any data anymore. Why?
    Screenshot 2021-09-24 174855.jpg
     
  3. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    361
    I managed to get a lot closer to the solution I am looking for.

    It is very important to recognize the difference between
    PlayableDirector.playableGraph.GetOutputCount() and
    PlayableDirector.playableGraph.GetOutputCountByType<>() when iterating through the graph because with the regular GetOutputCount the iterator is in sync with the inputs of the timelinePlayable while with ByType it is not.

    Furthermore the part of the playableAsset clone that I created, disconnected (beginning with the AnimLayerMixerPlayable next to the red arrow) and attached to the rest of the graph still has some connection to the timelinePlayable that I cloned along with it. Because I only get correct updates of the values that I expect when I attach output nodes to that timelinePlayable.

    If I destroy the second timelinePlayable I get Playable is Invalid errors as soon as I get data from that part of the graph.
    So what do I have to call on these disconnected nodes in order to fully attach them to my first timelinePlayable?