10using System.Collections.Generic;
22 public TimelineAsset[]
assets =
new TimelineAsset[0];
35 private void OnValidate() {
36 allBindings = allClips.SelectMany(c => AnimationUtility.GetCurveBindings(c.Value)).
43 [ContextMenu(
"Perform Post Process")]
44 public void PerformPostProcess() {
45 Dictionary<AnimationClip, TimeRange> ranges =
new Dictionary<AnimationClip, TimeRange>();
47 float total = allClips.Count();
50 foreach (var pair
in allClips) {
52 var animClip = pair.Value;
54 EditorUtility.DisplayCancelableProgressBar(
"Post processing clips",
"Processing " + animClip.name, index / total);
57 if (!ranges.TryGetValue(animClip, out range)) {
58 range =
new TimeRange() {
59 start = (float)clip.clipIn,
60 end = (
float)(clip.clipIn + clip.duration)
63 range.start = Mathf.Min(range.start, (
float)clip.clipIn);
64 range.end = Mathf.Max(range.end, (
float)(clip.clipIn + clip.duration));
67 ranges[animClip] = range;
71 foreach (var pair
in allClips) {
73 var animClip = pair.Value;
76 EditorUtility.DisplayCancelableProgressBar(
"Post-processing clips",
"Processing " + animClip.name, index / total);
78 BlendHeadPosition(clip, animClip);
81 CropAnimation(animClip, (
float)clip.clipIn, (
float)(clip.clipIn + clip.duration));
85 AssetDatabase.Refresh();
86 AssetDatabase.SaveAssets();
88 EditorUtility.ClearProgressBar();
92 public void CropAnimation(AnimationClip clip,
float start,
float end) {
93 var bindings = AnimationUtility.GetCurveBindings(clip);
95 foreach (var binding
in bindings) {
96 var curve = AnimationUtility.GetEditorCurve(clip, binding);
97 var cropped = AnimationCurveUtil.GetCropped(curve, start, end, slideToStart:
true);
98 AnimationUtility.SetEditorCurve(clip, binding, cropped);
102 public void BlendHeadPosition(TimelineClip clip, AnimationClip animClip) {
103 var bindings = AnimationUtility.GetCurveBindings(animClip);
105 float startTime = (float)clip.clipIn;
106 float endTime = (
float)(clip.clipIn + clip.duration);
108 var xBinding = bindings.Query().FirstOrNone(b => b.path ==
headPositionPath && b.propertyName ==
"m_LocalPosition.x");
109 var yBinding = bindings.Query().FirstOrNone(b => b.path ==
headPositionPath && b.propertyName ==
"m_LocalPosition.y");
110 var zBinding = bindings.Query().FirstOrNone(b => b.path ==
headPositionPath && b.propertyName ==
"m_LocalPosition.z");
112 if (!xBinding.hasValue || !yBinding.hasValue || !zBinding.hasValue) {
116 xBinding.Match(xB => {
117 yBinding.Match(yB => {
118 zBinding.Match(zB => {
119 bindings =
new EditorCurveBinding[] { xB, yB, zB };
124 for (
int i = 0; i < 3; i++) {
125 var binding = bindings[i];
126 var curve = AnimationUtility.GetEditorCurve(animClip, binding);
128 float startPos = curve.Evaluate(startTime);
129 float endPos = curve.Evaluate(endTime);
137 var keys = curve.keys;
138 for (
int j = 0; j < keys.Length; j++) {
141 float percent = (key.time - startTime) / (endTime - startTime);
142 float offset = Mathf.LerpUnclamped(startOffset, endOffset, percent);
145 curve.MoveKey(j, key);
148 AnimationUtility.SetEditorCurve(animClip, binding, curve);
152 private IEnumerable<KeyValuePair<TimelineClip, AnimationClip>> allClips {
154 foreach (var timeline
in assets) {
155 if (timeline ==
null)
continue;
157 foreach (var track
in timeline.GetOutputTracks()) {
158 var animTrack = track as AnimationTrack;
159 if (animTrack !=
null) {
160 foreach (var clip
in animTrack.GetClips()) {
161 var animClip = clip.animationClip;
162 yield
return new KeyValuePair<TimelineClip, AnimationClip>(clip, animClip);
170 private struct TimeRange {
171 public float start, end;
Vector3 startHeadPosition
bool lerpStartingPosition