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_ST`は`UnityCG.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上で綺麗にまとめる

![スクリーンショット 2019-12-17 13.35.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146297/79cf4459-759f-f6fe-6204-b8be839a1566.png)

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



## 追加しようか迷った機能


- ZWrite
- ZTest


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


## 今後やりたいこと

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


## まとめ

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

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