100 lines
4.1 KiB
C#
100 lines
4.1 KiB
C#
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
|
|
|
|
using System;
|
|
using Unity.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.Animations;
|
|
|
|
namespace Animancer
|
|
{
|
|
/// <summary>
|
|
/// A replacement for the default <see cref="AnimationLayerMixerPlayable"/> which uses custom
|
|
/// <see cref="BoneWeights"/> for each individual bone instead of just using an <see cref="AvatarMask"/>
|
|
/// to include or exclude them entirely.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This system currently only supports 2 layers (Base + 1). Adding support for more would require additional
|
|
/// <see cref="BoneWeights"/> for each additional layer and modifications to <see cref="WeightedMaskMixerJob"/>
|
|
/// to iterate through each layer instead of just using the first two.
|
|
/// </remarks>
|
|
/// https://kybernetik.com.au/animancer/api/Animancer/WeightedMaskLayerList
|
|
public class WeightedMaskLayerList : AnimancerLayerList, IDisposable
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>The objects being masked.</summary>
|
|
public readonly Transform[] Bones;
|
|
|
|
/// <summary>The job data.</summary>
|
|
private readonly WeightedMaskMixerJob _Job;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>The blend weight of each of the <see cref="Bones"/>.</summary>
|
|
public NativeArray<float> BoneWeights
|
|
=> _Job.boneWeights;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Returns the index of the value corresponding to the 'bone' in the <see cref="BoneWeights"/> array.</summary>
|
|
public int IndexOf(Transform bone)
|
|
=> Array.IndexOf(Bones, bone) - 1;// Index - 1 since the root is ignored.
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Creates a new <see cref="AnimancerGraph"/> and <see cref="WeightedMaskLayerList"/>.</summary>
|
|
/// <remarks>
|
|
/// This method can't be a constructor because it would need to
|
|
/// assign itself to the graph before being fully constructed.
|
|
/// </remarks>
|
|
public static WeightedMaskLayerList Create(Animator animator)
|
|
{
|
|
var graph = new AnimancerGraph();
|
|
var layers = new WeightedMaskLayerList(graph, animator);
|
|
graph.Layers = layers;
|
|
return layers;
|
|
}
|
|
|
|
/// <summary>Creates a new <see cref="WeightedMaskLayerList"/>.</summary>
|
|
public WeightedMaskLayerList(AnimancerGraph graph, Animator animator)
|
|
: base(graph)
|
|
{
|
|
graph.Layers = this;
|
|
|
|
Bones = animator.GetComponentsInChildren<Transform>();
|
|
|
|
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;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
void IDisposable.Dispose()
|
|
{
|
|
_Job.boneTransforms.Dispose();
|
|
_Job.boneWeights.Dispose();
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
}
|
|
|