WeightedMaskLayers.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
  2. using System;
  3. using Unity.Collections;
  4. using UnityEngine;
  5. namespace Animancer
  6. {
  7. /// <summary>
  8. /// Replaces the default <see cref="AnimancerLayerMixerList"/>
  9. /// with a <see cref="WeightedMaskLayerList"/>.
  10. /// </summary>
  11. /// https://kybernetik.com.au/animancer/api/Animancer/WeightedMaskLayers
  12. [AddComponentMenu(Strings.MenuPrefix + "Weighted Mask Layers")]
  13. [AnimancerHelpUrl(typeof(WeightedMaskLayers))]
  14. [DefaultExecutionOrder(-10000)]// Awake before anything else initializes Animancer.
  15. public class WeightedMaskLayers : MonoBehaviour
  16. {
  17. /************************************************************************************************************************/
  18. [SerializeField] private AnimancerComponent _Animancer;
  19. /// <summary>[<see cref="SerializeField"/>] The component to apply the layers to.</summary>
  20. public AnimancerComponent Animancer
  21. => _Animancer;
  22. /************************************************************************************************************************/
  23. [SerializeField] private WeightedMaskLayersDefinition _Definition;
  24. /// <summary>[<see cref="SerializeField"/>]
  25. /// The definition of transforms to control and weights to apply to them.
  26. /// </summary>
  27. public ref WeightedMaskLayersDefinition Definition
  28. => ref _Definition;
  29. /************************************************************************************************************************/
  30. /// <summary>The layer list created at runtime and assigned to <see cref="AnimancerGraph.Layers"/>.</summary>
  31. public WeightedMaskLayerList Layers { get; protected set; }
  32. /************************************************************************************************************************/
  33. /// <summary>The index of each of the <see cref="WeightedMaskLayersDefinition.Transforms"/>.</summary>
  34. public int[] Indices { get; protected set; }
  35. /************************************************************************************************************************/
  36. /// <summary>Finds the <see cref="Animancer"/> reference if it was missing.</summary>
  37. protected virtual void OnValidate()
  38. {
  39. gameObject.GetComponentInParentOrChildren(ref _Animancer);
  40. }
  41. /************************************************************************************************************************/
  42. /// <summary>Initializes the <see cref="Layers"/> and applies the default group weights.</summary>
  43. protected virtual void Awake()
  44. {
  45. if (Definition == null ||
  46. !Definition.IsValid)
  47. return;
  48. if (_Animancer == null)
  49. TryGetComponent(out _Animancer);
  50. Layers = WeightedMaskLayerList.Create(_Animancer.Animator);
  51. _Animancer.InitializePlayable(Layers.Graph);
  52. Indices = Definition.CalculateIndices(Layers);
  53. SetWeights(0);
  54. }
  55. /************************************************************************************************************************/
  56. /// <summary>Applies the weights of the specified group.</summary>
  57. public void SetWeights(int groupIndex)
  58. {
  59. Definition.AssertGroupIndex(groupIndex);
  60. var boneWeights = Layers.BoneWeights;
  61. var definitionWeights = Definition.Weights;
  62. var start = groupIndex * Indices.Length;
  63. for (int i = 0; i < Indices.Length; i++)
  64. {
  65. var index = Indices[i];
  66. var weight = definitionWeights[start + i];
  67. boneWeights[index] = weight;
  68. }
  69. }
  70. /************************************************************************************************************************/
  71. private Fade _Fade;
  72. /// <summary>Fades the weights towards the specified group.</summary>
  73. public void FadeWeights(
  74. int groupIndex,
  75. float fadeDuration,
  76. Func<float, float> easing = null)
  77. {
  78. if (fadeDuration > 0)
  79. {
  80. _Fade ??= new();
  81. _Fade.Start(this, groupIndex, fadeDuration, easing);
  82. }
  83. else
  84. {
  85. SetWeights(groupIndex);
  86. }
  87. }
  88. /************************************************************************************************************************/
  89. /// <summary>An <see cref="IUpdatable"/> which fades <see cref="WeightedMaskLayers"/> over time.</summary>
  90. /// https://kybernetik.com.au/animancer/api/Animancer/Fade
  91. public class Fade : Updatable
  92. {
  93. /************************************************************************************************************************/
  94. private NativeArray<float> _CurrentWeights;
  95. private float[] _OriginalWeights;
  96. private WeightedMaskLayers _Layers;
  97. private int _TargetWeightIndex;
  98. private Func<float, float> _Easing;
  99. /// <summary>The amount of time that has passed since the start of this fade (in seconds).</summary>
  100. public float ElapsedTime { get; set; }
  101. /// <summary>The total amount of time this fade will take (in seconds).</summary>
  102. public float Duration { get; set; }
  103. /************************************************************************************************************************/
  104. /// <summary>Initializes this fade and registers it to receive updates.</summary>
  105. public void Start(
  106. WeightedMaskLayers layers,
  107. int groupIndex,
  108. float duration,
  109. Func<float, float> easing = null)
  110. {
  111. layers.Definition.AssertGroupIndex(groupIndex);
  112. _CurrentWeights = layers.Layers.BoneWeights;
  113. _Easing = easing;
  114. _Layers = layers;
  115. _TargetWeightIndex = layers.Definition.IndexOf(groupIndex, 0);
  116. Duration = duration;
  117. var indices = _Layers.Indices;
  118. AnimancerUtilities.SetLength(ref _OriginalWeights, indices.Length);
  119. for (int i = 0; i < _OriginalWeights.Length; i++)
  120. {
  121. var index = indices[i];
  122. _OriginalWeights[i] = _CurrentWeights[index];
  123. }
  124. ElapsedTime = 0;
  125. layers.Layers.Graph.RequirePreUpdate(this);
  126. }
  127. /************************************************************************************************************************/
  128. /// <inheritdoc/>
  129. public override void Update()
  130. {
  131. ElapsedTime += AnimancerGraph.DeltaTime;
  132. if (ElapsedTime < Duration)
  133. {
  134. ApplyFade(ElapsedTime / Duration);
  135. }
  136. else
  137. {
  138. ApplyTargetWeights();
  139. AnimancerGraph.Current.CancelPreUpdate(this);
  140. }
  141. }
  142. /************************************************************************************************************************/
  143. /// <summary>Recalculates the weights by interpolating based on `t`.</summary>
  144. private void ApplyFade(float t)
  145. {
  146. if (_Easing != null)
  147. t = _Easing(t);
  148. var targetWeights = _Layers.Definition.Weights;
  149. var indices = _Layers.Indices;
  150. var boneWeights = _CurrentWeights;
  151. for (int i = 0; i < indices.Length; i++)
  152. {
  153. var index = indices[i];
  154. var from = _OriginalWeights[i];
  155. var to = targetWeights[_TargetWeightIndex + i];
  156. boneWeights[index] = Mathf.LerpUnclamped(from, to, t);
  157. }
  158. }
  159. /// <summary>Recalculates the target weights.</summary>
  160. private void ApplyTargetWeights()
  161. {
  162. var targetWeights = _Layers.Definition.Weights;
  163. var indices = _Layers.Indices;
  164. var boneWeights = _CurrentWeights;
  165. for (int i = 0; i < indices.Length; i++)
  166. {
  167. var index = indices[i];
  168. var to = targetWeights[_TargetWeightIndex + i];
  169. boneWeights[index] = to;
  170. }
  171. }
  172. /************************************************************************************************************************/
  173. }
  174. /************************************************************************************************************************/
  175. }
  176. }