[MaterialPropertyDrawer] [Unity] ShaderPropertyAttributeを自作した


CustomMaterialEditorを各シェーダーごとに作成するのは大変なので
簡単なデザインをできるようにいろいろと作ってみました。

ShaderPropertyAttributeとは

シェーダーのプロパティに属性を付与できる機能のことです
マテリアルのインスペクタでの表示を変えることができます。
例:[Header(Hoge)], [NoScaleOffset]など

以下の記事で公式で用意されているものが紹介されています。
【Unity】シェーダプロパティアトリビュートまとめ
【Unity】ShaderLabのプロパティ属性まとめ

ShaderPropertyAttributeを自作する

この属性ですが, MaterialPropertyDrawerを継承することで自作できます。
公式リファレンスに実装例が載っています

また、私が作成したプログラムもgistで公開しているので参考にどうぞ
https://gist.github.com/gatosyocora/9f506612a27a02e28e0be60d09535580

コード例です。

SampleAttribute1.cs
internal class SingleLineTexDrawer : MaterialPropertyDrawer
{
    public SingleLineTexDrawer() { }

    public override void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor)
    {
        editor.TexturePropertySingleLine(label, prop);
    }
}

これはTexture2Dを1行で表示するようにするAttributeです。
こんな感じになります

このAttributeでは単にTexture2Dのプロパティの表示を
MaterialEditor.TexturePropertySingleLine()で変えているだけです。

ここで注意する点は

  • MaterialPropertyDrawerを継承する
  • OnGUIをOverrideする
  • クラス名を○○Drawerにする
  • ファイル名とクラス名は一致していなくても良い
  • Editorフォルダ以下に入れる

このattributeはシェーダーコードではこのように書きます
作成したクラスのクラス名からDrawerを除外した部分を記入することになります。

sample1.shaderの一部
Properties
{
    [SingleLineTex]
    _TestTex ("TestTex", 2D) = "while" {}
}

もう一例をあげます

SampleAttribute2.cs
internal class LineDecorator : MaterialPropertyDrawer
{
    private float spaceSize;

    public LineDecorator()
    {
        spaceSize = 0;
    }

    public LineDecorator(float spaceSize)
    {
        this.spaceSize = spaceSize;
    }

    public override void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor)
    {
        GUILayout.Space(spaceSize);
        GUILayout.Box(string.Empty, GUILayout.ExpandWidth(true), GUILayout.Height(1));
        GUILayout.Space(spaceSize);
    }
}

これは区切り線を入れるAttributeでこんな感じの表示になります

区切り線の上下に空白を入れるようにしており、その高さを自分で設定できるようにしています。
シェーダーコードにはこのように書きます

sample2.shaderの一部
Properties
{
    [Line(10)]
    _Color ("Color", Color) = (1, 1, 1, 1)
}

ここで指定した10がLineDecorator(float spaceSize)の引数として入力されます。

ShaderPropertyAttributeの種類

ShaderPropertyAttributeですが、実は2種類あります。

Drawer

プロパティの表示自体に影響を与えるもの
プロパティにつき1つしかつけることができない
例: [HideInInspector] [Toggle] [Enum] [NoScaleOffset]
上記の例だとSingleLineTexDrawer

Decorator

マテリアルのインスペクターに影響を与えるもの
プロパティにつきいくつでも設定できる
例: [Space] [Header]
上記の例だとLineDecorator

Drawerはプロパティの表示自体を変えるが、
Decoratorは余白やタイトルなどの装飾をつけるときに使います。

これらはクラス名でどちらの種類かが区別されているようです。
Attributeによって適切なほうを使うのが良いです。
また、内部処理的に各プロパティごとに
すべてのDecoratorのOnGUIの実行後にDrawerのOnGUIを実行しているようです。