AnimationOutputWeightProcessor.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. using System.Collections.Generic;
  2. using UnityEngine.Animations;
  3. using UnityEngine.Playables;
  4. namespace UnityEngine.Timeline
  5. {
  6. // Does a post processing of the weights on an animation track to properly normalize
  7. // the mixer weights so that blending does not bring default poses and subtracks, layers and
  8. // layer graphs blend correctly
  9. class AnimationOutputWeightProcessor : ITimelineEvaluateCallback
  10. {
  11. struct WeightInfo
  12. {
  13. public Playable mixer;
  14. public Playable parentMixer;
  15. public int port;
  16. }
  17. AnimationPlayableOutput m_Output;
  18. AnimationMotionXToDeltaPlayable m_MotionXPlayable;
  19. readonly List<WeightInfo> m_Mixers = new List<WeightInfo>();
  20. public AnimationOutputWeightProcessor(AnimationPlayableOutput output)
  21. {
  22. m_Output = output;
  23. output.SetWeight(0);
  24. FindMixers();
  25. }
  26. void FindMixers()
  27. {
  28. var playable = m_Output.GetSourcePlayable();
  29. var outputPort = m_Output.GetSourceOutputPort();
  30. m_Mixers.Clear();
  31. // only write the final output in playmode. it should always be 1 in editor because we blend to the defaults
  32. FindMixers(playable, outputPort, playable.GetInput(outputPort));
  33. }
  34. // Recursively accumulates mixers.
  35. void FindMixers(Playable parent, int port, Playable node)
  36. {
  37. if (!node.IsValid())
  38. return;
  39. var type = node.GetPlayableType();
  40. if (type == typeof(AnimationMixerPlayable) || type == typeof(AnimationLayerMixerPlayable))
  41. {
  42. // use post fix traversal so children come before parents
  43. int subCount = node.GetInputCount();
  44. for (int j = 0; j < subCount; j++)
  45. {
  46. FindMixers(node, j, node.GetInput(j));
  47. }
  48. // if we encounter a layer mixer, we assume there is nesting occuring
  49. // and we modulate the weight instead of overwriting it.
  50. var weightInfo = new WeightInfo
  51. {
  52. parentMixer = parent,
  53. mixer = node,
  54. port = port,
  55. };
  56. m_Mixers.Add(weightInfo);
  57. }
  58. else
  59. {
  60. var count = node.GetInputCount();
  61. for (var i = 0; i < count; i++)
  62. {
  63. FindMixers(parent, port, node.GetInput(i));
  64. }
  65. }
  66. }
  67. public void Evaluate()
  68. {
  69. float weight = 1;
  70. m_Output.SetWeight(1);
  71. for (int i = 0; i < m_Mixers.Count; i++)
  72. {
  73. var mixInfo = m_Mixers[i];
  74. weight = WeightUtility.NormalizeMixer(mixInfo.mixer);
  75. mixInfo.parentMixer.SetInputWeight(mixInfo.port, weight);
  76. }
  77. // only write the final weight in player/playmode. In editor, we are blending to the appropriate defaults
  78. // the last mixer in the list is the final blend, since the list is composed post-order.
  79. if (Application.isPlaying)
  80. m_Output.SetWeight(weight);
  81. }
  82. }
  83. }