导入角色动画,和增加角色控制

This commit is contained in:
2025-12-11 19:30:20 +08:00
parent a60a92e7ba
commit 7775fa30bb
1452 changed files with 592217 additions and 42573 deletions

View File

@@ -0,0 +1,56 @@
// Designed by KINEMATION, 2025.
using KINEMATION.KAnimationCore.Runtime.Attributes;
using KINEMATION.KAnimationCore.Runtime.Rig;
using System.Collections.Generic;
using UnityEngine;
namespace KINEMATION.MagicBlend.Runtime
{
public enum MagicBlendOutType
{
DoNotBlendOut,
AutoBlendOut,
AutoBlendOutToPreviousAsset
}
public class MagicBlendAsset : ScriptableObject, IRigProvider
{
[Header("Rig")]
public KRig rigAsset;
[Header("Blending")]
[Min(0f)] public float blendTime = 0.15f;
public AnimationCurve blendCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
[Header("Poses")]
public AnimationClip basePose;
public AnimationClip overlayPose;
public List<OverrideOverlay> overrideOverlays = new List<OverrideOverlay>();
[Min(0f)] public float overlaySpeed = 1f;
[Tooltip("If Overlay is static or not.")]
public bool isAnimation = false;
public MagicBlendOutType blendOutType = MagicBlendOutType.DoNotBlendOut;
[Unfold] public List<LayeredBlend> layeredBlends = new List<LayeredBlend>();
[Range(0f, 1f)] public float globalWeight = 1f;
public KRig GetRigAsset()
{
return rigAsset;
}
public bool HasOverrides()
{
if (overrideOverlays.Count == 0) return false;
foreach (var overlay in overrideOverlays) if (overlay.overlay == null) return false;
return true;
}
public KRigElement[] GetHierarchy()
{
return rigAsset == null ? null : rigAsset.GetHierarchy();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cea8c2a1237b4b5b8bbfd16a4f12cc26
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: a497183ade831dc4aa44bf44b5ce27b8, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,192 @@
// Designed by KINEMATION, 2025.
using KINEMATION.KAnimationCore.Runtime.Core;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Animations;
namespace KINEMATION.MagicBlend.Runtime
{
// Processes base locomotion pose.
public struct PoseJob : IAnimationJob
{
[ReadOnly] public bool alwaysAnimate;
[ReadOnly] public bool readPose;
[ReadOnly] public TransformSceneHandle root;
public NativeArray<BlendStreamAtom> atoms;
public void ProcessAnimation(AnimationStream stream)
{
if (!alwaysAnimate && !readPose)
{
return;
}
KTransform rootTransform = new KTransform()
{
rotation = root.GetRotation(stream),
position = root.GetPosition(stream)
};
int num = atoms.Length;
for (int i = 0; i < num; i++)
{
var atom = atoms[i];
KTransform atomTransform = new KTransform()
{
position = atom.handle.GetPosition(stream),
rotation = atom.handle.GetRotation(stream)
};
atomTransform = rootTransform.GetRelativeTransform(atomTransform, false);
atom.activePose.basePose = atomTransform;
atom.activePose.basePose.position = atom.handle.GetLocalPosition(stream);
atoms[i] = atom;
}
}
public void ProcessRootMotion(AnimationStream stream)
{
}
}
// Processes active stream pose.
public struct OverlayJob : IAnimationJob
{
[ReadOnly] public bool alwaysAnimate;
[ReadOnly] public bool cachePose;
[ReadOnly] public TransformSceneHandle root;
public NativeArray<BlendStreamAtom> atoms;
public void ProcessAnimation(AnimationStream stream)
{
if (!alwaysAnimate && !cachePose)
{
return;
}
KTransform rootTransform = new KTransform()
{
rotation = root.GetRotation(stream),
position = root.GetPosition(stream)
};
int num = atoms.Length;
for (int i = 0; i < num; i++)
{
var atom = atoms[i];
KTransform atomTransform = new KTransform()
{
rotation = atom.handle.GetRotation(stream),
position = atom.handle.GetPosition(stream)
};
atomTransform = rootTransform.GetRelativeTransform(atomTransform, false);
atom.activePose.overlayPose = atomTransform;
atom.activePose.overlayPose.position = atom.handle.GetLocalPosition(stream);
atom.activePose.localOverlayRotation = atom.handle.GetLocalRotation(stream);
atoms[i] = atom;
}
}
public void ProcessRootMotion(AnimationStream stream)
{
}
}
// Processes final layering.
public struct LayeringJob : IAnimationJob
{
[ReadOnly] public float blendWeight;
[ReadOnly] public bool cachePose;
[ReadOnly] public TransformSceneHandle root;
public NativeArray<BlendStreamAtom> atoms;
public void ProcessAnimation(AnimationStream stream)
{
KTransform rootTransform = new KTransform()
{
rotation = root.GetRotation(stream),
position = root.GetPosition(stream)
};
int num = atoms.Length;
// Refresh the current pose.
for (int i = 0; i < num; i++)
{
var atom = atoms[i];
KTransform atomTransform = new KTransform()
{
rotation = atom.handle.GetRotation(stream),
position = atom.handle.GetPosition(stream),
scale = Vector3.one
};
atom.meshStreamPose = rootTransform.GetRelativeTransform(atomTransform, false);
atom.meshStreamPose.position = atom.handle.GetLocalPosition(stream);
atom.activePose.additiveWeight = atom.additiveWeight;
atom.activePose.baseWeight = atom.baseWeight;
atom.activePose.localWeight = atom.localWeight;
atoms[i] = atom;
}
// Apply mesh-space additive.
for (int i = 0; i < num; i++)
{
var atom = atoms[i];
AtomPose blendedPose = atom.GetBlendedAtomPose(blendWeight);
if (cachePose)
{
atom.cachedPose = blendedPose;
atoms[i] = atom;
}
KTransform meshBasePose = blendedPose.basePose;
KTransform meshOverlayPose = blendedPose.overlayPose;
Quaternion localOverlayRotation = blendedPose.localOverlayRotation;
float additiveWeight = blendedPose.additiveWeight;
float baseWeight = blendedPose.baseWeight;
float localWeight = blendedPose.localWeight;
KTransform additive = new KTransform()
{
rotation = atom.meshStreamPose.rotation * Quaternion.Inverse(meshBasePose.rotation),
position = atom.meshStreamPose.position - meshBasePose.position
};
Quaternion rotation = additive.rotation * meshOverlayPose.rotation;
// Blend additive.
rotation = Quaternion.Slerp(meshOverlayPose.rotation, rotation, additiveWeight);
// Blend locomotion pose.
rotation = Quaternion.Slerp(atom.meshStreamPose.rotation, rotation, baseWeight);
// Convert to world space.
rotation = rootTransform.rotation * rotation;
Vector3 position = meshOverlayPose.position + additive.position * additiveWeight;
position = Vector3.Lerp(atom.meshStreamPose.position, position, baseWeight);
atom.handle.SetRotation(stream, rotation);
rotation = Quaternion.Slerp(atom.handle.GetLocalRotation(stream), localOverlayRotation, localWeight);
atom.handle.SetLocalRotation(stream, rotation);
position = Vector3.Lerp(position, meshOverlayPose.position, localWeight);
atom.handle.SetLocalPosition(stream, position);
}
}
public void ProcessRootMotion(AnimationStream stream)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d94da5f3f9dd1584d95bc242f712151a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,151 @@
// Designed by KINEMATION, 2025.
using KINEMATION.KAnimationCore.Runtime.Core;
using KINEMATION.KAnimationCore.Runtime.Rig;
using System;
using System.Collections.Generic;
using KINEMATION.KAnimationCore.Runtime.Attributes;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
namespace KINEMATION.MagicBlend.Runtime
{
public struct AtomPose
{
public KTransform basePose;
public KTransform overlayPose;
public Quaternion localOverlayRotation;
public float baseWeight;
public float additiveWeight;
public float localWeight;
public static AtomPose Lerp(AtomPose a, AtomPose b, float alpha)
{
AtomPose outPose = new AtomPose();
outPose.basePose = KTransform.Lerp(a.basePose, b.basePose, alpha);
outPose.overlayPose = KTransform.Lerp(a.overlayPose, b.overlayPose, alpha);
outPose.localOverlayRotation = Quaternion.Slerp(a.localOverlayRotation, b.localOverlayRotation, alpha);
outPose.additiveWeight = Mathf.Lerp(a.additiveWeight, b.additiveWeight, alpha);
outPose.baseWeight = Mathf.Lerp(a.baseWeight, b.baseWeight, alpha);
outPose.localWeight = Mathf.Lerp(a.localWeight, b.localWeight, alpha);
return outPose;
}
}
public struct BlendStreamAtom
{
[Unity.Collections.ReadOnly] public TransformStreamHandle handle;
[Unity.Collections.ReadOnly] public float baseWeight;
[Unity.Collections.ReadOnly] public float additiveWeight;
[Unity.Collections.ReadOnly] public float localWeight;
public KTransform meshStreamPose;
public AtomPose activePose;
public AtomPose cachedPose;
public AtomPose GetBlendedAtomPose(float blendWeight)
{
return AtomPose.Lerp(cachedPose, activePose, blendWeight);
}
}
[Serializable]
public struct LayeredBlend
{
[CustomElementChainDrawer(false, true)]
public KRigElementChain layer;
[Range(0f, 1f)] public float baseWeight;
[Range(0f, 1f)] public float additiveWeight;
[Range(0f, 1f)] public float localWeight;
}
[Serializable]
public struct OverrideOverlay
{
public AnimationClip overlay;
public AvatarMask mask;
[Range(0f, 1f)] public float weight;
}
public class MagicBlendLibrary
{
public static NativeArray<BlendStreamAtom> SetupBlendAtoms(Animator animator, KRigComponent rigComponent)
{
var bones = rigComponent.GetRigTransforms();
int num = bones.Length;
var blendAtoms = new NativeArray<BlendStreamAtom>(num, Allocator.Persistent);
for (int i = 0; i < num; i++)
{
Transform bone = bones[i];
blendAtoms[i] = new BlendStreamAtom()
{
handle = animator.BindStreamTransform(bone)
};
}
return blendAtoms;
}
public static void ConnectPose(AnimationScriptPlayable playable, PlayableGraph graph, AnimationClip pose,
float speed = 0f)
{
if (playable.GetInput(0).IsValid())
{
playable.DisconnectInput(0);
}
var posePlayable = AnimationClipPlayable.Create(graph, pose);
posePlayable.SetSpeed(speed);
posePlayable.SetApplyFootIK(false);
playable.ConnectInput(0, posePlayable, 0, 1f);
}
public static void ConnectOverlays(AnimationScriptPlayable playable, PlayableGraph graph,
AnimationClip pose, List<OverrideOverlay> overrides, float speed = 0f)
{
if (playable.GetInput(0).IsValid())
{
playable.DisconnectInput(0);
}
if (overrides == null || overrides.Count == 0)
{
ConnectPose(playable, graph, pose, speed);
return;
}
var mixer = AnimationLayerMixerPlayable.Create(graph);
var overlayPlayable = AnimationClipPlayable.Create(graph, pose);
overlayPlayable.SetDuration(pose.length);
overlayPlayable.SetSpeed(speed);
overlayPlayable.SetApplyFootIK(false);
mixer.AddInput(overlayPlayable, 0, 1f);
foreach (var overlayOverride in overrides)
{
var posePlayable = AnimationClipPlayable.Create(graph, overlayOverride.overlay);
posePlayable.SetDuration(overlayOverride.overlay.length);
posePlayable.SetSpeed(speed);
posePlayable.SetApplyFootIK(false);
var index = mixer.AddInput(posePlayable, 0, overlayOverride.weight);
var mask = overlayOverride.mask == null ? new AvatarMask() : overlayOverride.mask;
mixer.SetLayerMaskFromAvatarMask((uint) index, mask);
}
playable.ConnectInput(0, mixer, 0, 1f);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ea61816638094afd9e1b1b9bf47e15cc
timeCreated: 1722703296

View File

@@ -0,0 +1,31 @@
// Designed by KINEMATION, 2025.
using UnityEngine;
namespace KINEMATION.MagicBlend.Runtime
{
public class MagicBlendState : StateMachineBehaviour
{
[SerializeField] private MagicBlendAsset magicBlendAsset;
private bool _isInitialized;
private MagicBlending _magicBlending;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (!_isInitialized)
{
_magicBlending = animator.gameObject.GetComponent<MagicBlending>();
if (_magicBlending == null) return;
_isInitialized = true;
}
float blendTime = animator.GetAnimatorTransitionInfo(layerIndex).duration;
_magicBlending.UpdateMagicBlendAsset(magicBlendAsset, new MagicBlendingData()
{
blendTime = blendTime,
useLinear = true
});
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 004dd898c28047b78e17ce086af4bdd2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 6fd4d99d3a1edc7408fe599214be6059, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,553 @@
// Designed by KINEMATION, 2025.
using System;
using KINEMATION.KAnimationCore.Runtime.Rig;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Experimental.Animations;
using UnityEngine.Playables;
namespace KINEMATION.MagicBlend.Runtime
{
public struct MagicBlendingData
{
public MagicBlendAsset blendAsset;
public AnimationClip overlayPose;
public float overlaySpeed;
public float blendTime;
public bool useLinear;
public static MagicBlendingData Empty = new MagicBlendingData()
{
overlayPose = null,
blendTime = -1f,
useLinear = false,
};
}
[HelpURL("https://kinemation.gitbook.io/magic-blend-documentation/")]
public class MagicBlending : MonoBehaviour
{
public PlayableGraph playableGraph;
public MagicBlendAsset BlendAsset => blendAsset;
[Tooltip("This asset controls the blending weights.")]
[SerializeField] private MagicBlendAsset blendAsset;
[Tooltip("Will update weights every frame.")]
[SerializeField] private bool forceUpdateWeights = true;
[Tooltip("Will process the Overlay pose. Keep it on most of the time.")]
[SerializeField] private bool alwaysAnimatePoses = true;
private const ushort PlayableSortingPriority = 900;
private Animator _animator;
private KRigComponent _rigComponent;
private AnimationLayerMixerPlayable _playableMixer;
private NativeArray<BlendStreamAtom> _atoms;
private PoseJob _poseJob;
private OverlayJob _overlayJob;
private LayeringJob _layeringJob;
private AnimationScriptPlayable _poseJobPlayable;
private AnimationScriptPlayable _overlayJobPlayable;
private AnimationScriptPlayable _layeringJobPlayable;
private bool _isInitialized;
private float _blendPlayback = 1f;
private float _blendTime = 0f;
private AnimationCurve _blendCurve;
private MagicBlendingData _blendData;
private MagicBlendingData _desiredBlendData;
private MagicBlendAsset _previousBlendAsset;
private List<int> _blendedIndexes = new List<int>();
private Dictionary<string, int> _hierarchyMap;
private RuntimeAnimatorController _cachedController;
private AnimationPlayableOutput _magicBlendOutput;
private bool _forceBlendOut;
private bool _wasAnimatorActive;
public void UpdateMagicBlendAsset(MagicBlendAsset newAsset)
{
UpdateMagicBlendAsset(newAsset, MagicBlendingData.Empty);
}
public void UpdateMagicBlendAsset(MagicBlendAsset newAsset, MagicBlendingData blendingData,
bool ignoreBlending = false)
{
if (newAsset == null || !_isInitialized)
{
return;
}
_desiredBlendData = blendingData;
_desiredBlendData.blendAsset = newAsset;
bool useBlending = blendingData.blendTime > 0f || newAsset.blendTime > 0f;
if (useBlending && !ignoreBlending)
{
_layeringJob.cachePose = true;
_layeringJobPlayable.SetJobData(_layeringJob);
return;
}
_layeringJob.blendWeight = 1f;
_layeringJobPlayable.SetJobData(_layeringJob);
SetNewAsset();
if (!alwaysAnimatePoses)
{
_poseJob.readPose = true;
_overlayJob.cachePose = true;
_poseJobPlayable.SetJobData(_poseJob);
_overlayJobPlayable.SetJobData(_overlayJob);
}
}
/// <summary>
/// Sets a new blending asset.
/// </summary>
/// <param name="newAsset">Blending asset.</param>
/// <param name="overlayOverride">Override clip.</param>>
/// <param name="useBlending">Whether we need blending.</param>
/// <param name="blendTime">Blending time in seconds.</param>
/// <param name="useCurve">Whether we need curve or linear transition.</param>
[Obsolete("Use the alternative override!")]
public void UpdateMagicBlendAsset(MagicBlendAsset newAsset, bool useBlending = true,
float blendTime = -1f, bool useCurve = true, AnimationClip overlayOverride = null)
{
UpdateMagicBlendAsset(newAsset, new MagicBlendingData()
{
blendTime = blendTime,
useLinear = !useCurve,
overlayPose = overlayOverride
});
}
public void StopMagicBlending()
{
_forceBlendOut = true;
_blendPlayback = 0f;
}
public void SetOverlayTime(float newTime)
{
var overlayPlayable = _overlayJobPlayable.GetInput(0);
if (!overlayPlayable.IsValid()) return;
overlayPlayable.SetTime(newTime);
}
public float GetOverlayTime(bool isNormalized = true)
{
var overlayPlayable = _overlayJobPlayable.GetInput(0);
if (!overlayPlayable.IsValid() || !blendAsset.isAnimation)
{
return 0f;
}
float length = (float) overlayPlayable.GetDuration();
if (Mathf.Approximately(length, 0f))
{
return 0f;
}
float time = (float) overlayPlayable.GetTime();
return isNormalized ? Mathf.Clamp01(time / length) : time;
}
protected virtual void SetProcessJobs(bool isActive)
{
_poseJobPlayable.SetProcessInputs(isActive);
_overlayJobPlayable.SetProcessInputs(isActive);
}
protected virtual void SetNewAsset()
{
_blendData = _desiredBlendData;
if (blendAsset != null && blendAsset.blendOutType == MagicBlendOutType.DoNotBlendOut)
{
_previousBlendAsset = blendAsset;
}
blendAsset = _blendData.blendAsset;
if (_previousBlendAsset == null && blendAsset.blendOutType == MagicBlendOutType.DoNotBlendOut)
{
_previousBlendAsset = blendAsset;
}
if (_blendData.overlayPose == null) _blendData.overlayPose = blendAsset.overlayPose;
_blendCurve = _blendData.useLinear ? null : blendAsset.blendCurve;
_blendTime = _blendData.blendTime > 0f ? _blendData.blendTime : blendAsset.blendTime;
MagicBlendLibrary.ConnectPose(_poseJobPlayable, playableGraph, blendAsset.basePose);
float overlaySpeed = Mathf.Approximately(_blendData.overlaySpeed, 0f)
? blendAsset.overlaySpeed
: _blendData.overlaySpeed;
float speed = blendAsset.isAnimation ? overlaySpeed : 0f;
if (blendAsset.HasOverrides())
{
MagicBlendLibrary.ConnectOverlays(_overlayJobPlayable, playableGraph, _blendData.overlayPose,
blendAsset.overrideOverlays, speed);
}
else
{
MagicBlendLibrary.ConnectPose(_overlayJobPlayable, playableGraph, _blendData.overlayPose, speed);
}
// Reset all weights.
for (int i = 0; i < _hierarchyMap.Count; i++)
{
var atom = _atoms[i];
atom.baseWeight = atom.additiveWeight = atom.localWeight = 0f;
_atoms[i] = atom;
}
// Add indexes which will be blended.
_blendedIndexes.Clear();
foreach (var blend in blendAsset.layeredBlends)
{
foreach (var element in blend.layer.elementChain)
{
_hierarchyMap.TryGetValue(element.name, out int index);
_blendedIndexes.Add(index);
}
}
// Active the jobs processing.
SetProcessJobs(true);
_forceBlendOut = false;
// Update weights.
UpdateBlendWeights();
}
protected virtual void BuildMagicMixer()
{
if (!_playableMixer.IsValid())
{
_playableMixer = AnimationLayerMixerPlayable.Create(playableGraph, 3);
InitializeJobs();
_playableMixer.ConnectInput(0, _poseJobPlayable, 0, 1f);
_playableMixer.ConnectInput(1, _overlayJobPlayable, 0, 1f);
_playableMixer.ConnectInput(2, _layeringJobPlayable, 0, 1f);
}
_magicBlendOutput.SetSourcePlayable(_playableMixer);
_magicBlendOutput.SetSortingOrder(PlayableSortingPriority);
int num = playableGraph.GetOutputCount();
int animatorPlayableIndex = 0;
for (int i = 0; i < num; i++)
{
var sourcePlayable = playableGraph.GetOutput(i).GetSourcePlayable();
if (sourcePlayable.GetPlayableType() != typeof(AnimatorControllerPlayable))
{
continue;
}
animatorPlayableIndex = i;
}
var animatorOutput = playableGraph.GetOutput(animatorPlayableIndex);
var animatorPlayable = animatorOutput.GetSourcePlayable();
if (_layeringJobPlayable.IsValid())
{
_layeringJobPlayable.DisconnectInput(0);
}
_layeringJobPlayable.ConnectInput(0, animatorPlayable, 0, 1f);
if (blendAsset != null)
{
UpdateMagicBlendAsset(blendAsset, new MagicBlendingData()
{
blendTime = -1f,
});
}
}
protected virtual void InitializeMagicBlending()
{
playableGraph = _animator.playableGraph;
_atoms = MagicBlendLibrary.SetupBlendAtoms(_animator, _rigComponent);
_magicBlendOutput = AnimationPlayableOutput.Create(playableGraph, "MagicBlendOutput", _animator);
_isInitialized = true;
BuildMagicMixer();
playableGraph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
playableGraph.Play();
}
private void InitializeJobs()
{
var rootSceneHandle = _animator.BindSceneTransform(_animator.transform);
_poseJob = new PoseJob()
{
atoms = _atoms,
root = rootSceneHandle,
alwaysAnimate = alwaysAnimatePoses,
readPose = false
};
_poseJobPlayable = AnimationScriptPlayable.Create(playableGraph, _poseJob, 1);
_overlayJob = new OverlayJob()
{
atoms = _atoms,
root = rootSceneHandle,
alwaysAnimate = alwaysAnimatePoses,
cachePose = false
};
_overlayJobPlayable = AnimationScriptPlayable.Create(playableGraph, _overlayJob, 1);
_layeringJob = new LayeringJob()
{
atoms = _atoms,
root = rootSceneHandle,
blendWeight = 1f,
cachePose = false,
};
_layeringJobPlayable = AnimationScriptPlayable.Create(playableGraph, _layeringJob, 1);
}
private void OnEnable()
{
if(_isInitialized) BuildMagicMixer();
}
private void Start()
{
_animator = GetComponent<Animator>();
_cachedController = _animator.runtimeAnimatorController;
_wasAnimatorActive = _animator.isActiveAndEnabled;
_rigComponent = GetComponentInChildren<KRigComponent>();
_hierarchyMap = new Dictionary<string, int>();
var hierarchy = _rigComponent.GetRigTransforms();
for (int i = 0; i < hierarchy.Length; i++)
{
_hierarchyMap.Add(hierarchy[i].name, i);
}
InitializeMagicBlending();
#if UNITY_EDITOR
_cachedBlendAsset = blendAsset;
#endif
}
protected virtual void UpdateBlendWeights(float globalWeight = 1f)
{
int index = 0;
foreach (var blend in blendAsset.layeredBlends)
{
foreach (var unused in blend.layer.elementChain)
{
int realIndex = _blendedIndexes[index];
var atom = _atoms[realIndex];
atom.baseWeight = blend.baseWeight * blendAsset.globalWeight * globalWeight;
atom.additiveWeight = blend.additiveWeight * blendAsset.globalWeight * globalWeight;
atom.localWeight = blend.localWeight * blendAsset.globalWeight * globalWeight;
_atoms[realIndex] = atom;
index++;
}
}
var overlayPlayable = _overlayJobPlayable.GetInput(0);
int count = overlayPlayable.GetInputCount();
if (count == 0) return;
for (int i = 1; i < count; i++)
{
overlayPlayable.SetInputWeight(i, blendAsset.overrideOverlays[i - 1].weight);
}
}
protected virtual void Update()
{
if (_blendData.blendAsset == null || blendAsset == null) return;
var activeAnimator = _animator.runtimeAnimatorController;
if (_cachedController != activeAnimator || _wasAnimatorActive != _animator.isActiveAndEnabled)
{
BuildMagicMixer();
}
_cachedController = activeAnimator;
_wasAnimatorActive = _animator.isActiveAndEnabled;
if (blendAsset.isAnimation)
{
int count = _overlayJobPlayable.GetInput(0).GetInputCount();
var overlayPlayable = count == 0 ? _overlayJobPlayable.GetInput(0)
: _overlayJobPlayable.GetInput(0).GetInput(0);
if (overlayPlayable.GetTime() >= _blendData.overlayPose.length)
{
if (blendAsset.blendOutType > MagicBlendOutType.DoNotBlendOut)
{
if ((blendAsset.blendOutType == MagicBlendOutType.AutoBlendOut
|| _previousBlendAsset == null))
{
if(!_forceBlendOut) StopMagicBlending();
}
else
{
UpdateMagicBlendAsset(_previousBlendAsset);
}
}
else if(_blendData.overlayPose.isLooping)
{
overlayPlayable.SetTime(0f);
}
}
if (count > 1)
{
for (int i = 1; i < count; i++)
{
var overrideOverlay = _overlayJobPlayable.GetInput(0).GetInput(i);
var overrideClip = blendAsset.overrideOverlays[i - 1].overlay;
if (!overrideClip.isLooping || overrideOverlay.GetTime() < overrideClip.length
|| blendAsset.blendOutType > MagicBlendOutType.DoNotBlendOut)
{
continue;
}
overrideOverlay.SetTime(0f);
}
}
}
float globalWeight = 1f;
if (_forceBlendOut)
{
_blendPlayback = Mathf.Clamp(_blendPlayback + Time.deltaTime, 0f, _blendTime);
float blendOutWeight = _blendPlayback / _blendTime;
globalWeight = 1f - (_blendCurve?.Evaluate(blendOutWeight) ?? blendOutWeight);
}
if (forceUpdateWeights || _forceBlendOut)
{
UpdateBlendWeights(globalWeight);
}
if (Mathf.Approximately(globalWeight, 0f))
{
SetProcessJobs(false);
blendAsset = null;
#if UNITY_EDITOR
_cachedBlendAsset = null;
#endif
}
if (_forceBlendOut || Mathf.Approximately(_blendPlayback, _blendTime)) return;
_blendPlayback = Mathf.Clamp(_blendPlayback + Time.deltaTime, 0f, _blendTime);
float normalizedWeight = _blendTime > 0f ? _blendPlayback / _blendTime : 1f;
_layeringJob.blendWeight = _blendCurve?.Evaluate(normalizedWeight) ?? normalizedWeight;
_layeringJobPlayable.SetJobData(_layeringJob);
}
protected virtual void LateUpdate()
{
if (!alwaysAnimatePoses && _poseJob.readPose)
{
_poseJob.readPose = false;
_overlayJob.cachePose = false;
_poseJobPlayable.SetJobData(_poseJob);
_overlayJobPlayable.SetJobData(_overlayJob);
}
if (_layeringJob.cachePose)
{
SetNewAsset();
_blendPlayback = 0f;
_layeringJob.cachePose = false;
_layeringJob.blendWeight = 0f;
_layeringJobPlayable.SetJobData(_layeringJob);
if (!alwaysAnimatePoses)
{
_poseJob.readPose = true;
_overlayJob.cachePose = true;
_poseJobPlayable.SetJobData(_poseJob);
_overlayJobPlayable.SetJobData(_overlayJob);
}
}
}
protected virtual void OnDestroy()
{
if (playableGraph.IsValid() && playableGraph.IsPlaying())
{
playableGraph.Stop();
}
if (_atoms.IsCreated)
{
_atoms.Dispose();
}
}
public void SetMagicBlendAsset(MagicBlendAsset newAsset)
{
blendAsset = newAsset;
}
#if UNITY_EDITOR
private MagicBlendAsset _cachedBlendAsset;
private void OnValidate()
{
if (!_isInitialized)
{
return;
}
_poseJob.alwaysAnimate = alwaysAnimatePoses;
_overlayJob.alwaysAnimate = alwaysAnimatePoses;
_poseJobPlayable.SetJobData(_poseJob);
_overlayJobPlayable.SetJobData(_overlayJob);
if (_cachedBlendAsset == blendAsset)
{
return;
}
UpdateMagicBlendAsset(blendAsset);
(_cachedBlendAsset, blendAsset) = (blendAsset, _cachedBlendAsset);
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cdf51b00bdc44c699c58a3ed985775d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 50
icon: {fileID: 2800000, guid: 6fd4d99d3a1edc7408fe599214be6059, type: 3}
userData:
assetBundleName:
assetBundleVariant: