LoginSignup
3
4

Shaderのマテリアルプロパティを見やすくしてみよう

Posted at

UnityでShaderを書いてますでしょうか。
書いた後は他の方に使いやすいようにマテリアルプロパティをカスタマイズはしていますでしょうか?
しなくても良いけど、した方が良い場合もあります。
私は今がそんな時です!なので色々と調べました!
ここに忘備録として弄り方を残しておきます。

前準備

CustomShaderGUIの基本的な事、適応の仕方はこちらのHoloMoto様の記事を読みましょう。

まずはShaderにCustomEditorを定義させて
ShaderGui用のファイルを制作して下さい。

また説明用として下記のようなシェーダーをAmplify Shader Editorで制作しました。
image.png
EmissionのUVをボロノイで取る事ができます。

例えばこのような設定にすれば、こんな感じになります。
image.png

ちなみにASEでシェーダーを制作した時は
image.png
この項目に設定したクラス名をかけば適応されますし、横の回転矢印マークを押せば通常に戻ります。

オリジナルと同じマテリアルプロパティを作る

まずは通常のマテリアルプロパティと同じ状態を作りましょう。
私はそれを作るのが面倒くさくて今まで触ろうともしませんでしたが
今は便利なものがあります!
そうChatGPTです。

ChatGPTに対して

UnityのShaderGUIについて、協力をして下さい。

下記のコードのShaderについて、ShaderGuiを制作しようと思います。
MaterialPropertyのコード部分を書いてください。
しかし、 base.OnGUI()は使用しないで下さい。
~~~~以下ShaderのProperties部分をコピペ~~~~

と聞いてみましょう。

きっとコードが帰ってくると思います。
それを必要部分( public override void OnGUIより以下)にコピペましょう。
これで準備が出来ました。

23/8/29現在だと
ChatGPT3.5は余計な処理を入れてしまいます。(聞き方が悪いのもあると思う)
ChatGPT4.0の方が素直なコードを出してくれました。

見た目を整えよう

見やすさは正義です。
設定個所のカテゴリー分けをする事で、設定のしやすさは格段に上がります。

image.png
ChatGPTに書いてもらったコードは、上記のようなマテリアルプロパティになりました。
テクスチャのUVを弄る[Tiling]と[Offset]が無くなってますが、これは後で設定をしましょう。


まずは、質感設定とボロノイ設定でカテゴリー分けをしましょう。
使用するのは、EditorGUILayout.VerticalScopeです。

using (new EditorGUILayout.VerticalScope("HelpBox"))
{
        //プロパティコードを入れる
}

EditorGUILayout.VerticalScope は、Unityエディタ拡張の中で縦方向のGUIレイアウトを制御するためのものです。このスコープ内でGUI要素を配置すると、それらは垂直方向に自動的に並べられます。

変数に"HelpBox"使用する事によって、中に入れたコードの範囲の情報を箱に収めたような感じに出来ます。

using (new EditorGUILayout.VerticalScope("HelpBox"))
{
    // 質感設定描写プロパティコード
}

EditorGUILayout.Space(); //スペースを開ける

using (new EditorGUILayout.VerticalScope("HelpBox"))
{
    // ボロノイ描写プロパティコード
}

image.png
というわけで、このように分けてみました。

参考URL

StandardShaderを真似る

みんな知っているStandardShaderのプロパティはこんな感じですね。
image.png

  • テクスチャ設定とカラーなどの調節設定が一列になっている。
  • Metalicにテクスチャを入れると、スライダーが消えて設定できなくなる。
  • Normal Mapにテクスチャを入れると、Scaleの設定が出てくる。
  • UVのTillingとOffsetがまとめて設定が出来る。
    などが特徴かと思います。

今現在のChatGPTに出したマテリアルプロパティは下記のような状態です。
image.png
コードはこちら

materialEditor.TexturePropertySingleLine(new GUIContent("Main Texture"), _MainTex, _MainColor);
materialEditor.RangeProperty(_Metalic, "Metalic");
materialEditor.TexturePropertySingleLine(new GUIContent("Metalic Texture"), _MetalicTex);
materialEditor.RangeProperty(_Smoothness, "Smoothness");
materialEditor.TexturePropertySingleLine(new GUIContent("Normal Texture"), _NormalTex, _NormalScale);

見た目は似たような感じになってますが、StandardShaderのようにはまだなっていません。
ここから変更を加えていきましょう。


