Unityエディター拡張のカスタムプレビュー
Unityエディター拡張のカスタムプレビュー:
この記事はカヤックUnityアドベントカレンダー2018の16日目の記事になります。
今日の記事ではUnityエディター拡張のカスタムプレビューを紹介していきたいと思います。
プレビューできないものは、エディター拡張を使ってカスタムプレビューを作れば、プレビューができるようになります。
ここから、簡単なSpriteプレビュアーを作りながら、カスタムプレビューを作るためによく使う関数を見てみましょう
この中で注目してほしいのはOnPreviewGUIです。描画の処理はこの関数に書きます
例としては、スプライトを半分のサイズで描画する切り替えボタンを作ります。
なんか、インスペクターが変わりました。
何故かと言うと、CustomEditorアトリビュートはプレビューだけではなく、エンジン内部で実装されたインスペクターなどの要素も上書きするからです。
一般的に、上書きしないようにそのエディタークラスを継承すればいいですけど、Unity内部のSpriteRendererEditorはinternalで継承できないです。
今回はプレビューのカスタムだけ求めるので、CustomPreview*1とObjectPreviewを使えば解決できます。
これでSpriteRendererでスプライトのプレビューができるようになりました。
最終のコードはこうなります
UISpriteAnimationはコマアニメを作るためのコンポーネントですが、エディター再生中しか動きを見れないので、いつでも見れるようにプレビュアーを作りました
サンプルコード
実際の作業に使われないし、実現するためにNGUIコードの改造も少し必要なので、今回割愛します。
上記の例に限らず、パーティクルのプレビューとか、AnimationClipにあるSpriteアニメーションのプレビューとか、3Dモデルのプレビューとか、複数のプレビューを使って各アニメーションのプレビューとか、いろんなことができるでしょう。
明日は浅利さんによる「HTC Vive で両手を使った transform 操作を実現する」の話になります。
はじめに
こんにちは、ソーシャルゲーム事業部のUnityエンジニアの魏です。この記事はカヤックUnityアドベントカレンダー2018の16日目の記事になります。
今日の記事ではUnityエディター拡張のカスタムプレビューを紹介していきたいと思います。
カスタムプレビュー
TextureやMaterialなどプレビューできるものを選択すると、インスペクターのプレビューウィンドウで中身を確認できます。プレビューできないものは、エディター拡張を使ってカスタムプレビューを作れば、プレビューができるようになります。
ここから、簡単なSpriteプレビュアーを作りながら、カスタムプレビューを作るためによく使う関数を見てみましょう
最低限の関数
コンポーネントのコードusing UnityEngine; public class SpritePreviewer : MonoBehaviour { public Sprite sprite; }カスタムエディターのコード。Editorフォルダ内へ入れます。
この中で注目してほしいのはOnPreviewGUIです。描画の処理はこの関数に書きます
[CustomEditor(typeof(SpritePreviewer))] public class SpritePreviewerEditor : Editor { private GUIContent _title = new GUIContent("スプライトプレビュアー"); // プレビューウィンドウを表示するかどうか public override bool HasPreviewGUI() { return true; } // 名前通り、プレビューウィンドウ名を設定する関数 public override GUIContent GetPreviewTitle() { return _title; } // プレビューウィンドウで描画させたい内容はここで書く public override void OnPreviewGUI(Rect r, GUIStyle background) { var previewer = target as SpritePreviewer; GUI.DrawTexture(r, AssetPreview.GetAssetPreview(previewer.sprite)); } }SpritePreviewerコンポーネントをGameObjectに追加して、Sprite画像をコンポーネントにつけたら、こうなりました。
OnPreviewSettings
AnimationClipのプレビューみたいに、動画の再生や再生速度の調整などのUIはOnPreviewSettings関数で実装されています。例としては、スプライトを半分のサイズで描画する切り替えボタンを作ります。
private bool _halfSize = false; // プレビューウィンドウで描画させたいものはここで書く public override void OnPreviewGUI(Rect r, GUIStyle background) { var previewer = target as SpritePreviewer; var rect = _halfSize ? new Rect(r.x, r.y, r.width / 2, r.height / 2) : r; GUI.DrawTexture(rect, AssetPreview.GetAssetPreview(previewer.sprite)); } // プレビューウィンドウのヘッダーバーをカスタムする関数 public override void OnPreviewSettings() { _halfSize = GUILayout.Toggle(_halfSize, "0.5x"); }
off | on |
---|---|
CustomPreviewAttributeとObjectPreview
新コンポーネントではなく、SpriteRendererに直接プレビューウィンドウを追加すればいいじゃないかと思って、Typeを変更してみたら//[CustomEditor(typeof(SpritePreviewer))] [CustomEditor(typeof(SpriteRenderer))] public class SpritePreviewerEditor : Editor { ... public override void OnPreviewGUI(Rect r, GUIStyle background) { // var previewer = target as SpritePreviewer; var previewer = target as SpriteRenderer; var rect = _halfSize ? new Rect(r.x, r.y, r.width / 2, r.height / 2) : r; GUI.DrawTexture(rect, AssetPreview.GetAssetPreview(previewer.sprite)); } }
なんか、インスペクターが変わりました。
何故かと言うと、CustomEditorアトリビュートはプレビューだけではなく、エンジン内部で実装されたインスペクターなどの要素も上書きするからです。
一般的に、上書きしないようにそのエディタークラスを継承すればいいですけど、Unity内部のSpriteRendererEditorはinternalで継承できないです。
今回はプレビューのカスタムだけ求めるので、CustomPreview*1とObjectPreviewを使えば解決できます。
// [CustomEditor(typeof(SpritePreviewer))] [CustomPreview(typeof(SpriteRenderer))] // CustomPreviewを使うために、ObjectPreviewを継承しなければいけない // public class SpritePreviewerEditor : Editor public class SpritePreviewerEditor : ObjectPreview { ... }
変更前 | CustomPreview |
---|---|
最終のコードはこうなります
using UnityEngine; using UnityEditor; [CustomPreview(typeof(SpriteRenderer))] public class SpritePreviewerEditor : Editor { private GUIContent _title = new GUIContent("スプライトプレビュアー"); private bool _halfSize = false; // プレビューウィンドウを表示するかどうか public override bool HasPreviewGUI() { return true; } // 名前通り、プレビューウィンドウ名を設定する関数 public override GUIContent GetPreviewTitle() { return _title; } // プレビューウィンドウで描画させたいものはここで書く public override void OnPreviewGUI(Rect r, GUIStyle background) { var previewer = target as SpritePreviewer; var rect = _halfSize ? new Rect(r.x, r.y, r.width / 2, r.height / 2) : r; GUI.DrawTexture(rect, AssetPreview.GetAssetPreview(previewer.sprite)); } // プレビューウィンドウのヘッダーバーをカスタムする関数 public override void OnPreviewSettings() { _halfSize = GUILayout.Toggle(_halfSize, "0.5x"); } }
使用例
NGUIのUISpriteとUISpriteAnimationに基づいて実装したUISpriteAnimationプレビュアーを紹介します。UISpriteAnimationはコマアニメを作るためのコンポーネントですが、エディター再生中しか動きを見れないので、いつでも見れるようにプレビュアーを作りました
サンプルコード
using UnityEngine; using UnityEditor; using System.Reflection; using System.Collections.Generic; [CustomEditor(typeof(UISprite))] // UISpriteInspectorのOnPreviewGUIを利用したいので継承する public class UISpriteAnimationPreviewer : UISpriteInspector { AnimationSetting _animSetting = null; bool _isPlaying = false; bool _hasAnimation = false; float _speedScale = 1f; protected override void OnEnable() { base.OnEnable(); _hasAnimation = false; var targetSprite = target as UISprite; var spriteAnim = targetSprite.GetComponent<UISpriteAnimation>(); if (spriteAnim != null) { _animSetting = new AnimationSetting(spriteAnim); _hasAnimation = true; } } // プレビューウィンドウで描画させたい内容はここで書く public override void OnPreviewGUI(Rect rect, GUIStyle background) { var t = target as UISprite; AnimationSetting setting = _animSetting; if (!Application.isPlaying && _hasAnimation) { var spriteAnim = setting.anim; BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance; var field = typeof(UISpriteAnimation).GetField("mSpriteNames",flags); var spriteNames = field.GetValue(spriteAnim) as List<string>; // UISpriteAnimationのUpdate関数を参考にして、 // 何枚目のUISpriteを表示するか経過時間で計算する setting.delta += ((float)EditorApplication.timeSinceStartup - setting.lastTime) * _speedScale; setting.lastTime = (float)EditorApplication.timeSinceStartup; if (spriteNames.Count > 0) { if (_isPlaying) { float rate = 1f / spriteAnim.framesPerSecond; if (rate < setting.delta) { setting.delta = Mathf.Repeat(setting.delta, rate); setting.index++; } setting.index %= spriteNames.Count; // プレビューウィンドウで表示するために、UISpriteのspriteNameを変える // 保存する時spriteNameの差分が出るかもしれない t.spriteName = spriteNames[setting.index]; } // どの画像を表示しているか分かるように、画像名を表示する EditorGUI.DropShadowLabel(rect, spriteNames[setting.index]); rect.height -= 15; } else { return; } } // UISpriteのプレビューを利用して、spriteNameで指定しているUISpriteを描画させる base.OnPreviewGUI(rect, background); } // プレビューウィンドウのヘッダーバーをカスタムする関数 public override void OnPreviewSettings() { base.OnPreviewSettings(); if (!_hasAnimation) { return; } // 再生するボタン var playButton = EditorGUIUtility.IconContent("preAudioPlayOn"); var pauseButton = EditorGUIUtility.IconContent("preAudioPlayOff"); EditorGUI.BeginChangeCheck(); _isPlaying = GUILayout.Toggle(_isPlaying, _isPlaying ? playButton : pauseButton, (GUIStyle)"preButton"); if (EditorGUI.EndChangeCheck()) { _animSetting.lastTime = (float)EditorApplication.timeSinceStartup; } // AnimationClipのような再生速度を制御するUI // 実際の作業はUISpriteAnimationのFramerateで調整しているので、ここは練習だけ^_^ var speedScale = EditorGUIUtility.IconContent("SpeedScale", "Speed Scale"); if (GUILayout.Button(speedScale, (GUIStyle)"preButton")) { _speedScale = 1; } _speedScale = GUILayout.HorizontalSlider(_speedScale, 0f, 5f, (GUIStyle)"preSlider", (GUIStyle)"preSliderThumb"); GUILayout.Box(_speedScale.ToString("0.000"), new GUIStyle("preLabel")); } public override bool HasPreviewGUI() { return true; } //常に再描画される必要があるかどうか public override bool RequiresConstantRepaint() { return _isPlaying; } private class AnimationSetting { public int index; public float delta; public float lastTime; public UISpriteAnimation anim; public AnimationSetting(UISpriteAnimation anim) { index = 0; delta = 0; lastTime = (float)EditorApplication.timeSinceStartup; this.anim = anim; } } }CanEditMultipleObjectsとEditor.targetsを利用すれば、下のGIFのように複数のUISpriteAnimationのプレビューもできますが、
実際の作業に使われないし、実現するためにNGUIコードの改造も少し必要なので、今回割愛します。
おわりに
ということで、Unityエディター拡張のカスタムプレビューを紹介しました。上記の例に限らず、パーティクルのプレビューとか、AnimationClipにあるSpriteアニメーションのプレビューとか、3Dモデルのプレビューとか、複数のプレビューを使って各アニメーションのプレビューとか、いろんなことができるでしょう。
明日は浅利さんによる「HTC Vive で両手を使った transform 操作を実現する」の話になります。
*1:CustomPreviewを使えば、1つのObjectで複数のプレビューを作ることができます。
オリジナルのエンクロージャ: |
48698224-e6839f00-ec29-11e8-8a1a-ec740f4207a3.png |
コメント
コメントを投稿