Standard Shaderを作ろう


Standard Shader を作ろう

ワタシ Unity ワカラナイ Shader モ ワカラナイ

マテリアルを作成する際にデフォルトで「Standard Shader」が設定されますが
2Dゲームでは持て余してしまう機能ばかりなので
UnityのStandardなシェーダーではなく
自分で好きにカスタマイズしたStandardなシェーダーを作ってみました

とりあえず必要だろうと思う機能

  • Blend Mode の設定
  • Culling Mode の設定
  • Stencil Id の設定
  • Stencil Operation の設定
  • Stencil Comparison の設定
  • Color Mask の設定
  • Main Texture の設定
  • Add Color の設定

全部Propertiesで定義してInspector上で調整できるようにします

Blend Mode の設定

Properties
_BlendSrc ("Blend Src", Int) =  5
_BlendDst ("Blend Dst", Int) = 10
SubShader
Blend [_BlendSrc] [_BlendDst]

デフォルトで半透明合成の設定にしておくと割と困ることはない気がします
5: SrcAlpha
10: OneMinusSrcAlpha
なので

SubShader
Blend SrcAlpha OneMinusSrcAlpha 

と同定義
BlendModeを簡単に設定する方法や詳細についてはまた別の記事にまとめようかなと思います

Culling Mode

Properties
[KeywordEnum(None, Front, Back)] _Cull("Culling", Int) = 2
SubShader
Cull [_Cull]

デフォルトで裏面は描画しないという設定にしておく
None 両面描画
Front 表面は描画しない
Back 裏面は描画しない
オプションはあらかじめ列挙しておく
列挙内容はUnityEngine.Rendering.CullModeに合わせる
FrontとBackはよく使うけどNoneはあまり使わないイメージ

Stencilの設定

Properties
_Stencil ("Stencil ID", Int) = 0
[KeywordEnum(Disabled, Never, Less, Equal, LessEqual, Greater, NotEqual, GreaterEqual, Always)] _StencilComp("Stencil Comparison", Int) = 8
[KeywordEnum(Keep, Zero, Replace, IncrSat, DecrSat, Invert, IncrWrap, DecrWrap)] _StencilOp("Stencil Operation", Int) = 0
SubShader
Stencil
{
  Ref [_Stencil]
  Comp [_StencilComp]
  Pass [_StencilOp]
}

Stencil周りの設定は本当に便利なのでこの辺の設定が自由に効くようにしておくと後々幸せになれそうですね
_Stencil 自由に書き換えれるようにする
_StencilComp オプションを列挙する(UnityEngine.Rendering.CompareFunctionに合わせる)
_StencilOp オプションを列挙する(UnityEngine.Rendering.StencilOpに合わせる)
ステンシルテストやOpやCompについてはまた別記事にまとめます

ColorMaskの設定

Properties
_ColorMask ("Color Mask", Float) = 15
SubShader
ColorMask [_ColorMask]

カラーマスクの設定は自由に書き換えられるようにする
うーん...使うか...???

MainTexture の設定

Properties
_MainTex ("Sprite Texture", 2D) = "white" {}
Pass
sampler2D _MainTex;
fixed4 _TextureSampleAdd;
float4 _MainTex_ST;

_MainTexはコンポーネントに設定されているテクスチャを参照してるので
マテリアルのInspector上でテクスチャの変更してしまうと上書きされてしまいます
上書きしたくない場合はProperties内で[PerRendererData]を付け加える必要があります

Properties
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}

これでマテリアル側からテクスチャを書き換えられる心配はなくなります
ただ、マテリアル側でテクスチャを設定しておきたいという場合もあるので
プロジェクトに合わせて_MainTexを秘匿にするかどうかを考えるべきだと思います

_TexturesampleAddはAlpha8のテクスチャが入ってきたときのために対策として付け加えます
_TexturesampleAddは基本RGBA(0,0,0,0)が代入されていますが
Alpha8のテクスチャが入ってきたときRGBA(1,1,1,0)が代入されるので黒の部分を白に塗り変えます
そもそもAlpha8のテクスチャを用意しないというのであれば不要なのですが念の為

_MainTex_STUnityCG.cgincをincludeしているため定義する必要があります
UnityCG.cginc内で_MainTex_STを利用しているのでコンパイルエラー回避のため定義します
UnityCG.cgincを利用しないのであれば定義する必要はありません

AddColor の設定

Properties
_Color ("Add Color", Color) = (1, 1, 1, 1)
SubShader
float4 _Color;

追加で乗算するためのカラー
マテリアルのInspectorから編集できるようにしています
コンポーネントに付属しているカラー編集とは別になるので混同しないよう気をつけてください

vertex shader

pass

fragmentOutput vert(vertexOutput input)
{

    fragmentOutput output;

    output.pos = UnityObjectToClipPos(input.pos);
    output.uv = TRANSFORM_TEX(input.uv, _MainTex);
    output.color = input.color * _Color;

    return output;
}

これといって特に珍しいことはしていないです
ごく普通の頂点シェーダー

fragment shader

Pass
float4 frag(fragmentOutput input) : SV_Target
{

    float4 outColor = (tex2D(_MainTex, input.uv) + _TextureSampleAdd) * input.color;

    return outColor;
}

こちらも特に珍しいことはしていないです
単純にテクスチャーのカラーを返しているのみのピクセルシェーダーになります
追加でマテリアル側からカラーを乗算できるようにしているくらい

Inspector上で綺麗にまとめる

GUIを整理してわかりやすいようにグループ分けしたり
見やすいようにウィンドウを分けたりしてエンジニア以外でも触りやすいように心がけるようにしたいですね
GUI周りについてはまた別記事にまとめます

追加しようか迷った機能

  • ZWrite
  • ZTest

MUSTではなかったので追加しなかったんですが
利便性を考えると追加しても良かったのかもしれないですね

今後やりたいこと

新しくマテリアルを生成した際にUnityのStandardなシェーダーが設定されるのではなく
デフォルトでカスタムしたStandardシェーダーが設定されるようにしたいなあと
Unityのファイルインポート時に任意の処理を走らせることができるらしいのでそれで対応していこうかなと思います。

まとめ

UnityのStandardなシェーダーではなくカスタムしたStandardシェーダーを用意することによっていらない処理とかを省くようにする
機能を持て余しておくとあとで痛い目に合いそうなので必要に応じていらないものは削ぎ落としていくことを常に考えようと思います

不明な点や間違っている点などがあったら遠慮せずコメントください