まずはこちら、テクスチャ関連を表示する時に使えるコード一覧と、その表示見本になります。

materialEditor.TextureProperty(mainTex , "TextureProperty" );
            
materialEditor.TexturePropertySingleLine(new GUIContent("TexturePropertySingleLine"), mainTex, color);
            
materialEditor.TexturePropertyTwoLines(new GUIContent("TexturePropertyTwoLines"), mainTex, color , new GUIContent("Smoothness"),  glossiness);
            
materialEditor.TexturePropertyWithHDRColor(new GUIContent("TexturePropertyWithHDRColor"), mainTex, color, true);
            
GUILayout.Label("TextureScaleOffsetProperty"); //文字の表示
materialEditor.TextureScaleOffsetProperty(mainTex);

image.png
こちらを使ってプロパティのUIを整えていきましょう。


…というわけで見た目が同じようになるよう編集し、読みやすくした後のコードはこちら

GUILayout.Label("Main Maps");

materialEditor.TexturePropertySingleLine(
                new GUIContent("Main Texture"), _MainTex,
                _MainColor);

materialEditor.TexturePropertySingleLine(
                new GUIContent("Metalic"), _MetalicTex,
                _Metalic);

materialEditor.ShaderProperty(_Smoothness ,
                new GUIContent("Smoothness") ,
                2 );

materialEditor.TexturePropertySingleLine(
                new GUIContent("Normal Texture"), _NormalTex,
                _NormalScale);

image.png

  • _MainTex_NormalTex はChatGPTが出してくれた一行表示のまま。
  • Metalicはテクスチャと _Metaric を一列表示に。
  • _SmoothnessShaderProperty の3番目の引数に数字(int)を入れる事でインデントさせてます

これでStandardShaderのような配置になりました。

インデントについて

これインデントできることをUNITYのドキュメントには書いてないんですよね。

https://docs.unity3d.com/ScriptReference/MaterialEditor.ShaderProperty.html

https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/Inspector/MaterialEditor.cs#L1796

こっちを見ると、存在している。

テクスチャ導入に伴うプロパティの変化

ここから、テクスチャを入れるとプロパティが変化する仕組みを追加していきましょう。
まずはNormalTexturから。

プロパティに条件演算子を使用する事で、テクスチャの有無で分岐をさせる事が可能になります。

materialEditor.TexturePropertySingleLine(new GUIContent("Normal Texture"), _NormalTex,
              _NormalTex.textureValue != null ? _NormalScale : null );

image.png

_NormalTex.textureValue != nullこれでテクスチャが有無がわかります。
ある場合は、_NomalScale を表示、無い場合は null で無を表示させます。


Metalicの仕様はちょっと複雑で、

  • テクスチャが入ってないと、Metalicの強さを数値で決めれる。
  • テクスチャに入っていると、Metalicの強さが設定できなくなり
    内部計算の関係で 1.0 が入る。

これをコードに書くとこうなります。

bool isMetallicTex = _MetalicTex.textureValue;
materialEditor.TexturePropertySingleLine(
                new GUIContent("Metalic"), _MetalicTex,
                isMetallicTex ? null : _Metalic);

if(isMetallicTex){
    _Metalic.floatValue = 1f;
}
  1. _Metalic.textureValue を取得し、テクスチャの有無を isMetallicTex というbool変数に格納します。
  2. 条件演算子を使用して、テクスチャがある時は _Metalic の強さを設定できないように null を入れ、
    テクスチャがない時は数値を入れる事が出来るようにします。
  3. if文で、テクスチャがある時には _Metalic に 1.0 を入れる。
StandardShaderとの仕様違い

StandardShaderでは、Metalicの数字を設定した後に(例えば0.5とか)テクスチャを入れるとMetalicの数値が消え、
テクスチャを外すと数値が元に(0.5に)戻りますが、上記のコードだと戻りません。
これはStandardShaderがテクスチャの有無で数値を変更するのではなく、
プロパティの変数自体を変えているためになります。

テクスチャのスケールとオフセットを編集するためのプロパティを表示するためには下記のメソッドを使用します。

materialEditor.TextureScaleOffsetProperty(_MainTex);

image.png

Vectorプロパティを分解する

ボロノイのプロパティを編集していきます。
まずは今現在はこのようなプロパティになっています。
image.png

materialEditor.TexturePropertySingleLine(new GUIContent("Emission Texture"),
                    _EmissionTex, _EmissonColor);
                    
