#カスタムシェーダーのInspectorもこだわりたい。
StandardShader
の一番上についているRenderting Mode
のプルダウンメニュー
自作シェーダーのBlendMode
をいじるたびにコレつけられたらかっこいいのに!
と思ってました。
というわけで、ちょっとチャレンジしてみることにしました。
Unity2017.2.0f3
で動作確認しています。
#参考
・builtin_shadersの中に含まれるeditor/StandardShaderGUI.cs
・安藤圭吾さんのエディター拡張入門
第6章 EditorGUI (EdirotGUILayout)
Create > Shader>Unlit Shader
名前をGUITest
Create >Material
できたMaterialに先ほどのShaderをアタッチ
Editorフォルダを作って中にCreate > C# Script
名前は適当に付けました。 一応画像の通りにしてあります。
Shaderの最後にCustomEditor "BlendTestGUI"
(名前は任意)
こうすることでこのShaderはMaterial経由でInspectorに表示される時は指定されたScriptを
参照するようになるみたいです。
ちなみに、Standard.Shaderは末尾にCustomEditor "StandardShaderGUI"
と書いてありますね。
#調べたこと
StandardShaderGUI.csの中にModeの設定について記載がありました。
public enum BlendMode
public static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode)
BlendModeの定義を使ってSetupMaterialWithBlendModeで値をセットしているみたいです。
StandardShaderGUIは長いので後はEditorGUIを調べつつシンプルに実装していきます。
※ソースは下記参照してください
Inspectorの表示物はこの中↓に記載します
OnInspectorGUI()
流れとしては。
Material targetMat = target as Material;
ここで扱うMaterialを確保しておいて
EditorGUI.BeginChangeCheck();
これでGUI内の変更を監視しつつ、表示部本体を表示
if (EditorGUI.EndChangeCheck())
ここで変更があった場合にパラメータをMaterialにセットしていきます。
セット忘れると、GUIはいじれても値がセットされません。
Materialの設定項目そのものはStandardShader
からコピペになっています。
#結果
さあどうでしょうか。無事モードセレクトが表示されました。
このあとは設定項目にAdditive
を追加してみたりとか夢がひろがります。
Materialを設定する人が使いやすいGUI設計ができそうな気がしてきました。
#それぞれのScriptの中身
Shaderの中はこんな感じにしています。
Shader "Custom/GuiTest"
{
Properties
{
_Color("Color",color) = (1,1,1,1)
_MainTex ("Texture", 2D) = "white" {}
[HideInInspector] _Mode("Mode", Float) = 0.0
[HideInInspector]_SrcBlend("Blend Src", Float) = 0
[HideInInspector]_DstBlend("Blend Dst", Float) = 0
[HideInInspector]_ZWrite("ZWrite", Float) = 0
}
SubShader
{
LOD 100
Pass
{
Blend[_SrcBlend][_DstBlend]
ZWrite[_ZWrite]
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _Color;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv) * _Color;
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
CustomEditor "BlendTestGUI"
}
Edirorの中に作成したBlendTestGUI.csはこんな感じです。
public class BlendTestGUI : MaterialEditor
{
public override void OnInspectorGUI()
{
if (!isVisible)
return;
//Materialを所得
Material targetMat = target as Material;
//GUIの変更をチェック開始
EditorGUI.BeginChangeCheck();
//表示物本体
//Mode選択
BlendMode SelectedMode = (BlendMode)EditorGUILayout.EnumPopup("ブレンドモード", (BlendMode)targetMat.GetFloat("_Mode"));
Color color = EditorGUILayout.ColorField("MainColor",targetMat.color);
Texture Texture = EditorGUILayout.ObjectField(targetMat.GetTexture("_MainTex"),
typeof(Texture),false, GUILayout.Width(64), GUILayout.Height(64)) as Texture;
Vector2 Tiling = EditorGUILayout.Vector2Field("Tiling", targetMat.GetTextureScale("_MainTex"),
GUILayout.Width(200), GUILayout.Height(32));
Vector2 Offset = EditorGUILayout.Vector2Field("Offset", targetMat.GetTextureOffset("_MainTex"),
GUILayout.Width(200), GUILayout.Height(32));
//GUIの変更点をMaterialに反映
if (EditorGUI.EndChangeCheck())
{
targetMat.SetFloat("_Mode", (float)SelectedMode);
SetupMaterialWithBlendMode(targetMat, SelectedMode);//BlendModeも保存
targetMat.SetColor("_Color", color);
targetMat.SetTexture("_MainTex", Texture);
targetMat.SetTextureScale("_MainTex", Tiling);
targetMat.SetTextureOffset("_MainTex", Offset);
}
}
//StandardShaderGUI.csから引っこ抜き
public enum BlendMode
{
Opaque,
Cutout,
Fade, // Old school alpha-blending mode, fresnel does not affect amount of transparency
Transparent // Physically plausible transparency mode, implemented as alpha pre-multiply
}
public static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode)
{
switch (blendMode)
{
case BlendMode.Opaque:
material.SetOverrideTag("RenderType", "");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
break;
case BlendMode.Cutout:
material.SetOverrideTag("RenderType", "TransparentCutout");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.EnableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest;
break;
case BlendMode.Fade:
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
break;
case BlendMode.Transparent:
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
break;
}
}
}