Skip to content

Instantly share code, notes, and snippets.

@shichiE
Created September 17, 2018 10:58
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shichiE/c8b7409ed519a62fe9b718c3a08af28b to your computer and use it in GitHub Desktop.
Save shichiE/c8b7409ed519a62fe9b718c3a08af28b to your computer and use it in GitHub Desktop.
AnimatinClipのカーブのスパイクを均すエディタ拡張
// 自由に使ってどうぞ
// [Edit]フォルダに入れてメニューの[Animation Clip Smoother]-[Open]を選択するとウィンドウが表示される。
// 編集するAnimationClipを選択後、編集するカーブを選択して[実行]ボタンを押す。
using UnityEditor;
using UnityEngine;
public class AnimationClipSmoother : EditorWindow
{
/// <summary>
/// 編集するAnimationClip
/// </summary>
private AnimationClip _selectAnimationClip = null;
/// <summary>
/// チェクする範囲
/// </summary>
private int _range = 5;
/// <summary>
/// スパイク判定するしきい値
/// </summary>
private float _threshold = 0.8f;
/// <summary>
/// 均したときの坂の勾配
/// </summary>
private float _slopeLevel = 0f;
/// <summary>
/// 符号反転したときだけ均すかどうか
/// </summary>
private bool _isSignInversion = false;
/// <summary>
/// curve番号
/// </summary>
private int _curveNumber;
/// <summary>
/// AnimationCipのプロパティ配列
/// </summary>
private string[] _propertyNameArray = {""};
[MenuItem("Animation Clip Smoother/Open")]
static void Open()
{
GetWindow<AnimationClipSmoother>();
}
void OnGUI()
{
EditorGUI.BeginChangeCheck();
_selectAnimationClip = EditorGUILayout.ObjectField(
"編集するアニメーションクリップ",
_selectAnimationClip,
typeof(AnimationClip), false) as AnimationClip;
// アニメーションクリップを選んだらそのプロパティをリスト要素にする
if (EditorGUI.EndChangeCheck())
{
int count = 0;
foreach (var binding in AnimationUtility.GetCurveBindings(_selectAnimationClip))
{
count++;
}
_propertyNameArray = new string[count];
count = 0;
foreach (var binding in AnimationUtility.GetCurveBindings(_selectAnimationClip))
{
_propertyNameArray[count] = binding.propertyName;
count++;
}
}
_range = EditorGUILayout.IntSlider("1度にチェックする範囲", _range, 2, 50);
_threshold = EditorGUILayout.Slider("しきい値", _threshold, 0.001f, 10);
_slopeLevel = EditorGUILayout.Slider("坂の勾配", _slopeLevel, 0f, 0.1f);
_isSignInversion = EditorGUILayout.Toggle("符号が反転する場合のみ", _isSignInversion);
_curveNumber = EditorGUILayout.Popup("編集するカーブ", _curveNumber, _propertyNameArray);
bool clickExecuteButton = GUILayout.Button("実行");
if (clickExecuteButton && _selectAnimationClip != null)
{
string curveName = _propertyNameArray[_curveNumber];
ClickExecuteButton(curveName);
}
}
/// <summary>
/// 実行ボタンを押したとき
/// </summary>
/// <param name="curveName">カーブ名</param>
private void ClickExecuteButton(string curveName)
{
AnimationClip animationClip = _selectAnimationClip;
Debug.Log(animationClip.name);
foreach (var binding in AnimationUtility.GetCurveBindings(animationClip))
{
var curve = AnimationUtility.GetEditorCurve(animationClip, binding);
if (binding.propertyName.StartsWith(curveName))
{
Debug.Log(binding.propertyName + " KeyLength=" + curve.keys.Length);
curve = SmoothCurve(curve);
AnimationUtility.SetEditorCurve(animationClip, binding, curve);
}
}
}
/// <summary>
/// カーブをスパイクを均す
/// </summary>
/// <param name="curve">カーブ</param>
/// <returns>均したAnimationCurve</returns>
private AnimationCurve SmoothCurve(AnimationCurve curve)
{
for (int i = 0; i < curve.keys.Length; i++)
{
var max = float.MinValue;
var min = float.MaxValue;
var maxIndex = 0;
var minIndex = 0;
for (int count = 0; count < _range && i + count < curve.keys.Length; count++)
{
if (min > curve.keys[i + count].value)
{
min = curve.keys[i + count].value;
minIndex = i + count;
}
if (max < curve.keys[i + count].value)
{
max = curve.keys[i + count].value;
maxIndex = i + count;
}
// しきい値を超えた場合キーフレームを移動させる
if (max - min > _threshold &&
(!_isSignInversion || (max >= 0f && min <= 0f)))
{
var index = 0;
if (curve.keys[i + count].value > min)
{
Keyframe key = curve.keys[minIndex];
// 坂の勾配をつける
for (index = minIndex + 1;
index < curve.keys.Length &&
key.value < curve.keys[index].value;
index++)
{
key.value += _slopeLevel;
Debug.Log("MoveKey index=" + index + " value=" + key.value);
curve.MoveKey(index, key);
curve.SmoothTangents(index, 1);
}
}
else
{
Keyframe key = curve.keys[maxIndex];
// 坂の勾配をつける
for (index = maxIndex + 1;
index < curve.keys.Length &&
key.value > curve.keys[index].value;
index++)
{
key.value -= _slopeLevel;
Debug.Log("MoveKey index=" + index + " value=" + key.value);
curve.MoveKey(index, key);
curve.SmoothTangents(index, 1);
}
}
}
}
}
return curve;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment