Search Unity

Blend Timlines with multible Animators

Discussion in 'Animation' started by fffMalzbier, Sep 27, 2019.

  1. fffMalzbier

    fffMalzbier

    Joined:
    Jun 14, 2011
    Posts:
    3,276
    Im currently in need of a way to blend / transition a timeline with multible animatior from one point to another point in time in the same timeline.

    I currently got a sollution that works with one ainmator but all my trys to make it work for multible do not seem to get it done.
    Either i do not get any animations at all or the blending does not work.

    Here is what i got so far.

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Animations;
    6. using UnityEngine.Playables;
    7. using UnityEngine.Timeline;
    8. using Object = System.Object;
    9.  
    10.  
    11. [RequireComponent(typeof(PlayableDirector))]
    12. public class CrossFadeTimeline : MonoBehaviour
    13. {
    14.     public bool StartTrigger;
    15.     public float FadeDuration = 1f;
    16.     public float SeekTime = 0f;
    17.  
    18.     private PlayableDirector _playableDirector;
    19.     private AnimationPlayableOutput _output;
    20.     private PlayableDirector _playableDirector2;
    21.     private Playable _originalSourcePlayable;
    22.     private Playable _clone;
    23.     private AnimationMixerPlayable _mixer;
    24.     private int _originalIndex;
    25.     private int _cloneIndex;
    26.     private float _decreasingWeight;
    27.     private float _increasingWeight;
    28.     public float debugProgress;
    29.     public int animationOutputIndex;
    30.  
    31.  
    32.  
    33.     // Assume playOnAwake on the playabledirector
    34.     void OnEnable()
    35.     {
    36.         _playableDirector = GetComponent<PlayableDirector>();
    37.  
    38.         if (_playableDirector.playableGraph.IsValid())
    39.         {
    40.             // assumes the first output is the one we want to fade
    41.  
    42.  
    43.             var oldOutput = (AnimationPlayableOutput)_playableDirector.playableGraph.GetOutputByType<AnimationPlayableOutput>(animationOutputIndex);
    44.  
    45.             _originalSourcePlayable = oldOutput.GetSourcePlayable();
    46.  
    47.             _clone = _playableDirector.playableAsset.CreatePlayable(_playableDirector.playableGraph, _playableDirector.gameObject);
    48.             _mixer = AnimationMixerPlayable.Create(_playableDirector.playableGraph, 2);
    49.      
    50.  
    51.             _cloneIndex = _mixer.AddInput(_clone, 0);
    52.             _originalIndex = _mixer.AddInput(_originalSourcePlayable, 0, 1f);
    53.  
    54.  
    55. //needed?
    56.             for (int i = 0; i < _clone.GetInputCount(); i++)
    57.             {
    58.                 for (int j = 0; j < _clone.GetInput(i).GetInputCount(); j++)
    59.                 {
    60.  
    61.                     if (_clone.GetInput(i).GetPlayableType() != typeof(TimeMachineMixerBehaviour))
    62.                     {
    63.                         _clone.GetInput(i).SetInputWeight(j, 1);
    64.                     }
    65.  
    66.                 }
    67.             }
    68.    
    69.  
    70.             if (oldOutput.IsOutputValid() && oldOutput.GetTarget() != null)
    71.             {
    72.                 _output = AnimationPlayableOutput.Create(_playableDirector.playableGraph, "OverridedDirectorOutput", oldOutput.GetTarget());
    73.                 _output.SetSourcePlayable(_mixer);
    74.                 _output.SetSourceOutputPort(oldOutput.GetSourceOutputPort());
    75.                 _output.SetWeight(1f);
    76.                 oldOutput.SetTarget(null);
    77.             }
    78.         }
    79.     }
    80.  
    81.  
    82.     [ContextMenu("PauseTimeline")]
    83.     public void PauseTimeline()
    84.     {
    85.  
    86.         _originalSourcePlayable.SetSpeed(0);
    87.  
    88.         //_playableDirector.playableGraph.GetRootPlayable(0).SetSpeed(0);
    89.     }
    90.  
    91.     public void StartFadeOut(float time)
    92.     {
    93.         Debug.Log("StartFadeOut");
    94.         StartTrigger = true;
    95.         SeekTime = time;
    96.  
    97.         if (!_output.IsOutputValid())
    98.         {
    99.             OnEnable();
    100.         }
    101.     }
    102.  
    103.     void Update()
    104.     {
    105.  
    106.         if (StartTrigger)
    107.         {
    108.             StartTrigger = false;
    109.             if (_output.IsOutputValid())
    110.                 StartCoroutine(CrossFade());
    111.             else
    112.                 Debug.LogError("_output is not valid");
    113.         }
    114.     }
    115.  
    116.     IEnumerator CrossFade()
    117.     {
    118.         float t = 0;
    119.  
    120.         _originalSourcePlayable.SetSpeed(1);
    121.         //Debug.Log($"CrossFade Start - OriginalTime: {_playableDirector.time:N4} CloneTime {_clone.GetTime():N4}");
    122.  
    123.         _clone.SetTime(_playableDirector.time);
    124.         _clone.Play();
    125.  
    126.         _playableDirector.time = SeekTime;
    127.         _playableDirector.Play();
    128.  
    129.         while (t < FadeDuration)
    130.         {
    131.             var normalizedTime = Mathf.Clamp01(t / FadeDuration);
    132.             debugProgress = normalizedTime;
    133.             _decreasingWeight = 1 - normalizedTime;
    134.             _increasingWeight = normalizedTime;
    135.  
    136.             _mixer.SetInputWeight(_cloneIndex, _decreasingWeight);
    137.             _mixer.SetInputWeight(_originalIndex, _increasingWeight);
    138.  
    139.            // Debug.Log($"Tick - CloneTime-: {_clone.GetTime():N4} / {_decreasingWeight}, OriginalTime+: {_playableDirector.time:N4} / {_increasingWeight}");
    140.  
    141.             yield return null;
    142.             t += Time.deltaTime;
    143.         }
    144.  
    145.         _mixer.SetInputWeight(_cloneIndex, 0);
    146.         _mixer.SetInputWeight(_originalIndex, 1f);
    147.  
    148.         _clone.Pause();
    149.        // Debug.Log("CrossFade Finished");
    150.     }
    151. }


    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Animations;
    6. using UnityEngine.Playables;
    7. using UnityEngine.Timeline;
    8. using System.Linq;
    9. using Object = System.Object;
    10.  
    11.  
    12. [RequireComponent(typeof(PlayableDirector))]
    13. public class CrossFadeTimeline : MonoBehaviour
    14. {
    15.     public bool StartTrigger;
    16.     public float FadeDuration = 1f;
    17.     public float SeekTime = 0f;
    18.  
    19.     private PlayableDirector _playableDirector;
    20.  
    21.     private float _decreasingWeight;
    22.     private float _increasingWeight;
    23.     public float debugProgress;
    24.     public Playable _clone;
    25.  
    26.     public int animationOutputIndex;
    27.  
    28.  
    29.     struct playableData
    30.     {
    31.         public AnimationPlayableOutput _output;
    32.         public PlayableDirector _playableDirector2;
    33.         public Playable _originalSourcePlayable;
    34.         public AnimationPlayableOutput oldOutput;
    35.  
    36.         public AnimationMixerPlayable _mixer;
    37.         public int _originalIndex;
    38.         public int _cloneIndex;
    39.     }
    40.  
    41.  
    42.     List<playableData> playableDataList;
    43.  
    44.  
    45.     // Assume playOnAwake on the playabledirector
    46.     void OnEnable()
    47.     {
    48.         Debug.Log("OnEnable");
    49.         _playableDirector = GetComponent<PlayableDirector>();
    50.         playableDataList = new List<playableData>();
    51.  
    52.  
    53.         if (_playableDirector.playableGraph.IsValid())
    54.         {
    55.             int count = _playableDirector.playableGraph.GetOutputCountByType<AnimationPlayableOutput>();
    56.  
    57.             List<AnimationPlayableOutput> animPlayout = new List<AnimationPlayableOutput>() ;
    58.  
    59.             for (int p = 0; p < count; p++)
    60.             {
    61.                 var oldOutput = (AnimationPlayableOutput)_playableDirector.playableGraph.GetOutputByType<AnimationPlayableOutput>(p);
    62.        
    63.  
    64.                 animPlayout.Add(oldOutput);
    65.             }
    66.  
    67.  
    68.             for (int p = 0; p < count; p++)
    69.             {
    70.                 playableData curentDataSet = new playableData();
    71.                 curentDataSet.oldOutput = animPlayout[p];
    72.  
    73.  
    74.                 curentDataSet._originalSourcePlayable = curentDataSet.oldOutput.GetSourcePlayable();
    75.  
    76.  
    77.      
    78.                 if (!_clone.IsValid())
    79.                 {
    80.                     _clone = _playableDirector.playableAsset.CreatePlayable(_playableDirector.playableGraph, _playableDirector.gameObject);
    81.              
    82.                 }
    83.  
    84.    
    85.  
    86.                 curentDataSet._mixer = AnimationMixerPlayable.Create(_playableDirector.playableGraph, 2);
    87.  
    88.  
    89.                 curentDataSet._cloneIndex = curentDataSet._mixer.AddInput(_clone, p);
    90.                 _clone.SetOutputCount(curentDataSet._originalSourcePlayable.GetOutputCount() + 1);
    91.  
    92.                 curentDataSet._originalSourcePlayable.SetOutputCount(curentDataSet._originalSourcePlayable.GetOutputCount() + 1);
    93.                 curentDataSet._originalIndex = curentDataSet._mixer.AddInput(curentDataSet._originalSourcePlayable, p, 1f);
    94.  
    95.                 for (int i = 0; i < _clone.GetInputCount(); i++)
    96.                 {
    97.                     for (int j = 0; j < _clone.GetInput(i).GetInputCount(); j++)
    98.                     {
    99.  
    100.                         if (_clone.GetInput(i).GetPlayableType() != typeof(TimeMachineMixerBehaviour))
    101.                         {
    102.                             _clone.GetInput(i).SetInputWeight(j, curentDataSet._originalSourcePlayable.GetInput(i).GetInputWeight(j));
    103.            
    104.  
    105.                         }
    106.  
    107.  
    108.                     }
    109.                 }
    110.  
    111.  
    112.  
    113.      
    114.                 if (curentDataSet.oldOutput.IsOutputValid() && curentDataSet.oldOutput.GetTarget() != null)
    115.                 {
    116.  
    117.                     int outputport = curentDataSet.oldOutput.GetSourceOutputPort();
    118.                     Animator target = curentDataSet.oldOutput.GetTarget();
    119.                  //   Debug.Log("OLD     " + curentDataSet.oldOutput.GetReferenceObject() + " " + curentDataSet.oldOutput.GetTarget());
    120.  
    121.                     curentDataSet._output = AnimationPlayableOutput.Create(_playableDirector.playableGraph, "OverridedDirectorOutput", target);
    122.  
    123.            
    124.                     curentDataSet._output.SetSourcePlayable(curentDataSet._mixer);
    125.                     curentDataSet._output.SetReferenceObject(curentDataSet.oldOutput.GetReferenceObject());
    126.  
    127.                   //  Debug.Log("new     " + curentDataSet._output.GetReferenceObject() + " " + curentDataSet._output.GetTarget());
    128.  
    129.  
    130.                     curentDataSet._output.SetSourceOutputPort(outputport);
    131.                     _playableDirector.playableGraph.Disconnect(curentDataSet.oldOutput.GetSourcePlayable(), 0);
    132.                     curentDataSet.oldOutput.SetSourcePlayable(curentDataSet.oldOutput.GetSourcePlayable(), 0);
    133.  
    134.  
    135.                  //   Debug.Log("old del " + curentDataSet.oldOutput.GetReferenceObject() + " " + curentDataSet.oldOutput.GetTarget());
    136.                  //   Debug.Log("new after " +curentDataSet._output.GetReferenceObject() + " " + curentDataSet._output.GetTarget());
    137.  
    138.  
    139.                     curentDataSet._output.SetWeight(1f);
    140.  
    141.                     curentDataSet._output.SetTarget(curentDataSet.oldOutput.GetTarget());
    142.                  //   Debug.Log("oldOutput " + curentDataSet.oldOutput.GetHashCode()  + " curentDataSet._output " + curentDataSet._output.GetHashCode());
    143.                     curentDataSet.oldOutput.SetTarget(null);
    144.  
    145.                 }
    146.                 playableDataList.Add(curentDataSet);
    147.  
    148.             }
    149.  
    150.  
    151.  
    152.         }
    153.  
    154.  
    155.         for (int i = 0; i < _playableDirector.playableGraph.GetOutputCountByType<AnimationPlayableOutput>(); i++)
    156.         {
    157.             var test = (AnimationPlayableOutput)_playableDirector.playableGraph.GetOutputByType<AnimationPlayableOutput>(i);
    158.             if (test.IsOutputValid())
    159.             {
    160.                 if (test.GetTarget() != null)
    161.                 {
    162.                     Debug.LogWarning("output " + i + " " + test.GetTarget().ToString());
    163.                 }
    164.                 else
    165.                 {
    166.                     Debug.LogWarning("Output " + i + " target is null");
    167.                 }
    168.  
    169.             }
    170.             else
    171.             {
    172.                 Debug.LogWarning("Output " + i + " is not valid");
    173.             }
    174.  
    175.         }
    176.  
    177.  
    178.  
    179.     }
    180.  
    181.  
    182.     [ContextMenu("PauseTimeline")]
    183.     public void PauseTimeline()
    184.     {
    185.         for (int i = 0; i < playableDataList.Count; i++)
    186.         {
    187.             playableDataList[i]._originalSourcePlayable.SetSpeed(0);
    188.  
    189.         }
    190.     }
    191.  
    192.     public void StartFadeOut(float time)
    193.     {
    194.         Debug.Log("StartFadeOut");
    195.         StartTrigger = true;
    196.         SeekTime = time;
    197.  
    198.         if (playableDataList.Any((x) => !x._output.IsOutputValid()))
    199.         {
    200.             OnEnable();
    201.         }
    202.     }
    203.  
    204.     void Update()
    205.     {
    206.  
    207.         if (StartTrigger)
    208.         {
    209.             StartTrigger = false;
    210.             if (playableDataList.All((x) => x._output.IsOutputValid()))
    211.                 StartCoroutine(CrossFade());
    212.             else
    213.                 Debug.LogError("_output is not valid");
    214.         }
    215.     }
    216.  
    217.     IEnumerator CrossFade()
    218.     {
    219.         float t = 0;
    220.         for (int i = 0; i < playableDataList.Count; i++)
    221.         {
    222.             // playableDataList[i]
    223.             Debug.Log(playableDataList[i]._output.GetTarget());
    224.  
    225.             playableDataList[i]._originalSourcePlayable.SetSpeed(1);
    226.             //Debug.Log($"CrossFade Start - OriginalTime: {_playableDirector.time:N4} CloneTime {_clone.GetTime():N4}");
    227.  
    228.             _clone.SetTime(_playableDirector.time);
    229.             _clone.Play();
    230.         }
    231.  
    232.  
    233.         _playableDirector.time = SeekTime;
    234.         _playableDirector.Play();
    235.  
    236.         while (t < FadeDuration)
    237.         {
    238.             var normalizedTime = Mathf.Clamp01(t / FadeDuration);
    239.             debugProgress = normalizedTime;
    240.             _decreasingWeight = 1 - normalizedTime;
    241.             _increasingWeight = normalizedTime;
    242.             for (int i = 0; i < playableDataList.Count; i++)
    243.             {
    244.                 playableDataList[i]._mixer.SetInputWeight(playableDataList[i]._cloneIndex, _decreasingWeight);
    245.                 playableDataList[i]._mixer.SetInputWeight(playableDataList[i]._originalIndex, _increasingWeight);
    246.             }
    247.            // Debug.Log($"Tick - CloneTime-: {_clone.GetTime():N4} / {_decreasingWeight}, OriginalTime+: {_playableDirector.time:N4} / {_increasingWeight}");
    248.  
    249.             yield return null;
    250.             t += Time.deltaTime;
    251.         }
    252.  
    253.         for (int i = 0; i < playableDataList.Count; i++)
    254.         {
    255.  
    256.             playableDataList[i]._mixer.SetInputWeight(playableDataList[i]._cloneIndex, 0);
    257.             playableDataList[i]._mixer.SetInputWeight(playableDataList[i]._originalIndex, 1f);
    258.  
    259.             _clone.Pause();
    260.  
    261.         }
    262.        // Debug.Log("CrossFade Finished");
    263.     }
    264. }
    screenshot.84.jpg
    Any ideas on what might be wrong or other ways to archive it are highly appreciated.

    Greetings fffMalzbier
     
    Last edited: Sep 27, 2019