94 lines
3.2 KiB
C#
94 lines
3.2 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine.Animations;
|
|
using UnityEngine.Playables;
|
|
|
|
namespace UnityEngine.Timeline
|
|
{
|
|
// Does a post processing of the weights on an animation track to properly normalize
|
|
// the mixer weights so that blending does not bring default poses and subtracks, layers and
|
|
// layer graphs blend correctly
|
|
class AnimationOutputWeightProcessor : ITimelineEvaluateCallback
|
|
{
|
|
struct WeightInfo
|
|
{
|
|
public Playable mixer;
|
|
public Playable parentMixer;
|
|
public int port;
|
|
}
|
|
|
|
AnimationPlayableOutput m_Output;
|
|
AnimationMotionXToDeltaPlayable m_MotionXPlayable;
|
|
readonly List<WeightInfo> m_Mixers = new List<WeightInfo>();
|
|
|
|
public AnimationOutputWeightProcessor(AnimationPlayableOutput output)
|
|
{
|
|
m_Output = output;
|
|
output.SetWeight(0);
|
|
FindMixers();
|
|
}
|
|
|
|
void FindMixers()
|
|
{
|
|
var playable = m_Output.GetSourcePlayable();
|
|
var outputPort = m_Output.GetSourceOutputPort();
|
|
|
|
m_Mixers.Clear();
|
|
// only write the final output in playmode. it should always be 1 in editor because we blend to the defaults
|
|
FindMixers(playable, outputPort, playable.GetInput(outputPort));
|
|
}
|
|
|
|
// Recursively accumulates mixers.
|
|
void FindMixers(Playable parent, int port, Playable node)
|
|
{
|
|
if (!node.IsValid())
|
|
return;
|
|
|
|
var type = node.GetPlayableType();
|
|
if (type == typeof(AnimationMixerPlayable) || type == typeof(AnimationLayerMixerPlayable))
|
|
{
|
|
// use post fix traversal so children come before parents
|
|
int subCount = node.GetInputCount();
|
|
for (int j = 0; j < subCount; j++)
|
|
{
|
|
FindMixers(node, j, node.GetInput(j));
|
|
}
|
|
|
|
// if we encounter a layer mixer, we assume there is nesting occuring
|
|
// and we modulate the weight instead of overwriting it.
|
|
var weightInfo = new WeightInfo
|
|
{
|
|
parentMixer = parent,
|
|
mixer = node,
|
|
port = port,
|
|
};
|
|
m_Mixers.Add(weightInfo);
|
|
}
|
|
else
|
|
{
|
|
var count = node.GetInputCount();
|
|
for (var i = 0; i < count; i++)
|
|
{
|
|
FindMixers(parent, port, node.GetInput(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Evaluate()
|
|
{
|
|
float weight = 1;
|
|
m_Output.SetWeight(1);
|
|
for (int i = 0; i < m_Mixers.Count; i++)
|
|
{
|
|
var mixInfo = m_Mixers[i];
|
|
weight = WeightUtility.NormalizeMixer(mixInfo.mixer);
|
|
mixInfo.parentMixer.SetInputWeight(mixInfo.port, weight);
|
|
}
|
|
|
|
// only write the final weight in player/playmode. In editor, we are blending to the appropriate defaults
|
|
// the last mixer in the list is the final blend, since the list is composed post-order.
|
|
if (Application.isPlaying)
|
|
m_Output.SetWeight(weight);
|
|
}
|
|
}
|
|
}
|