4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

StandardShaderのMode選択機能をカスタムシェーダーに入れたい!

Last updated at Posted at 2017-11-09

#カスタムシェーダーのInspectorもこだわりたい。
StandardShaderの一番上についているRenderting Modeのプルダウンメニュー
自作シェーダーのBlendModeをいじるたびにコレつけられたらかっこいいのに!
と思ってました。

↓コレ
StandardMode.png

というわけで、ちょっとチャレンジしてみることにしました。
Unity2017.2.0f3で動作確認しています。

#参考
・builtin_shadersの中に含まれるeditor/StandardShaderGUI.cs
・安藤圭吾さんのエディター拡張入門
第6章 EditorGUI (EdirotGUILayout)

#まずは準備
shadersample.png

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設計ができそうな気がしてきました。

kekka1.png

kekka2.png

#それぞれの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;
        }
    }

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?