LoginSignup
10
6

Editor拡張を使ってAnimationCurveをプリセット化する

Posted at

はじめに

Editor拡張でAnimationCurveのプリセット機能を作成しました。
その際、Animationウィンドウから情報を引っ張ってくるのに苦戦したので
方法をまとめておこうと思います。

↓こんな感じでワンボタンでイージング反映する機能です
265275292-124a3be5-54bb-4ac9-9b3d-9237feb5da87.gif

コード全文

流れ

Animationウィンドウは外部から操作できない仕様ぽかったので、
ここを見ながらReflectionを利用してアクセスする形になりました。

AnimationWindowから3つの情報を取得できれば自由に操れるのでゴールです。
①選択中のKeyframeが所属するAnimationCurve
②選択中のKeyframe
③選択中のAnimationClip

選択中のAnimationWindowKeyframeを取得

AnimationWindow.animEditor.state.selectedKeys というところに
選択中のキーフレーム情報が保持されているのがわかりました。
まずはこれを取得します。

//Animationウィンドウを取得する。開いてなけれ開き、そのインスタンスを取得する。
var animationWindow = EditorWindow.GetWindow(animationWindowType,false,null,true);

//AnimationWindowstateを取得するため、AnimEditorを取得
var animEditorProperty = animationWindowType.GetProperty("animEditor", BindingFlags.Instance | BindingFlags.NonPublic);
var animEditor = animEditorProperty.GetValue(animationWindow);

//Animationウィンドウ内の情報取得のため、AnimationWindowstateを取得。
var stateProperty = animEditorType.GetProperty("state", BindingFlags.Instance | BindingFlags.Public);
var state = stateProperty.GetValue(animEditor);

//今開いてるのがCurveWindowの場合は選択中のキーフレームが上手く取得できないので、
//一度DopeSheetに戻してSelectionKeyの更新をする
var showCurveEditor = animationWindowStateType.GetField("showCurveEditor", BindingFlags.Instance | BindingFlags.Public);
if((bool)showCurveEditor.GetValue(state))
{
    var onEnableWindow = animEditorType.GetMethod("SwitchBetweenCurvesAndDopesheet", BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . Public);
    onEnableWindow.Invoke(animEditor,null); // DopeSheetに切り替えたことでSelectionKeyが更新される
    onEnableWindow.Invoke(animEditor,null); // 更新が終わったのでCurveWindowに戻す
}

//選択中のキーフレーム取得のため、AnimationWindowState.selectedKeysを取得
//AnimationWindowKeyframe型のListで返ってくるが、そのままだと扱えないのでdynamic型で受け取り
var getSelectionProperty = animationWindowStateType.GetProperty("selectedKeys", BindingFlags.Instance | BindingFlags.Public);
var keys = getSelectionProperty.GetValue(state) as dynamic;
foreach (var key in keys)
{
    //この中でキーを処理
}

ここまででツマッたポイントが2つあります。

①カーブウィンドウを開いている場合、selectedKeysが更新されないらしい。
animEditor.SwitchBetweenCurvesAndDopesheet()で一度ドープシートを開くことで更新し、
もう一度実行しカーブウィンドウに戻すことで解消しました。

②selectedKeysを取得したはいいが、なかなかListの要素にアクセスできなかった
NGパターン

keys = getSelectionProperty.GetValue(state);
//この場合Listとして認識されないので、foreachで回せず要素を取り出すことができない。

keys = getSelectionProperty.GetValue(state) as List<AnimationWindowKeyframe>;
//かといって正しい型で取得しようとした場合、AnimationWindowKeyframeへのアクセス権が無くエラーを吐く

dynamicで取得してあげたら上手く行きました。

AnimationCurveの取得・編集・保存

AnimationWindowKeyframeから
AnimationCurve、Keyframe、AnimationClipを取得出来るので
自由編集してAnimationClipを保存すれば完了です。

//選択しているキーフレームを含む、AnimationWindowCurveを取得
var curveProperty = animationWindowKeyframeType.GetProperty("curve", BindingFlags.Instance | BindingFlags.Public);
var selectWindowCurve = curveProperty.GetValue(key);

//AnimationWindowCurveのままだと編集しにくいので、UnityEngene.AnimationCurveに変換する
var toAnimationCurve = animationWindowCurveType.GetMethod("ToAnimationCurve" ,  BindingFlags.Instance | BindingFlags.Public);
var animationCurve = toAnimationCurve.Invoke(obj:selectWindowCurve , parameters: null) as AnimationCurve;

//選択したキーフレームがAnimationCurve内の何番目か取得
var getIndex = animationWindowKeyframeType.GetMethod("GetIndex" ,  BindingFlags.Instance | BindingFlags.Public);
var index = (int)getIndex.Invoke(key , null);

//選択キーフレームをKeyframeで取得
var keyframe = animationCurve[index];

///////
//ここでanimationCurveを編集する
///////

//保存先のAnimationClipを取得
var clipProperty = animationWindowCurveType.GetProperty("clip", BindingFlags.Instance | BindingFlags.Public);
var clip = clipProperty.GetValue(selectWindowCurve);

//AnimationCurve判別のためにCurveBindingを取得
var bindingProperty = animationWindowCurveType.GetProperty("binding", BindingFlags.Instance | BindingFlags.Public);
var binding = bindingProperty.GetValue(selectWindowCurve);

//AnimationClipにAnimationCurveの編集を反映
AnimationUtility.SetEditorCurve(clip, binding, animationCurve);

あとがき

カーブ調整もう少し楽出来ないかなぁと軽い気持ちではじめましたが、
公式のコードを読み解くだけで一苦労でした…

冒頭GifのEditor拡張はこちらです。

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6