Editor拡張でAnimationClipをいじるやつ
この記事は性DEC Advent Calendar 2024の13日目の記事になります。
Unityのアニメーションクリップの値をスクリプトから直した~い
具体的には色情報を修正したい欲求が生まれました。
詳細は明後日の性DEC2024下半期にて・・・!
とにかくスクリプトからアニメーションクリップを編集したいのです。
大まかな流れ
- AnimationClipを取得
- AnimationClipの色に関連するキーフレームを取得
- AnimationClipの値を編集
- AnimationClipを保存
どう実装する?
今回はサンプルなので指定のパスをもつやつを編集できるだけにしてみます。
EditoprWindowにAnimationClipを渡してロードする>該当のパスがある場合色のパラメーターが見れる。
今回のAnimationClipはキーフレームが一つしかないみたいな前提
とりあえずEditorWindowを作る
こういうやつ
以下みたいなコードでできます。
using UnityEngine;
using UnityEditor;
public class AnimationClipColorEditor : EditorWindow
{
private AnimationClip selectedClip;
[MenuItem("Tools/AnimationClip Color Editor")]
public static void ShowWindow()
{
GetWindow<AnimationClipColorEditor>("AnimationClip Color Editor");
}
void OnGUI()
{
// AnimationClip選択
selectedClip = (AnimationClip)EditorGUILayout.ObjectField("Animation Clip", selectedClip, typeof(AnimationClip), false);
if (selectedClip == null)
{
EditorGUILayout.HelpBox("編集するAnimationClipを選択してください。", MessageType.Info);
return;
}
if (GUILayout.Button("Load Color Curves"))
{
LoadColorCurves(); // ロードの処理をかく
}
}
}
LoadColorCurvesの実装
AnimationClipの中をのぞく
AnimationClipを読み取ってAnimationCurveを確認する。
今回はパスを指定し、プロパティー名を取得してそれらに対して操作を行う。
とりあえず自動で便利にするのは後回しでバイネームで指定できるようにしたい。
なのでパスとプロパティー名をログに出してみる
private void LoadColorCurves()
{
// AnimationClipのすべてのカーブバインディングを取得
curveBindings = AnimationUtility.GetCurveBindings(selectedClip);
// 色に対応するカーブを探す
foreach (var binding in curveBindings)
{
Debug.Log(binding.path + ", "+binding.propertyName);
}
}
取得できた!
取得できたので編集する
今回はButton_Normal/Innerのm_Color.r,m_Color.g,m_Color.b,m_Color.aを編集したい。
今回な直指定でやるので以下みたいなコードにした。
private void LoadColorCurves()
{
// AnimationClipのすべてのカーブバインディングを取得
curveBindings = AnimationUtility.GetCurveBindings(selectedClip);
var inner = curveBindings.Where(x => x.path == "Button_Normal/Inner")
.Where(x => x.propertyName.Contains("m_Color"))
.ToDictionary(x => x.propertyName, x => x);
これでAnimationClipに含まれているButton_Normal/Innerの色のパラメーターを取得できた。
これをEditor上で編集するためにEditgorWindow側にAnimationCurveを保存する場所を追加する。
private AnimationCurve curveR;
private AnimationCurve curveG;
private AnimationCurve curveB;
private AnimationCurve curveA;
雑にこんな感じでメンバ変数に追加しましょう。
LoadColorCurves()にこれらのAnimationCurveに取得したAnimationCurveを保存する箇所を追加してみる
private void LoadColorCurves()
{
// AnimationClipのすべてのカーブバインディングを取得
curveBindings = AnimationUtility.GetCurveBindings(selectedClip);
var inner = curveBindings.Where(x => x.path == "Button_Normal/Inner")
.Where(x => x.propertyName.Contains("m_Color"))
.ToDictionary(x => x.propertyName, x => x);
if (inner.ContainsKey("m_Color.r"))
curveR = AnimationUtility.GetEditorCurve(selectedClip, inner["m_Color.r"]);
if (inner.ContainsKey("m_Color.g") )
curveG = AnimationUtility.GetEditorCurve(selectedClip, inner["m_Color.g"]);
if (inner.ContainsKey("m_Color.b"))
curveB = AnimationUtility.GetEditorCurve(selectedClip, inner["m_Color.b"]);
if (inner.ContainsKey("m_Color.a"))
curveA = AnimationUtility.GetEditorCurve(selectedClip, inner["m_Color.a"]);
}
これでこのAnimationのAnimationCurveは取得できた。
続いて次みたいなUIを作ってみる
色を表示してみる
AnimationCurveを編集することになるがそうは言っても色がわからないのは困るので確認できるようにする。
色のフィールドを追加するのはEditorGUILayout.ColorField(color);みたいなコードでできる。
void OnGUI()
{
// カーブがロードされている場合
if (curveR != null && curveG != null && curveB != null && curveA != null)
{
EditorGUILayout.LabelField("Edit Color Curves");
// 各カーブの編集
curveR = EditorGUILayout.CurveField("m_Color.r", curveR);
curveG = EditorGUILayout.CurveField("m_Color.g", curveG);
curveB = EditorGUILayout.CurveField("m_Color.b", curveB);
curveA = EditorGUILayout.CurveField("m_Color.a", curveA);
Color color = new Color(curveR.Evaluate(0), curveG.Evaluate(0), curveB.Evaluate(0), curveA.Evaluate(0));
EditorGUILayout.ColorField(color);
こんな感じでフィールドを追加するとこういうUIが表示できる。
このままだといじっても何にもならないから編集して保存してみる。
セーブ機構を追加
void OnGUI()
{
// AnimationClip選択
selectedClip = (AnimationClip)EditorGUILayout.ObjectField("Animation Clip", selectedClip, typeof(AnimationClip), false);
if (selectedClip == null)
{
EditorGUILayout.HelpBox("編集するAnimationClipを選択してください。", MessageType.Info);
return;
}
if (GUILayout.Button("Load Color Curves"))
{
LoadColorCurves();
}
// カーブがロードされている場合
if (curveR != null && curveG != null && curveB != null && curveA != null)
{
EditorGUILayout.LabelField("Edit Color Curves");
// 各カーブの編集
curveR = EditorGUILayout.CurveField("m_Color.r", curveR);
curveG = EditorGUILayout.CurveField("m_Color.g", curveG);
curveB = EditorGUILayout.CurveField("m_Color.b", curveB);
curveA = EditorGUILayout.CurveField("m_Color.a", curveA);
Color color = new Color(curveR.Evaluate(0), curveG.Evaluate(0), curveB.Evaluate(0), curveA.Evaluate(0));
EditorGUILayout.ColorField(color);
if (GUILayout.Button("Save Changes"))
{
SaveColorCurves();
}
}
新しくセーブボタンを追加してみる。
SaveColorCurves()に実装を作っていく。
SaveColorCurves の実装
ざっくり以下のような感じでやったら保存の仕組みができる。
private void SaveColorCurves()
{
if (selectedClip == null) return;
Undo.RecordObject(selectedClip, "Edit Color Curves");
// バインディングを設定
for (int i = 0; i < curveBindings.Length; i++)
{
var binding = curveBindings[i];
if (binding.path != "Button_Normal/Inner") continue;
if (binding.propertyName == "m_Color.r")
AnimationUtility.SetEditorCurve(selectedClip, binding, curveR);
else if (binding.propertyName == "m_Color.g")
AnimationUtility.SetEditorCurve(selectedClip, binding, curveG);
else if (binding.propertyName == "m_Color.b")
AnimationUtility.SetEditorCurve(selectedClip, binding, curveB);
else if (binding.propertyName == "m_Color.a")
AnimationUtility.SetEditorCurve(selectedClip, binding, curveA);
}
EditorUtility.SetDirty(selectedClip);
Debug.Log("変更を保存しました。");
}
Undo.RecordObject(selectedClip, "Edit Color Curves");
Unityのアンドゥに対応するために必要なやつ。
自前のEditgor拡張でもこれでアンドゥに対応できる。
保存の部分
EditorUtility.SetDirty(selectedClip);
Debug.Log("変更を保存しました。");
SetDirty付けると変更フラグを付けることができる。これがついてるとエンジン側で何かしらの変更があったことになる。これが無いと変更があったと認識されず保存されなかったりする。
## できた!!
アニメーションクリップを指定する。
読み込む
アニメーションカーブをいじる
保存する
の一連の流れがこれでできました!ぶっちゃけアニメーションカーブで色を編集するとか絶対向いてないのでもっと工夫したほうが良いと思うけど今回はアクセスして値を変えて保存がしたーい!というところでそこは達成できたのでOK!!!
自分の場合は色だったけど開発時に動的にAnimationClipを作ったりとかできるからなにか便利な使い方もできるかも?
なんか参考になったら幸いです・・・!それでは!