// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik // using System; using Unity.Collections; using UnityEngine; using UnityEngine.Animations; namespace Animancer { /// /// A replacement for the default which uses custom /// for each individual bone instead of just using an /// to include or exclude them entirely. /// /// /// This system currently only supports 2 layers (Base + 1). Adding support for more would require additional /// for each additional layer and modifications to /// to iterate through each layer instead of just using the first two. /// /// https://kybernetik.com.au/animancer/api/Animancer/WeightedMaskLayerList public class WeightedMaskLayerList : AnimancerLayerList, IDisposable { /************************************************************************************************************************/ /// The objects being masked. public readonly Transform[] Bones; /// The job data. private readonly WeightedMaskMixerJob _Job; /************************************************************************************************************************/ /// The blend weight of each of the . public NativeArray BoneWeights => _Job.boneWeights; /************************************************************************************************************************/ /// Returns the index of the value corresponding to the 'bone' in the array. public int IndexOf(Transform bone) => Array.IndexOf(Bones, bone) - 1;// Index - 1 since the root is ignored. /************************************************************************************************************************/ /// Creates a new and . /// /// This method can't be a constructor because it would need to /// assign itself to the graph before being fully constructed. /// public static WeightedMaskLayerList Create(Animator animator) { var graph = new AnimancerGraph(); var layers = new WeightedMaskLayerList(graph, animator); graph.Layers = layers; return layers; } /// Creates a new . public WeightedMaskLayerList(AnimancerGraph graph, Animator animator) : base(graph) { graph.Layers = this; Bones = animator.GetComponentsInChildren(); var boneCount = Bones.Length - 1;// Ignore the root bone. _Job = new WeightedMaskMixerJob() { boneTransforms = new(boneCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory), boneWeights = new(boneCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory), }; graph.Disposables.Add(this); for (var i = 0; i < boneCount; i++) { _Job.boneTransforms[i] = animator.BindStreamTransform(Bones[i + 1]); _Job.boneWeights[i] = 1; } var playable = AnimationScriptPlayable.Create(graph, _Job, Capacity); playable.SetProcessInputs(false); Playable = playable; } /************************************************************************************************************************/ /// void IDisposable.Dispose() { _Job.boneTransforms.Dispose(); _Job.boneWeights.Dispose(); } /************************************************************************************************************************/ } }