// 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();
}
/************************************************************************************************************************/
}
}