materialEditor.VectorProperty(_Voronoi_UV, "Voronoi UV");

materialEditor.ShaderProperty(_EnableVonoroi, "Enable Vonoroi");

この Voronoi UV の項目については
X:ボロノイのアングル
Y:ボロノイのスケール
Z:ボロノイ隙間距離
W:ボロノイの表示比率(0~1)
になってます。
これをそれぞれに設定を出来るようにしていきましょう。

出来たコードはこちら

EditorGUI.BeginChangeCheck();
Vector4 VoronoiVal = EditorGUILayout.Vector2Field("Voronoi UV", _Voronoi_UV.vectorValue);

VoronoiVal.z = EditorGUILayout.FloatField ("Voronoi size", _Voronoi_UV.vectorValue.z );

VoronoiVal.w = EditorGUILayout.Slider("Voronoi" , _Voronoi_UV.vectorValue.w , 0 , 1 );

if (EditorGUI.EndChangeCheck())
{
    _Voronoi_UV.vectorValue = VoronoiVal;
}

通常はVectorプロパティを使用した場合、XYだけを使用していたとしてもVectorなのでxyzwの項目が必ず表示されてしまいます。
それを、XYだけを表示・編集が出来るようにしましょう。
しかし、それをするにはmaterialEditorを使用するのではなく、EditorGUILayoutを使用しなくてはなりません。
EditorGUILayoutを使用した場合、見た目は作れるのですがマテリアル変数( _Voronoi_UV)の値を変更する事が出来ません。

そこでEditorGUI.BeginChangeCheck()メソッドを使用し、この後のGUI要素に変更が加えられたかどうかをチェックします。
if(EditorGUI.EndChangeCheck())で更新後に _Voronoi_UVに値を代入しています。

  • Vector4 VoronoiVal = EditorGUILayout.Vector2Field("Voronoi UV", _Voronoi_UV.vectorValue);

Vector2Fieldは、ラベルとともにVector2の入力フィールドをInspectorに表示します。しかし、ここで扱っているのはVector4型の変数なので、このメソッドはその先頭2つの要素(XとY)のみを変更することができます。
同時に、最終的に_Voronoi_UVに代入する変数 VoronoiVal を設定してます。

  • VoronoiVal.z = EditorGUILayout.FloatField ("Voronoi size", _Voronoi_UV.vectorValue.z );

FloatFieldは、浮動小数点数の入力フィールドを表示します。ここでは、_Voronoi_UVのZ要素を変更するための入力フィールドを提供しています。

  • VoronoiVal.w = EditorGUILayout.Slider("Voronoi" , _Voronoi_UV.vectorValue.w , 0 , 1 );

Sliderは、指定された最小値と最大値の間で値をスライドさせて選択するためのスライダーを提供します。ここでは、_Voronoi_UV のW要素を0から1の間で変更するためのスライダーを表示しています。

そして、上記の設定が変更された場合に _Voronoi_UV.vectorValue = VoronoiVal; が実行されマテリアルに代入されます。

image.png


ボロノイを使用しない場合はボロノイを設定するプロパティを隠していた方が見た目的にも良いでしょう

というわけで、次のコードがプロパティの表示をON OFFする為のコードです。

materialEditor.ShaderProperty(_EnableVonoroi, "Enable Vonoroi");

if(_EnableVonoroi.floatValue == 1){

    using (new EditorGUILayout.VerticalScope("Box")){

            ///上記のVoronoiコードが入る

    }
}

image.png

  • materialEditor.ShaderProperty(_EnableVonoroi, "Enable Vonoroi");
    _EnableVonoroi のプロパティを表示します。Shaderコード側でToggle表示にしています。

  • if(_EnableVonoroi.floatValue == 1)
    上記で表示された _EnableVonoroi の値が1の場合にのみ、GUI要素を表示します。

  • using (new EditorGUILayout.VerticalScope("Box"))
    VerticalScopeはもう説明済みになりますが、ここではBOXを指定してカテゴリーを分けて見やすくしています。


Render Queue・Instance GPU ・Double Sided Global Illuminationの項目を表示させるには
下記のコードを追加します。

materialEditor.RenderQueueField();
materialEditor.EnableInstancingField();
materialEditor.DoubleSidedGIField();

その他にとても参考になるサイト

StandardShaderのカスタムGUIコード

警告文などの表示に

3
4
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
3
4