Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,657 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace UnityEditor.Timeline
|
||||
{
|
||||
// Utility class for editing animation clips from serialized properties
|
||||
static class CurveEditUtility
|
||||
{
|
||||
public static bool IsRotationKey(EditorCurveBinding binding)
|
||||
{
|
||||
return binding.propertyName.Contains("localEulerAnglesRaw");
|
||||
}
|
||||
|
||||
public static void AddKey(AnimationClip clip, EditorCurveBinding sourceBinding, SerializedProperty prop, double time)
|
||||
{
|
||||
if (sourceBinding.isPPtrCurve)
|
||||
{
|
||||
AddObjectKey(clip, sourceBinding, prop, time);
|
||||
}
|
||||
else if (IsRotationKey(sourceBinding))
|
||||
{
|
||||
AddRotationKey(clip, sourceBinding, prop, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddFloatKey(clip, sourceBinding, prop, time);
|
||||
}
|
||||
}
|
||||
|
||||
static void AddObjectKey(AnimationClip clip, EditorCurveBinding sourceBinding, SerializedProperty prop, double time)
|
||||
{
|
||||
if (prop.propertyType != SerializedPropertyType.ObjectReference)
|
||||
return;
|
||||
|
||||
ObjectReferenceKeyframe[] curve = null;
|
||||
var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
|
||||
var curveIndex = Array.IndexOf(info.objectBindings, sourceBinding);
|
||||
if (curveIndex >= 0)
|
||||
{
|
||||
curve = info.objectCurves[curveIndex];
|
||||
|
||||
// where in the array does the evaluation land?
|
||||
var evalIndex = EvaluateIndex(curve, (float)time);
|
||||
|
||||
if (KeyCompare(curve[evalIndex].time, (float)time, clip.frameRate) == 0)
|
||||
{
|
||||
curve[evalIndex].value = prop.objectReferenceValue;
|
||||
}
|
||||
// check the next key (always return the minimum value)
|
||||
else if (evalIndex < curve.Length - 1 && KeyCompare(curve[evalIndex + 1].time, (float)time, clip.frameRate) == 0)
|
||||
{
|
||||
curve[evalIndex + 1].value = prop.objectReferenceValue;
|
||||
}
|
||||
// resize the array
|
||||
else
|
||||
{
|
||||
if (time > curve[0].time)
|
||||
evalIndex++;
|
||||
var key = new ObjectReferenceKeyframe();
|
||||
key.time = (float)time;
|
||||
key.value = prop.objectReferenceValue;
|
||||
ArrayUtility.Insert(ref curve, evalIndex, key);
|
||||
}
|
||||
}
|
||||
else // curve doesn't exist, add it
|
||||
{
|
||||
curve = new ObjectReferenceKeyframe[1];
|
||||
curve[0].time = (float)time;
|
||||
curve[0].value = prop.objectReferenceValue;
|
||||
}
|
||||
|
||||
AnimationUtility.SetObjectReferenceCurve(clip, sourceBinding, curve);
|
||||
EditorUtility.SetDirty(clip);
|
||||
}
|
||||
|
||||
static void AddRotationKey(AnimationClip clip, EditorCurveBinding sourceBind, SerializedProperty prop, double time)
|
||||
{
|
||||
if (prop.propertyType != SerializedPropertyType.Quaternion)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var updateCurves = new List<AnimationCurve>();
|
||||
var updateBindings = new List<EditorCurveBinding>();
|
||||
|
||||
var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
|
||||
for (var i = 0; i < info.bindings.Length; i++)
|
||||
{
|
||||
if (sourceBind.type != info.bindings[i].type)
|
||||
continue;
|
||||
|
||||
if (info.bindings[i].propertyName.Contains("localEuler"))
|
||||
{
|
||||
updateBindings.Add(info.bindings[i]);
|
||||
updateCurves.Add(info.curves[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// use this instead of serialized properties because the editor will attempt to maintain
|
||||
// correct localeulers
|
||||
var eulers = ((Transform)prop.serializedObject.targetObject).localEulerAngles;
|
||||
if (updateBindings.Count == 0)
|
||||
{
|
||||
var propName = AnimationWindowUtility.GetPropertyGroupName(sourceBind.propertyName);
|
||||
updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".x"));
|
||||
updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".y"));
|
||||
updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".z"));
|
||||
|
||||
var curveX = new AnimationCurve();
|
||||
var curveY = new AnimationCurve();
|
||||
var curveZ = new AnimationCurve();
|
||||
AddKeyFrameToCurve(curveX, (float)time, clip.frameRate, eulers.x, false);
|
||||
AddKeyFrameToCurve(curveY, (float)time, clip.frameRate, eulers.y, false);
|
||||
AddKeyFrameToCurve(curveZ, (float)time, clip.frameRate, eulers.z, false);
|
||||
|
||||
updateCurves.Add(curveX);
|
||||
updateCurves.Add(curveY);
|
||||
updateCurves.Add(curveZ);
|
||||
}
|
||||
|
||||
for (var i = 0; i < updateBindings.Count; i++)
|
||||
{
|
||||
var c = updateBindings[i].propertyName.Last();
|
||||
var value = eulers.x;
|
||||
if (c == 'y') value = eulers.y;
|
||||
else if (c == 'z') value = eulers.z;
|
||||
AddKeyFrameToCurve(updateCurves[i], (float)time, clip.frameRate, value, false);
|
||||
}
|
||||
|
||||
UpdateEditorCurves(clip, updateBindings, updateCurves);
|
||||
}
|
||||
|
||||
// Add a floating point curve key
|
||||
static void AddFloatKey(AnimationClip clip, EditorCurveBinding sourceBind, SerializedProperty prop, double time)
|
||||
{
|
||||
var updateCurves = new List<AnimationCurve>();
|
||||
var updateBindings = new List<EditorCurveBinding>();
|
||||
|
||||
var updated = false;
|
||||
var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
|
||||
for (var i = 0; i < info.bindings.Length; i++)
|
||||
{
|
||||
var binding = info.bindings[i];
|
||||
if (binding.type != sourceBind.type)
|
||||
continue;
|
||||
|
||||
SerializedProperty valProp = null;
|
||||
var curve = info.curves[i];
|
||||
|
||||
// perfect match on property path, editting a float
|
||||
if (prop.propertyPath.Equals(binding.propertyName))
|
||||
{
|
||||
valProp = prop;
|
||||
}
|
||||
// this is a child object
|
||||
else if (binding.propertyName.Contains(prop.propertyPath))
|
||||
{
|
||||
valProp = prop.serializedObject.FindProperty(binding.propertyName);
|
||||
}
|
||||
|
||||
if (valProp != null)
|
||||
{
|
||||
var value = GetKeyValue(valProp);
|
||||
if (!float.IsNaN(value)) // Nan indicates an error retrieving the property value
|
||||
{
|
||||
updated = true;
|
||||
AddKeyFrameToCurve(curve, (float)time, clip.frameRate, value, valProp.propertyType == SerializedPropertyType.Boolean);
|
||||
updateCurves.Add(curve);
|
||||
updateBindings.Add(binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Curves don't exist, add them
|
||||
if (!updated)
|
||||
{
|
||||
var propName = AnimationWindowUtility.GetPropertyGroupName(sourceBind.propertyName);
|
||||
if (!prop.hasChildren)
|
||||
{
|
||||
var value = GetKeyValue(prop);
|
||||
if (!float.IsNaN(value))
|
||||
{
|
||||
updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, sourceBind.propertyName));
|
||||
var curve = new AnimationCurve();
|
||||
AddKeyFrameToCurve(curve, (float)time, clip.frameRate, value, prop.propertyType == SerializedPropertyType.Boolean);
|
||||
updateCurves.Add(curve);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// special case because subproperties on color aren't 'visible' so you can't iterate over them
|
||||
if (prop.propertyType == SerializedPropertyType.Color)
|
||||
{
|
||||
updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".r"));
|
||||
updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".g"));
|
||||
updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".b"));
|
||||
updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, propName + ".a"));
|
||||
|
||||
var c = prop.colorValue;
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
var curve = new AnimationCurve();
|
||||
AddKeyFrameToCurve(curve, (float)time, clip.frameRate, c[i], prop.propertyType == SerializedPropertyType.Boolean);
|
||||
updateCurves.Add(curve);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prop = prop.Copy();
|
||||
foreach (SerializedProperty cp in prop)
|
||||
{
|
||||
updateBindings.Add(EditorCurveBinding.FloatCurve(sourceBind.path, sourceBind.type, cp.propertyPath));
|
||||
var curve = new AnimationCurve();
|
||||
AddKeyFrameToCurve(curve, (float)time, clip.frameRate, GetKeyValue(cp), cp.propertyType == SerializedPropertyType.Boolean);
|
||||
updateCurves.Add(curve);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateEditorCurves(clip, updateBindings, updateCurves);
|
||||
}
|
||||
|
||||
public static void RemoveKey(AnimationClip clip, EditorCurveBinding sourceBinding, SerializedProperty prop, double time)
|
||||
{
|
||||
if (sourceBinding.isPPtrCurve)
|
||||
{
|
||||
RemoveObjectKey(clip, sourceBinding, time);
|
||||
}
|
||||
else if (IsRotationKey(sourceBinding))
|
||||
{
|
||||
RemoveRotationKey(clip, sourceBinding, prop, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveFloatKey(clip, sourceBinding, prop, time);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveObjectKey(AnimationClip clip, EditorCurveBinding sourceBinding, double time)
|
||||
{
|
||||
var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
|
||||
var curveIndex = Array.IndexOf(info.objectBindings, sourceBinding);
|
||||
if (curveIndex >= 0)
|
||||
{
|
||||
var curve = info.objectCurves[curveIndex];
|
||||
var evalIndex = GetKeyframeAtTime(curve, (float)time, clip.frameRate);
|
||||
if (evalIndex >= 0)
|
||||
{
|
||||
ArrayUtility.RemoveAt(ref curve, evalIndex);
|
||||
AnimationUtility.SetObjectReferenceCurve(clip, sourceBinding, curve.Length == 0 ? null : curve);
|
||||
EditorUtility.SetDirty(clip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetObjectKeyCount(AnimationClip clip, EditorCurveBinding sourceBinding)
|
||||
{
|
||||
var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
|
||||
var curveIndex = Array.IndexOf(info.objectBindings, sourceBinding);
|
||||
if (curveIndex >= 0)
|
||||
{
|
||||
var curve = info.objectCurves[curveIndex];
|
||||
return curve.Length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void RemoveRotationKey(AnimationClip clip, EditorCurveBinding sourceBind, SerializedProperty prop, double time)
|
||||
{
|
||||
if (prop.propertyType != SerializedPropertyType.Quaternion)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var updateCurves = new List<AnimationCurve>();
|
||||
var updateBindings = new List<EditorCurveBinding>();
|
||||
|
||||
var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
|
||||
for (var i = 0; i < info.bindings.Length; i++)
|
||||
{
|
||||
if (sourceBind.type != info.bindings[i].type)
|
||||
continue;
|
||||
|
||||
if (info.bindings[i].propertyName.Contains("localEuler"))
|
||||
{
|
||||
updateBindings.Add(info.bindings[i]);
|
||||
updateCurves.Add(info.curves[i]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var c in updateCurves)
|
||||
{
|
||||
RemoveKeyFrameFromCurve(c, (float)time, clip.frameRate);
|
||||
}
|
||||
|
||||
UpdateEditorCurves(clip, updateBindings, updateCurves);
|
||||
}
|
||||
|
||||
// Removes the float keys from curves
|
||||
static void RemoveFloatKey(AnimationClip clip, EditorCurveBinding sourceBind, SerializedProperty prop, double time)
|
||||
{
|
||||
var updateCurves = new List<AnimationCurve>();
|
||||
var updateBindings = new List<EditorCurveBinding>();
|
||||
|
||||
var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
|
||||
for (var i = 0; i < info.bindings.Length; i++)
|
||||
{
|
||||
var binding = info.bindings[i];
|
||||
if (binding.type != sourceBind.type)
|
||||
continue;
|
||||
|
||||
SerializedProperty valProp = null;
|
||||
var curve = info.curves[i];
|
||||
|
||||
// perfect match on property path, editting a float
|
||||
if (prop.propertyPath.Equals(binding.propertyName))
|
||||
{
|
||||
valProp = prop;
|
||||
}
|
||||
// this is a child object
|
||||
else if (binding.propertyName.Contains(prop.propertyPath))
|
||||
{
|
||||
valProp = prop.serializedObject.FindProperty(binding.propertyName);
|
||||
}
|
||||
if (valProp != null)
|
||||
{
|
||||
RemoveKeyFrameFromCurve(curve, (float)time, clip.frameRate);
|
||||
updateCurves.Add(curve);
|
||||
updateBindings.Add(binding);
|
||||
}
|
||||
}
|
||||
|
||||
// update the curve. Do this last to not mess with the curve caches we are iterating over
|
||||
UpdateEditorCurves(clip, updateBindings, updateCurves);
|
||||
}
|
||||
|
||||
static void UpdateEditorCurve(AnimationClip clip, EditorCurveBinding binding, AnimationCurve curve)
|
||||
{
|
||||
if (curve.keys.Length == 0)
|
||||
AnimationUtility.SetEditorCurve(clip, binding, null);
|
||||
else
|
||||
AnimationUtility.SetEditorCurve(clip, binding, curve);
|
||||
}
|
||||
|
||||
static void UpdateEditorCurves(AnimationClip clip, List<EditorCurveBinding> bindings, List<AnimationCurve> curves)
|
||||
{
|
||||
if (curves.Count == 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < curves.Count; i++)
|
||||
{
|
||||
UpdateEditorCurve(clip, bindings[i], curves[i]);
|
||||
}
|
||||
EditorUtility.SetDirty(clip);
|
||||
}
|
||||
|
||||
public static void RemoveCurves(AnimationClip clip, SerializedProperty prop)
|
||||
{
|
||||
if (clip == null || prop == null)
|
||||
return;
|
||||
|
||||
var toRemove = new List<EditorCurveBinding>();
|
||||
var info = AnimationClipCurveCache.Instance.GetCurveInfo(clip);
|
||||
for (var i = 0; i < info.bindings.Length; i++)
|
||||
{
|
||||
var binding = info.bindings[i];
|
||||
|
||||
// check if we match directly, or with a child object
|
||||
if (prop.propertyPath.Equals(binding.propertyName) || binding.propertyName.Contains(prop.propertyPath))
|
||||
{
|
||||
toRemove.Add(binding);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < toRemove.Count; i++)
|
||||
{
|
||||
AnimationUtility.SetEditorCurve(clip, toRemove[i], null);
|
||||
}
|
||||
}
|
||||
|
||||
// adds a stepped key frame to the given curve
|
||||
public static void AddKeyFrameToCurve(AnimationCurve curve, float time, float framerate, float value, bool stepped)
|
||||
{
|
||||
var key = new Keyframe();
|
||||
|
||||
bool add = true;
|
||||
var keyIndex = GetKeyframeAtTime(curve, time, framerate);
|
||||
if (keyIndex != -1)
|
||||
{
|
||||
add = false;
|
||||
key = curve[keyIndex]; // retain the tangents and mode
|
||||
curve.RemoveKey(keyIndex);
|
||||
}
|
||||
|
||||
key.value = value;
|
||||
key.time = GetKeyTime(time, framerate);
|
||||
keyIndex = curve.AddKey(key);
|
||||
|
||||
if (stepped)
|
||||
{
|
||||
AnimationUtility.SetKeyBroken(curve, keyIndex, stepped);
|
||||
AnimationUtility.SetKeyLeftTangentMode(curve, keyIndex, AnimationUtility.TangentMode.Constant);
|
||||
AnimationUtility.SetKeyRightTangentMode(curve, keyIndex, AnimationUtility.TangentMode.Constant);
|
||||
key.outTangent = Mathf.Infinity;
|
||||
key.inTangent = Mathf.Infinity;
|
||||
}
|
||||
else if (add)
|
||||
{
|
||||
AnimationUtility.SetKeyLeftTangentMode(curve, keyIndex, AnimationUtility.TangentMode.ClampedAuto);
|
||||
AnimationUtility.SetKeyRightTangentMode(curve, keyIndex, AnimationUtility.TangentMode.ClampedAuto);
|
||||
}
|
||||
|
||||
if (keyIndex != -1 && !stepped)
|
||||
{
|
||||
AnimationUtility.UpdateTangentsFromModeSurrounding(curve, keyIndex);
|
||||
AnimationUtility.SetKeyBroken(curve, keyIndex, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Removes a keyframe at the given time from the animation curve
|
||||
public static bool RemoveKeyFrameFromCurve(AnimationCurve curve, float time, float framerate)
|
||||
{
|
||||
var keyIndex = GetKeyframeAtTime(curve, time, framerate);
|
||||
if (keyIndex == -1)
|
||||
return false;
|
||||
|
||||
curve.RemoveKey(keyIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
// gets the value of the key
|
||||
public static float GetKeyValue(SerializedProperty prop)
|
||||
{
|
||||
switch (prop.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.Integer:
|
||||
return prop.intValue;
|
||||
case SerializedPropertyType.Boolean:
|
||||
return prop.boolValue ? 1.0f : 0.0f;
|
||||
case SerializedPropertyType.Float:
|
||||
return prop.floatValue;
|
||||
default:
|
||||
Debug.LogError("Could not convert property type " + prop.propertyType.ToString() + " to float");
|
||||
break;
|
||||
}
|
||||
return float.NaN;
|
||||
}
|
||||
|
||||
public static void SetFromKeyValue(SerializedProperty prop, float keyValue)
|
||||
{
|
||||
switch (prop.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.Float:
|
||||
{
|
||||
prop.floatValue = keyValue;
|
||||
return;
|
||||
}
|
||||
case SerializedPropertyType.Integer:
|
||||
{
|
||||
prop.intValue = (int)keyValue;
|
||||
return;
|
||||
}
|
||||
case SerializedPropertyType.Boolean:
|
||||
{
|
||||
prop.boolValue = Math.Abs(keyValue) > 0.001f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogError("Could not convert float to property type " + prop.propertyType.ToString());
|
||||
}
|
||||
|
||||
// gets the index of the key, -1 if not found
|
||||
public static int GetKeyframeAtTime(AnimationCurve curve, float time, float frameRate)
|
||||
{
|
||||
var range = 0.5f / frameRate;
|
||||
var keys = curve.keys;
|
||||
for (var i = 0; i < keys.Length; i++)
|
||||
{
|
||||
var k = keys[i];
|
||||
if (k.time >= time - range && k.time < time + range)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int GetKeyframeAtTime(ObjectReferenceKeyframe[] curve, float time, float frameRate)
|
||||
{
|
||||
if (curve == null || curve.Length == 0)
|
||||
return -1;
|
||||
|
||||
var range = 0.5f / frameRate;
|
||||
for (var i = 0; i < curve.Length; i++)
|
||||
{
|
||||
var t = curve[i].time;
|
||||
if (t >= time - range && t < time + range)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static float GetKeyTime(float time, float frameRate)
|
||||
{
|
||||
return Mathf.Round(time * frameRate) / frameRate;
|
||||
}
|
||||
|
||||
public static int KeyCompare(float timeA, float timeB, float frameRate)
|
||||
{
|
||||
if (Mathf.Abs(timeA - timeB) <= 0.5f / frameRate)
|
||||
return 0;
|
||||
return timeA < timeB ? -1 : 1;
|
||||
}
|
||||
|
||||
// Evaluates an object (bool curve)
|
||||
public static Object Evaluate(ObjectReferenceKeyframe[] curve, float time)
|
||||
{
|
||||
return curve[EvaluateIndex(curve, time)].value;
|
||||
}
|
||||
|
||||
// returns the index from evaluation
|
||||
public static int EvaluateIndex(ObjectReferenceKeyframe[] curve, float time)
|
||||
{
|
||||
if (curve == null || curve.Length == 0)
|
||||
throw new InvalidOperationException("Can not evaluate a PPtr curve with no entries");
|
||||
|
||||
// clamp conditions
|
||||
if (time <= curve[0].time)
|
||||
return 0;
|
||||
if (time >= curve.Last().time)
|
||||
return curve.Length - 1;
|
||||
|
||||
// binary search
|
||||
var max = curve.Length - 1;
|
||||
var min = 0;
|
||||
while (max - min > 1)
|
||||
{
|
||||
var imid = (min + max) / 2;
|
||||
if (Mathf.Approximately(curve[imid].time, time))
|
||||
return imid;
|
||||
if (curve[imid].time < time)
|
||||
min = imid;
|
||||
else if (curve[imid].time > time)
|
||||
max = imid;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
// Shifts the animation clip so the time start at 0
|
||||
public static void ShiftBySeconds(this AnimationClip clip, float time)
|
||||
{
|
||||
var floatBindings = AnimationUtility.GetCurveBindings(clip);
|
||||
var objectBindings = AnimationUtility.GetObjectReferenceCurveBindings(clip);
|
||||
|
||||
// update the float curves
|
||||
foreach (var bind in floatBindings)
|
||||
{
|
||||
var curve = AnimationUtility.GetEditorCurve(clip, bind);
|
||||
var keys = curve.keys;
|
||||
for (var i = 0; i < keys.Length; i++)
|
||||
keys[i].time += time;
|
||||
curve.keys = keys;
|
||||
AnimationUtility.SetEditorCurve(clip, bind, curve);
|
||||
}
|
||||
|
||||
// update the PPtr curves
|
||||
foreach (var bind in objectBindings)
|
||||
{
|
||||
var curve = AnimationUtility.GetObjectReferenceCurve(clip, bind);
|
||||
for (var i = 0; i < curve.Length; i++)
|
||||
curve[i].time += time;
|
||||
AnimationUtility.SetObjectReferenceCurve(clip, bind, curve);
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(clip);
|
||||
}
|
||||
|
||||
public static void ScaleTime(this AnimationClip clip, float scale)
|
||||
{
|
||||
var floatBindings = AnimationUtility.GetCurveBindings(clip);
|
||||
var objectBindings = AnimationUtility.GetObjectReferenceCurveBindings(clip);
|
||||
|
||||
// update the float curves
|
||||
foreach (var bind in floatBindings)
|
||||
{
|
||||
var curve = AnimationUtility.GetEditorCurve(clip, bind);
|
||||
var keys = curve.keys;
|
||||
for (var i = 0; i < keys.Length; i++)
|
||||
keys[i].time *= scale;
|
||||
curve.keys = keys.OrderBy(x => x.time).ToArray();
|
||||
AnimationUtility.SetEditorCurve(clip, bind, curve);
|
||||
}
|
||||
|
||||
// update the PPtr curves
|
||||
foreach (var bind in objectBindings)
|
||||
{
|
||||
var curve = AnimationUtility.GetObjectReferenceCurve(clip, bind);
|
||||
for (var i = 0; i < curve.Length; i++)
|
||||
curve[i].time *= scale;
|
||||
curve = curve.OrderBy(x => x.time).ToArray();
|
||||
AnimationUtility.SetObjectReferenceCurve(clip, bind, curve);
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(clip);
|
||||
}
|
||||
|
||||
// Creates an opposing blend curve that matches the given curve to make sure the result is normalized
|
||||
public static AnimationCurve CreateMatchingCurve(AnimationCurve curve)
|
||||
{
|
||||
Keyframe[] keys = curve.keys;
|
||||
|
||||
for (var i = 0; i != keys.Length; i++)
|
||||
{
|
||||
if (!Single.IsPositiveInfinity(keys[i].inTangent))
|
||||
keys[i].inTangent = -keys[i].inTangent;
|
||||
if (!Single.IsPositiveInfinity(keys[i].outTangent))
|
||||
keys[i].outTangent = -keys[i].outTangent;
|
||||
keys[i].value = 1.0f - keys[i].value;
|
||||
}
|
||||
return new AnimationCurve(keys);
|
||||
}
|
||||
|
||||
// Sanitizes the keys on an animation to force the property to be normalized
|
||||
public static Keyframe[] SanitizeCurveKeys(Keyframe[] keys, bool easeIn)
|
||||
{
|
||||
if (keys.Length < 2)
|
||||
{
|
||||
if (easeIn)
|
||||
keys = new[] { new Keyframe(0, 0), new Keyframe(1, 1) };
|
||||
else
|
||||
keys = new[] { new Keyframe(0, 1), new Keyframe(1, 0) };
|
||||
}
|
||||
else if (easeIn)
|
||||
{
|
||||
keys[0].time = 0;
|
||||
keys[keys.Length - 1].time = 1;
|
||||
keys[keys.Length - 1].value = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
keys[0].time = 0;
|
||||
keys[0].value = 1;
|
||||
keys[keys.Length - 1].time = 1;
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue