796 lines
27 KiB
C#
796 lines
27 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
[CustomEditor(typeof(AnimationHelper))]
|
|
public class AnimationHelperInspector : Editor
|
|
{
|
|
public enum CurveType {POS_X, POS_Y, POS_Z, ROT_X, ROT_Y, ROT_Z };
|
|
const float segLen = 0.1f;
|
|
const float timeStep = 0.02f;
|
|
private const float handleSize = 0.04f;
|
|
private const float pickSize = 0.06f;
|
|
//private Transform trans;
|
|
private AnimationHelper aHelper;
|
|
class PositionData : IComparable<PositionData>
|
|
{
|
|
public PositionData()
|
|
{
|
|
//xKeyId = yKeyId = zKeyId = -1;
|
|
point = Vector3.zero;
|
|
inTan = Vector3.zero;
|
|
outTan = Vector3.zero;
|
|
}
|
|
public Vector3 point;
|
|
public Vector3 inTan;
|
|
public Vector3 outTan;
|
|
public float time;
|
|
//public int xKeyId, yKeyId, zKeyId;
|
|
|
|
public int CompareTo(PositionData other)
|
|
{
|
|
|
|
if (time < other.time)
|
|
return -1;
|
|
else if (time > other.time)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
class AnimationData
|
|
{
|
|
SortedList<float,PositionData> keys = new SortedList<float, PositionData>();
|
|
public Transform trans;
|
|
|
|
public int Count
|
|
{
|
|
get { return keys.Count; }
|
|
}
|
|
|
|
public PositionData this[int i]
|
|
{
|
|
get
|
|
{
|
|
return keys.Values[i];
|
|
}
|
|
set
|
|
{
|
|
keys.Values[i] = value;
|
|
}
|
|
}
|
|
|
|
public void GenerateKeys(AnimationCurve curve)
|
|
{
|
|
for (int i = 0; i < curve.keys.Length; i++)
|
|
{
|
|
Keyframe k = curve.keys[i];
|
|
if (!keys.ContainsKey(k.time))
|
|
{
|
|
PositionData p = new PositionData();
|
|
p.time = k.time;
|
|
keys.Add(k.time, p);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public void CopyKeys(AnimationCurve curve, CurveType type)
|
|
{
|
|
foreach (Keyframe k in curve.keys)
|
|
{
|
|
PositionData data = keys[k.time];
|
|
switch (type)
|
|
{
|
|
case CurveType.POS_X:
|
|
data.point.x = k.value;
|
|
data.inTan.x = k.inTangent;
|
|
data.outTan.x = k.outTangent;
|
|
break;
|
|
case CurveType.POS_Y:
|
|
data.point.y = k.value;
|
|
data.inTan.y = k.inTangent;
|
|
data.outTan.y = k.outTangent;
|
|
break;
|
|
case CurveType.POS_Z:
|
|
data.point.z = k.value;
|
|
data.inTan.z = k.inTangent;
|
|
data.outTan.z = k.outTangent;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool AddMissingKeysToCurve(AnimationCurve curve)
|
|
{
|
|
bool res = false;
|
|
//curve.k
|
|
KeyTimeComparer cmp = new KeyTimeComparer();
|
|
Keyframe k = new Keyframe();
|
|
for (int i = 0; i < keys.Values.Count; i++)
|
|
{
|
|
k.time = keys.Values[i].time;
|
|
if (Array.BinarySearch<Keyframe>(curve.keys, k, cmp) < 0)
|
|
{
|
|
curve.AddKey(k.time, curve.Evaluate(k.time));
|
|
res = true;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
public void TransformToWorld()
|
|
{
|
|
if (trans)
|
|
{
|
|
foreach (KeyValuePair<float, PositionData> k in keys)
|
|
{
|
|
k.Value.inTan = trans.TransformDirection(k.Value.inTan);
|
|
k.Value.outTan = trans.TransformDirection(k.Value.outTan);
|
|
k.Value.point = trans.TransformPoint(k.Value.point);
|
|
}
|
|
|
|
}
|
|
for (int i = 0; i < keys.Count - 1; i++)
|
|
{
|
|
float a = 1f / 3f;
|
|
float timeDiff = this[i + 1].time - this[i].time;
|
|
a *= timeDiff;
|
|
this[i].outTan *= a;
|
|
this[i + 1].inTan *= a;
|
|
}
|
|
}
|
|
|
|
public Vector3 GetWorldPosition(int idx)
|
|
{
|
|
return trans ? trans.TransformPoint(this[idx].point) : this[idx].point;
|
|
}
|
|
|
|
public void SetWorldPosition(int idx, Vector3 pos)
|
|
{
|
|
if (keys.Count <= idx)
|
|
return;
|
|
this[idx].point = trans ? trans.InverseTransformPoint(pos) : pos;
|
|
}
|
|
|
|
public Vector3 GetWorldTangent(int idx)
|
|
{
|
|
Vector3 res = Vector3.zero;
|
|
|
|
return res;
|
|
}
|
|
|
|
public bool InTangentFromWorld(int idx, Vector3 point, out Vector3 outVect)
|
|
{
|
|
outVect = point;
|
|
if (idx - 1 >= 0)
|
|
{
|
|
point = this[idx].point - point;
|
|
float timeDiff = this[idx].time - this[idx - 1].time;
|
|
float a = 1f / 3.0f;
|
|
a *= timeDiff;
|
|
point /= a;
|
|
|
|
if (trans)
|
|
point = trans.transform.InverseTransformDirection(point);
|
|
outVect = point;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool OutTangentFromWorld(int idx, Vector3 point, out Vector3 outVect)
|
|
{
|
|
outVect = point;
|
|
if (idx + 1 < keys.Count)
|
|
{
|
|
point = point - this[idx].point;
|
|
float timeDiff = this[idx + 1].time - this[idx].time;
|
|
float a = 1f / 3.0f;
|
|
a *= timeDiff;
|
|
point /= a;
|
|
|
|
if (trans)
|
|
point = trans.transform.InverseTransformDirection(point);
|
|
outVect = point;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
AnimationData animData;
|
|
// List<PositionData> positionAnim;
|
|
AnimationCurve pxCurve;
|
|
AnimationCurve pyCurve;
|
|
AnimationCurve pzCurve;
|
|
Nullable<EditorCurveBinding> pxBind = null;
|
|
Nullable<EditorCurveBinding> pyBind = null;
|
|
Nullable<EditorCurveBinding> pzBind = null;
|
|
AnimationClip anim;
|
|
|
|
|
|
class KeyTimeComparer : System.Collections.Generic.IComparer<UnityEngine.Keyframe>
|
|
{
|
|
public int Compare(Keyframe x, Keyframe y)
|
|
{
|
|
return (x).time.CompareTo(y.time);
|
|
}
|
|
}
|
|
|
|
private bool AddMissingKeysToCurve(AnimationCurve src, AnimationCurve dest)
|
|
{
|
|
bool res = false;
|
|
KeyTimeComparer cmp = new KeyTimeComparer();
|
|
for (int i=0; i<src.length; i++)
|
|
{
|
|
if (Array.BinarySearch<Keyframe>(dest.keys, src[i], cmp) < 0)
|
|
{
|
|
dest.AddKey(src[i].time, dest.Evaluate(src[i].time));
|
|
res = true;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
private void EnsureKeysIntegrity()
|
|
{
|
|
/*
|
|
bool xChanged = false;
|
|
bool yChanged = false;
|
|
bool zChanged = false;
|
|
yChanged |= AddMissingKeysToCurve(pxCurve, pyCurve);
|
|
zChanged |= AddMissingKeysToCurve(pxCurve, pzCurve);
|
|
|
|
xChanged |= AddMissingKeysToCurve(pyCurve, pxCurve);
|
|
zChanged |= AddMissingKeysToCurve(pyCurve, pzCurve);
|
|
|
|
xChanged |= AddMissingKeysToCurve(pzCurve, pxCurve);
|
|
yChanged |= AddMissingKeysToCurve(pzCurve, pyCurve);
|
|
|
|
if (xChanged)
|
|
AnimationUtility.SetEditorCurve(anim, pxBind.Value, pxCurve);
|
|
if (yChanged)
|
|
AnimationUtility.SetEditorCurve(anim, pyBind.Value, pyCurve);
|
|
if (zChanged)
|
|
AnimationUtility.SetEditorCurve(anim, pzBind.Value, pzCurve);
|
|
*/
|
|
if (animData.AddMissingKeysToCurve(pxCurve))
|
|
AnimationUtility.SetEditorCurve(anim, pxBind.Value, pxCurve);
|
|
if (animData.AddMissingKeysToCurve(pyCurve))
|
|
AnimationUtility.SetEditorCurve(anim, pyBind.Value, pzCurve);
|
|
if (animData.AddMissingKeysToCurve(pzCurve))
|
|
AnimationUtility.SetEditorCurve(anim, pzBind.Value, pzCurve);
|
|
|
|
}
|
|
|
|
private bool FindBindings()
|
|
{
|
|
Animator animator = null;
|
|
String path = "";
|
|
Transform trans = aHelper.transform;
|
|
while (true)
|
|
{
|
|
animator = trans.GetComponent<Animator>();
|
|
if (animator != null || trans.parent == null)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
path = path == "" ? trans.gameObject.name : trans.gameObject.name + "/" + path;
|
|
trans = trans.parent;
|
|
}
|
|
}
|
|
Debug.Log("Current Path: " + path);
|
|
|
|
if (animator == null)
|
|
return false;
|
|
|
|
//find clip
|
|
if (aHelper.currentClip != null)
|
|
{
|
|
anim = aHelper.currentClip;
|
|
}
|
|
else
|
|
{
|
|
AnimatorClipInfo[] info = animator.GetCurrentAnimatorClipInfo(0);
|
|
if (info.Length == 0)
|
|
animator.GetNextAnimatorClipInfo(0);
|
|
if (info.Length == 0)
|
|
return false;
|
|
anim = info[0].clip;
|
|
aHelper.currentClip = anim;
|
|
}
|
|
|
|
EditorCurveBinding[] cb = AnimationUtility.GetCurveBindings(anim);
|
|
//AnimationUtility.g
|
|
pxBind = null;
|
|
pyBind = null;
|
|
pzBind = null;
|
|
//trans = aHelper.transform;
|
|
|
|
foreach (EditorCurveBinding b in cb)
|
|
{
|
|
//Debug.Log("Property: " + b.propertyName + ", Path:" + b.path);
|
|
if (b.path != path)
|
|
continue;
|
|
if (b.propertyName == "m_LocalPosition.x")
|
|
{
|
|
pxBind = b;
|
|
}
|
|
else if (b.propertyName == "m_LocalPosition.y")
|
|
{
|
|
pyBind = b;
|
|
}
|
|
else if (b.propertyName == "m_LocalPosition.z")
|
|
{
|
|
pzBind = b;
|
|
}
|
|
}
|
|
|
|
|
|
return pxBind.HasValue && pyBind.HasValue && pzBind.HasValue;
|
|
}
|
|
|
|
|
|
private void OnSceneGUI()
|
|
{
|
|
aHelper = target as AnimationHelper;
|
|
animData = new AnimationData();
|
|
//use transformy for points only if parent exists. Otherwise, keys are in global coords.
|
|
if (aHelper.transform.parent)
|
|
animData.trans = aHelper.transform.parent.transform;
|
|
|
|
if (!FindBindings())
|
|
return;
|
|
|
|
pxCurve = null;
|
|
pyCurve = null;
|
|
pzCurve = null;
|
|
if (pxBind.HasValue)
|
|
{
|
|
pxCurve = AnimationUtility.GetEditorCurve(anim, pxBind.Value);
|
|
}
|
|
if (pyBind.HasValue)
|
|
{
|
|
pyCurve = AnimationUtility.GetEditorCurve(anim, pyBind.Value);
|
|
}
|
|
if (pzBind.HasValue)
|
|
{
|
|
pzCurve = AnimationUtility.GetEditorCurve(anim, pzBind.Value);
|
|
}
|
|
// anim.
|
|
if (pxCurve == null || pyCurve == null || pzCurve == null)
|
|
return;
|
|
|
|
//positionAnim = new List<PositionData>();
|
|
animData.GenerateKeys(pxCurve);
|
|
animData.GenerateKeys(pyCurve);
|
|
animData.GenerateKeys(pzCurve);
|
|
|
|
if (animData.Count < 2)
|
|
return;
|
|
|
|
EnsureKeysIntegrity();
|
|
animData.CopyKeys(pxCurve, CurveType.POS_X);
|
|
animData.CopyKeys(pyCurve, CurveType.POS_Y);
|
|
animData.CopyKeys(pzCurve, CurveType.POS_Z);
|
|
animData.TransformToWorld();
|
|
|
|
for (int i = 0; i < animData.Count; i++)
|
|
{
|
|
ShowPoint(i);
|
|
}
|
|
|
|
for (int i = 0; i < animData.Count - 1; i++)
|
|
{
|
|
Handles.DrawBezier(animData[i].point, animData[i + 1].point, animData[i].point + animData[i].outTan, animData[i + 1].point - animData[i + 1].inTan, Color.white, null, 2f);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
PositionData tmp;
|
|
for (int i = 0; i < pxCurve.keys.Length; i++)
|
|
{
|
|
Keyframe k = pxCurve.keys[i];
|
|
tmp = new PositionData();
|
|
tmp.time = k.time;
|
|
int idx = positionAnim.BinarySearch(tmp);
|
|
if (idx < 0)
|
|
{
|
|
//tmp.xKeyId = i;
|
|
tmp.point.x = k.value;
|
|
tmp.inTan.x = k.inTangent;
|
|
tmp.outTan.x = k.outTangent;
|
|
positionAnim.Add(tmp);
|
|
}
|
|
else
|
|
{
|
|
//positionAnim[idx].xKeyId = i;
|
|
positionAnim[idx].point.x = k.value;
|
|
positionAnim[idx].inTan.x = k.inTangent;
|
|
positionAnim[idx].outTan.x = k.outTangent;
|
|
}
|
|
}
|
|
for (int i = 0; i < pyCurve.keys.Length; i++)
|
|
{
|
|
Keyframe k = pyCurve.keys[i];
|
|
tmp = new PositionData();
|
|
tmp.time = k.time;
|
|
int idx = positionAnim.BinarySearch(tmp);
|
|
if (idx < 0)
|
|
{
|
|
//tmp.yKeyId = i;
|
|
tmp.point.y = k.value;
|
|
tmp.inTan.y = k.inTangent;
|
|
tmp.outTan.y = k.outTangent;
|
|
positionAnim.Add(tmp);
|
|
}
|
|
else
|
|
{
|
|
//positionAnim[idx].yKeyId = i;
|
|
positionAnim[idx].point.y = k.value;
|
|
positionAnim[idx].inTan.y = k.inTangent;
|
|
positionAnim[idx].outTan.y = k.outTangent;
|
|
}
|
|
}
|
|
for (int i = 0; i < pzCurve.keys.Length; i++)
|
|
{
|
|
Keyframe k = pzCurve.keys[i];
|
|
tmp = new PositionData();
|
|
tmp.time = k.time;
|
|
int idx = positionAnim.BinarySearch(tmp);
|
|
if (idx < 0)
|
|
{
|
|
//tmp.zKeyId = i;
|
|
tmp.point.z = k.value;
|
|
tmp.inTan.z = k.inTangent;
|
|
tmp.outTan.z = k.outTangent;
|
|
positionAnim.Add(tmp);
|
|
}
|
|
else
|
|
{
|
|
//positionAnim[idx].zKeyId = i;
|
|
positionAnim[idx].point.z = k.value;
|
|
positionAnim[idx].inTan.z = k.inTangent;
|
|
positionAnim[idx].outTan.z = k.outTangent;
|
|
}
|
|
}
|
|
|
|
if (positionAnim.Count < 2)
|
|
return;
|
|
for (int i = 0; i < positionAnim.Count; i++)
|
|
{
|
|
if (trans.parent)
|
|
{
|
|
positionAnim[i].point = trans.parent.transform.TransformPoint(positionAnim[i].point);
|
|
positionAnim[i].inTan = trans.parent.transform.TransformDirection(positionAnim[i].inTan);
|
|
positionAnim[i].outTan = trans.parent.transform.TransformDirection(positionAnim[i].outTan);
|
|
}
|
|
ShowPoint(i);
|
|
}
|
|
// Debug.Log(anim.frameRate);
|
|
|
|
//adjust tangents
|
|
for (int i = 0; i < positionAnim.Count - 1; i++)
|
|
{
|
|
float a = 1f/3f;
|
|
float timeDiff = positionAnim[i + 1].time - positionAnim[i].time;
|
|
a *= timeDiff;
|
|
positionAnim[i].outTan *= a;
|
|
positionAnim[i + 1].inTan *= a;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < positionAnim.Count - 1; i++)
|
|
{
|
|
Handles.DrawBezier(positionAnim[i].point, positionAnim[i + 1].point, positionAnim[i].point + positionAnim[i].outTan, positionAnim[i + 1].point - positionAnim[i + 1].inTan, Color.white, null, 2f);
|
|
}
|
|
|
|
float timeEnd = positionAnim[positionAnim.Count - 1].time;
|
|
Vector3 p0 = positionAnim[0].point;
|
|
Vector3 p1 = p0;
|
|
for (float t = positionAnim[0].time; t < timeEnd; t += timeStep)
|
|
{
|
|
p1.x = pxCurve.Evaluate(t);
|
|
p1.y = pyCurve.Evaluate(t);
|
|
p1.z = pzCurve.Evaluate(t);
|
|
// p1 = trans.TransformPoint(p1);
|
|
Handles.DrawLine(p0, p1);
|
|
p0 = p1;
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
private Vector3 ShowPoint(int index)
|
|
{
|
|
PositionData pData = animData[index];
|
|
Vector3 point = pData.point;
|
|
float size = HandleUtility.GetHandleSize(point);
|
|
if (index == 0)
|
|
{
|
|
size *= 2f;
|
|
}
|
|
Handles.color = Color.gray;
|
|
|
|
Quaternion handleRot = Tools.pivotRotation == PivotRotation.Local ?
|
|
aHelper.transform.rotation : Quaternion.identity;
|
|
|
|
|
|
//Handles.DrawBezier(positionAnim[i].point, positionAnim[i + 1].point, positionAnim[i].point + positionAnim[i].outTan, positionAnim[i + 1].point - positionAnim[i + 1].inTan, Color.white, null, 2f);
|
|
|
|
|
|
Handles.DrawLine(point, point - pData.inTan);
|
|
Handles.DrawLine(point, point + pData.outTan);
|
|
|
|
if (Handles.Button(point, handleRot, size * handleSize, size * pickSize, Handles.DotHandleCap))
|
|
{
|
|
aHelper.selectedKeyIndex = index;
|
|
aHelper.selectionType = AnimationHelper.SelectionType.KEY;
|
|
Repaint();
|
|
}
|
|
else if (Handles.Button(point + pData.outTan, handleRot, size * handleSize, size * pickSize, Handles.DotHandleCap))
|
|
{
|
|
aHelper.selectedKeyIndex = index;
|
|
aHelper.selectionType = AnimationHelper.SelectionType.OUT_TANGENT;
|
|
Repaint();
|
|
}
|
|
else if (Handles.Button(point - pData.inTan, handleRot, size * handleSize, size * pickSize, Handles.DotHandleCap))
|
|
{
|
|
aHelper.selectedKeyIndex = index;
|
|
aHelper.selectionType = AnimationHelper.SelectionType.IN_TANGENT;
|
|
Repaint();
|
|
}
|
|
|
|
if (aHelper.selectedKeyIndex == index)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
|
|
switch (aHelper.selectionType)
|
|
{
|
|
case AnimationHelper.SelectionType.KEY:
|
|
point = Handles.DoPositionHandle(point, handleRot);
|
|
break;
|
|
case AnimationHelper.SelectionType.IN_TANGENT:
|
|
point = Handles.DoPositionHandle(point - pData.inTan, handleRot);
|
|
break;
|
|
case AnimationHelper.SelectionType.OUT_TANGENT:
|
|
point = Handles.DoPositionHandle(point + pData.outTan, handleRot);
|
|
break;
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
Undo.RecordObject(aHelper, "Move Point");
|
|
EditorUtility.SetDirty(aHelper);
|
|
Keyframe[] xkeys, ykeys, zkeys;
|
|
xkeys = pxCurve.keys;
|
|
ykeys = pyCurve.keys;
|
|
zkeys = pzCurve.keys;
|
|
switch (aHelper.selectionType)
|
|
{
|
|
case AnimationHelper.SelectionType.KEY:
|
|
animData.SetWorldPosition(index, point);
|
|
point = animData[index].point;
|
|
|
|
xkeys[index].value = point.x;
|
|
ykeys[index].value = point.y;
|
|
zkeys[index].value = point.z;
|
|
|
|
break;
|
|
case AnimationHelper.SelectionType.IN_TANGENT:
|
|
if (animData.InTangentFromWorld(index, point, out point))
|
|
{
|
|
xkeys[index].inTangent = point.x;
|
|
ykeys[index].inTangent = point.y;
|
|
zkeys[index].inTangent = point.z;
|
|
//
|
|
if (aHelper.tangentMode == AnimationHelper.TangentMode.SMOOTH)
|
|
{
|
|
xkeys[index].outTangent = point.x;
|
|
ykeys[index].outTangent = point.y;
|
|
zkeys[index].outTangent = point.z;
|
|
}
|
|
|
|
}
|
|
break;
|
|
case AnimationHelper.SelectionType.OUT_TANGENT:
|
|
if (animData.OutTangentFromWorld(index, point, out point))
|
|
{
|
|
xkeys[index].outTangent = point.x;
|
|
ykeys[index].outTangent = point.y;
|
|
zkeys[index].outTangent = point.z;
|
|
//
|
|
if (aHelper.tangentMode == AnimationHelper.TangentMode.SMOOTH)
|
|
{
|
|
xkeys[index].inTangent = point.x;
|
|
ykeys[index].inTangent = point.y;
|
|
zkeys[index].inTangent = point.z;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
pxCurve.keys = xkeys;
|
|
pyCurve.keys = ykeys;
|
|
pzCurve.keys = zkeys;
|
|
|
|
|
|
|
|
|
|
AnimationUtility.SetEditorCurve(anim, pxBind.Value, pxCurve);
|
|
AnimationUtility.SetEditorCurve(anim, pyBind.Value, pyCurve);
|
|
AnimationUtility.SetEditorCurve(anim, pzBind.Value, pzCurve);
|
|
}
|
|
}
|
|
return point;
|
|
}
|
|
/*
|
|
private Vector3 ShowPoint(int index)
|
|
{
|
|
PositionData pData = positionAnim[index];
|
|
Vector3 point = pData.point;
|
|
float size = HandleUtility.GetHandleSize(point);
|
|
if (index == 0)
|
|
{
|
|
size *= 2f;
|
|
}
|
|
Handles.color = Color.gray;
|
|
|
|
//Handles.DrawBezier(positionAnim[i].point, positionAnim[i + 1].point, positionAnim[i].point + positionAnim[i].outTan, positionAnim[i + 1].point - positionAnim[i + 1].inTan, Color.white, null, 2f);
|
|
|
|
|
|
Handles.DrawLine(point, point - pData.inTan);
|
|
Handles.DrawLine(point, point + pData.outTan);
|
|
|
|
if (Handles.Button(point, trans.localRotation, size * handleSize, size * pickSize, Handles.DotCap))
|
|
{
|
|
aHelper.selectedKeyIndex = index;
|
|
aHelper.selectionType = AnimationHelper.SelectionType.KEY;
|
|
Repaint();
|
|
}
|
|
else if (Handles.Button(point + pData.outTan, trans.localRotation, size * handleSize, size * pickSize, Handles.DotCap))
|
|
{
|
|
aHelper.selectedKeyIndex = index;
|
|
aHelper.selectionType = AnimationHelper.SelectionType.OUT_TANGENT;
|
|
Repaint();
|
|
}
|
|
else if (Handles.Button(point - pData.inTan, trans.localRotation, size * handleSize, size * pickSize, Handles.DotCap))
|
|
{
|
|
aHelper.selectedKeyIndex = index;
|
|
aHelper.selectionType = AnimationHelper.SelectionType.IN_TANGENT;
|
|
Repaint();
|
|
}
|
|
|
|
if (aHelper.selectedKeyIndex == index)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
|
|
switch (aHelper.selectionType)
|
|
{
|
|
case AnimationHelper.SelectionType.KEY:
|
|
point = Handles.DoPositionHandle(point, trans.localRotation);
|
|
break;
|
|
case AnimationHelper.SelectionType.IN_TANGENT:
|
|
point = Handles.DoPositionHandle(point - pData.inTan, trans.localRotation);
|
|
break;
|
|
case AnimationHelper.SelectionType.OUT_TANGENT:
|
|
point = Handles.DoPositionHandle(point + pData.outTan, trans.localRotation);
|
|
break;
|
|
}
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
Undo.RecordObject(aHelper, "Move Point");
|
|
EditorUtility.SetDirty(aHelper);
|
|
Keyframe[] xkeys, ykeys, zkeys;
|
|
xkeys = pxCurve.keys;
|
|
ykeys = pyCurve.keys;
|
|
zkeys = pzCurve.keys;
|
|
switch (aHelper.selectionType)
|
|
{
|
|
case AnimationHelper.SelectionType.KEY:
|
|
if (trans.parent)
|
|
point = trans.parent.transform.InverseTransformPoint(point);
|
|
|
|
xkeys[index].value = point.x;
|
|
ykeys[index].value = point.y;
|
|
zkeys[index].value = point.z;
|
|
|
|
break;
|
|
case AnimationHelper.SelectionType.IN_TANGENT:
|
|
point = pData.point - point;
|
|
if (index -1 >= 0)
|
|
{
|
|
float timeDiff = pData.time - positionAnim[index-1].time;
|
|
float a = 1f/3.0f;
|
|
a *= timeDiff;
|
|
point /= a;
|
|
|
|
if (trans.parent)
|
|
point = trans.parent.transform.InverseTransformDirection(point);
|
|
|
|
xkeys[index].inTangent = point.x;
|
|
ykeys[index].inTangent = point.y;
|
|
zkeys[index].inTangent = point.z;
|
|
//
|
|
if (aHelper.tangentMode == AnimationHelper.TangentMode.SMOOTH)
|
|
{
|
|
xkeys[index].outTangent = point.x;
|
|
ykeys[index].outTangent = point.y;
|
|
zkeys[index].outTangent = point.z;
|
|
}
|
|
|
|
}
|
|
break;
|
|
case AnimationHelper.SelectionType.OUT_TANGENT:
|
|
point = point - pData.point;
|
|
if (index + 1 < positionAnim.Count)
|
|
{
|
|
float timeDiff = positionAnim[index + 1].time - pData.time;
|
|
float a = 1f/3f;
|
|
a *= timeDiff;
|
|
point /= a;
|
|
|
|
if (trans.parent)
|
|
point = trans.parent.transform.InverseTransformDirection(point);
|
|
|
|
xkeys[index].outTangent = point.x;
|
|
ykeys[index].outTangent = point.y;
|
|
zkeys[index].outTangent = point.z;
|
|
//
|
|
if (aHelper.tangentMode == AnimationHelper.TangentMode.SMOOTH)
|
|
{
|
|
xkeys[index].inTangent = point.x;
|
|
ykeys[index].inTangent = point.y;
|
|
zkeys[index].inTangent = point.z;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
pxCurve.keys = xkeys;
|
|
pyCurve.keys = ykeys;
|
|
pzCurve.keys = zkeys;
|
|
|
|
|
|
|
|
|
|
AnimationUtility.SetEditorCurve(anim, pxBind.Value, pxCurve);
|
|
AnimationUtility.SetEditorCurve(anim, pyBind.Value, pyCurve);
|
|
AnimationUtility.SetEditorCurve(anim, pzBind.Value, pzCurve);
|
|
}
|
|
}
|
|
return point;
|
|
}
|
|
*/
|
|
private float GetBezierValue(float t, float p0, float p1, float p2, float p3)
|
|
{
|
|
t = Mathf.Clamp01(t); float oneMinusT = 1.0f - t;
|
|
float oneMinusT2 = oneMinusT * oneMinusT;
|
|
float oneMinusT3 = oneMinusT2 * oneMinusT;
|
|
float t2 = t * t;
|
|
float t3 = t2 * t;
|
|
return oneMinusT3 * p0 + 3.0f * oneMinusT2 * t * p1 + 3.0f * oneMinusT * t2 * p2 + t3 * p3;
|
|
}
|
|
|
|
private float GetBezierDerivative(float t, float p0, float p1, float p2, float p3)
|
|
{
|
|
t = Mathf.Clamp01(t);
|
|
float oneMinusT = 1f - t;
|
|
return
|
|
3f * oneMinusT * oneMinusT * (p1 - p0) +
|
|
6f * oneMinusT * t * (p2 - p1) +
|
|
3f * t * t * (p3 - p2);
|
|
}
|
|
} |