蒼水家技術録

蒼水が普段制作とか勉強とかして覚えたことを復習としてまとめてるものです。 それが最適解かどうかはわからないけど、何を目的として始めて、何が必要で、実際何をやって、どうなったか、まで全部過程を残すための技術ブログです。

Unity Tips編 #3 エディタ拡張でHLSLファイルを作成できるようにする


どうも蒼水です。
最近シェーダー開発していてちょーっと不便だなと思ったこととしてUnityくん、標準でHLSLファイルを作成できないらしい。
だったら拡張すれば良いじゃない!ということで作りました、という記事です。
ツール配布あります。

前回のTip記事はこちらからどうぞ。
atelier-aomi.hatenablog.com

実行環境:Unity6(6000.0.26f1)

今回の目的

今回はUnity標準で対応されていないHLSLファイルを作成できるようにエディタ拡張をすることを目的とします。
Shaderを開発しているとIncludeファイルをHLSLで作成することがあるのですが、標準で作れないじゃん!って思って作ったのでそのメモです。

BOOTHで配布していますのでご自由にご利用ください!
atelier-aomi.booth.pm

機能紹介



本スクリプトをインポートするとProjectウィンドウで右クリック -> Create -> Shader -> HLSL Include FIleからHLSLファイルを作成可能になります。


また、作成時にファイル名を自由に付けることができ、作成されたファイルにはインクルードガードが自動挿入された状態で作成されます。
なので純粋にそのまますぐShander Includeファイルの開発を可能としました。

コード解説

変数の定義

変更可能性のあるものに対応するためにこれらは変数として扱います。
ファイル名と対象のパスが対象です。

private static string _fileName = "NewShaderInclude";
private static string _selectedPath = "";

作成時のウィンドウ表示

ウィンドウの表示に関してはこの部分。
現在選択しているファイル、階層を判断し作成対象のパスを取得し、その場に作成できるようにします。

[MenuItem("Assets/Create/Shader/HLSL Include File", false, 84)]
static void ShowWindow()
{
  // 選択中のパスを取得
  _selectedPath = AssetDatabase.GetAssetPath(Selection.activeObject);
  if (string.IsNullOrEmpty(_selectedPath))
  {
   _selectedPath = "Assets";
  }
   else if (!Directory.Exists(_selectedPath))
  {
   _selectedPath = Path.GetDirectoryName(_selectedPath);
  }

  // ウィンドウを表示
  HLSLFileCreator window = GetWindow<HLSLFileCreator>(true, "Create HLSL File", true);
  window.minSize = new Vector2(400, 120);
  window.maxSize = new Vector2(400, 120);
  window.ShowUtility();
}

HLSLファイルを作成する

HLSLファイルを作成するメソッドです。
ここでは入力された文字列をもとにマクロ名を作成し、それをもとにHLSLファイルに書き込んで生成します。
これにより自動インクルードガードが設定された状態でファイルを作成できます。

        void CreateHLSLFile()
        {
            if (string.IsNullOrWhiteSpace(_fileName))
            {
                EditorUtility.DisplayDialog("Error", "File name cannot be empty!", "OK");
                return;
            }

            // 不正な文字を削除
            _fileName = string.Join("_", _fileName.Split(Path.GetInvalidFileNameChars()));

            string fileNameWithExt = _fileName + ".hlsl";
            string filePath = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(_selectedPath, fileNameWithExt));

            // マクロ名を生成
            string macroName = _fileName.ToUpper().Replace(" ", "_") + "_INCLUDED";

            string template = $@"#ifndef {macroName}
#define {macroName}

// Add your shader code here

#endif // {macroName}
";

            File.WriteAllText(filePath, template);
            AssetDatabase.Refresh();

            Object asset = AssetDatabase.LoadAssetAtPath<Object>(filePath);
            Selection.activeObject = asset;
            EditorGUIUtility.PingObject(asset);

            // 次回のためにデフォルト名をリセット
            _fileName = "NewShaderInclude";
        }

OnGUI


GUI描画周りです。
ここで文字列の入力周りやボタン周りの実装しており、先ほどのメソッドを呼ぶことでファイルを生成します。

        void OnGUI()
        {
            GUILayout.Space(10);

            EditorGUILayout.LabelField("File Name (without extension):", EditorStyles.boldLabel);
            GUI.SetNextControlName("FileNameField");
            _fileName = EditorGUILayout.TextField(_fileName);

            GUILayout.Space(10);
            EditorGUILayout.LabelField($"Path: {_selectedPath}", EditorStyles.miniLabel);

            GUILayout.Space(10);

            EditorGUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();

            if (GUILayout.Button("Cancel", GUILayout.Width(100)))
            {
                Close();
            }

            if (GUILayout.Button("Create", GUILayout.Width(100)))
            {
                CreateHLSLFile();
                Close();
            }

            EditorGUILayout.EndHorizontal();

            // 初回表示時にテキストフィールドにフォーカス
            if (Event.current.type == EventType.Layout)
            {
                EditorGUI.FocusTextInControl("FileNameField");
            }

            // Enterキーで作成
            if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
            {
                CreateHLSLFile();
                Close();
                Event.current.Use();
            }
        }

おわりに

これでHLSLファイルが作成できるようになりました。
是非ご自由にご利用ください!
これ標準で対応されて欲しいなぁ...。

次回記事

atelier-aomi.hatenablog.com

Unity Tips編記事一覧はこちらからどうぞ。
atelier-aomi.hatenablog.com

<PR>