Unity でShaderの勉強 その6 アルファブレンディングとステンシルバッファ

##アルファブレンディングについて
アルファブレンディングをするためにはShaderにBendの記述が必要。

とりあえずアルファブレンディング用のShaderを書いてみた

```
Shader "Custom/TestShader2" {
	Properties {
		_Color("Color", Color) = (1,1,1,1)
	}

	SubShader {
		Tags { "Queue" = "Transparent" "RenderType" = "Transparent"}
		ZTest LEqual
		ZWrite On
		Blend SrcAlpha OneMinusSrcAlpha

		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			uniform float4 _Color;

			float4 vert(float4 pos : POSITION) : SV_POSITION {
				return mul(UNITY_MATRIX_MVP,pos);
			}

			float4 frag() : SV_TARGET {
				return _Color;
			}
			ENDCG
		}
	}
}
```

結果(手前のピンクCubeにTest2Shaderをつけてる)
アルファブレンディングが正常に動作した。
<img width="424" alt="スクリーンショット 2017-02-23 2.35.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/c3f7e500-6ce6-69cd-b172-1cc23f813065.png">

アルファブレンディングの仕方は様々あるらしい。
Unity Shaderでは次の行で指定している

```
		Blend SrcAlpha OneMinusSrcAlpha
```

Blendしない場合は`Blend Off` (Blend指定しないとデフォルトでOffになる)
ちなみにBlend Offにするとこんな感じ
<img width="420" alt="スクリーンショット 2017-02-23 2.37.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/e1b6c6b4-142b-7d60-741f-3d6443a8c131.png">

Blend SrcAlpha OneMinusSrcAlphaについて調べて見る

このあたりのサイトが参考になった。
http://masuqat.net/programming/csharp/OpenTK01-09.php
https://wgld.org/d/webgl/w029.html

Blend SrcAlpha OneMinusSrcAlphaとはfragmet処理後の色を決定するアルファブレンドの式に使用され、
fragment処理後の色 = 
デプスバッファに書き込まれている色 * SrcAlpha + 今から書き込もうとしている色 * OneMinusSrcAlpha
になるとのこと。

##ステンシルバッファについて
ここを参照
https://wgld.org/d/webgl/w038.html
http://qiita.com/edo_m18/items/95a7f350d1164486e03b

ステンシルバッファ => ステンシルテストに使う基準値を記録するバッファ
ステンシルテスト => デプステストみたいにそのピクセルに色を塗るかどうか判断するテスト

とりあえずコード書いてみた

```lang:TestShader
Shader "Custom/TestShader" {
	Properties {
		_Color("main Color" , Color) = (1,1,1,1)
	}

	SubShader {
		Tags { "Queue" = "Geometry" "RenderType" = "Opaque"}
		ZTest LEqual
		ZWrite On
		Pass {
			Stencil {
				Ref 1
				Comp Always
				Pass replace
			}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			uniform float4 _Color;

			float4 vert(float4 pos : POSITION) : SV_POSITION {
				return mul(UNITY_MATRIX_MVP,pos);
			}

			float4 frag() : SV_TARGET {
				return _Color;
			}
			ENDCG
		}
	}
}
```

```lang:TestShader2
Shader "Custom/TestShader2" {
	Properties {
		_Color("Color", Color) = (1,1,1,1)
	}

	SubShader {
		Tags { "Queue" = "Transparent" "RenderType" = "Transparent"}
		ZTest LEqual
		ZWrite On
		Blend SrcAlpha OneMinusSrcAlpha

		Pass {

			Stencil {
				Ref 1
				Comp Equal
				Pass replace
			}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			uniform float4 _Color;

			float4 vert(float4 pos : POSITION) : SV_POSITION {
				return mul(UNITY_MATRIX_MVP,pos);
			}

			float4 frag() : SV_TARGET {
				return _Color;
			}
			ENDCG
		}
	}
}
```

TestShaderは必ずRef1を書き込み、TestShader2はステンシルバッファに1が入っていた時のみ描画する。
そのためTestShader2の描画は背後にTestShaderを持ったオブジェクトがある時のみ行われるはず。

結果
青CubeがTestShader
ピンクCubeがTestShader2
ピンクCubeはステンシルテストに不合格のため描画されない
<img width="496" alt="スクリーンショット 2017-02-23 3.30.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/7064db16-d314-f656-eccc-c9d6e7b449c7.png">

わかりやすく青Cubeを大きくした。
背後に青Cubeがあり、ステンシルバッファに1が書き込まれているため、ピンクCubeがステンシルテストに合格したのでピンクCubeは描画された。
<img width="395" alt="スクリーンショット 2017-02-23 3.31.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/a9a58878-bbc2-fcb8-bafe-a381df45c941.png">

Shader処理の順番は、
fragment処理 => ステンシルテスト => (ステンシル合格なら) デプステスト => (デプステスト合格なら) 書き込み
となっている。
ステンシルテストが不合格の場合にデプステストは行われるのだろうか？

結果：ステンシルテストが不合格の場合はデプステストは行われない。
ピンクCubeのステンシルテストをNeverにして必ず不合格にし、緑Cube(ピンクCubeよりQueueが大きい)をピンクCubeより奥に配置した。
緑Cubeが描画されているのでピンクCubeのデプステストが行われていないことがわかる
<img width="517" alt="スクリーンショット 2017-02-23 3.39.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/fef39812-f7b7-8dae-21af-854943fe2b54.png">
<img width="468" alt="スクリーンショット 2017-02-23 3.40.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/3c070c4b-d45d-7550-db6a-f631011e0395.png">


##ステンシルを使ってアウトラインを書いてみる
こちらを参照
https://wgld.org/d/webgl/w039.html
http://tarowork.hatenablog.jp/entry/2014/07/27/193816

1Passでアウトライン用のStencilを書き込んで
2Passで本体描画
3Passでアウトライン描画

```
Shader "Custom/TestShader2" {
	Properties {
		_Color("Color", Color) = (1,1,1,1)
		_OutlineColor("Outline Color",Color) = (1,1,1,1)
		_OutlineWidth("outline width",Range(0,0.5)) = 0.01

	}

	SubShader {
		Pass {
			Tags { "Queue" = "Geometry-1" "RenderType" = "Opaque"}
			ZTest Off
			ZWrite Off
			ColorMask 0
			Cull Off

			Stencil {
				Ref 2
				CompFront always
				CompBack always
				PassFront replace
				PassBack replace
			}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform float _OutlineWidth;

			float4 vert(float4 pos : POSITION,float3 normal : NORMAL) : SV_POSITION {
				float4 wPos = mul(UNITY_MATRIX_MVP,pos);
				wPos += float4(UnityObjectToWorldNormal(normal) * _OutlineWidth,0);
				return wPos;
			}

			float4 frag() : SV_TARGET {
				return float4(1,1,1,1);
			}
			ENDCG
		}

		Pass {
			Tags { "Queue" = "Geometry" "RenderType" = "Opaque"}
			ZTest LEqual
			ZWrite On
			Stencil {
			  Ref 3
			  CompFront always
			  CompBack always
			  PassFront replace
			  PassBack replace
			  FailFront replace
			  FailBack replace
			//ZFailBack replace
			//ZFailFront replace
			}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			uniform float4 _Color;

			float4 vert(float4 pos : POSITION) : SV_POSITION {
				return mul(UNITY_MATRIX_MVP,pos);
			}

			float4 frag() : SV_TARGET {
				return _Color;
			}
			ENDCG
		}

		Pass {
			Tags { "Queue" = "Ovarlay" "RenderType" = "Opaque"}
			ZTest Off
			ZWrite Off

			Stencil {
				Ref 2
				Comp Equal
			}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			uniform float4 _OutlineColor;
			uniform float _OutlineWidth;

			float4 vert(float4 pos : POSITION,float3 normal : NORMAL) : SV_POSITION {
				float4 wPos = mul(UNITY_MATRIX_MVP,pos);
				wPos += float4(UnityObjectToWorldNormal(normal) * _OutlineWidth,0);
				return wPos;
			}

			float4 frag() : SV_TARGET {
				return _OutlineColor;
			}
			ENDCG
		}
	}
}
```

結果:
<img width="520" alt="スクリーンショット 2017-02-23 4.48.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/cc6b34d0-548a-e292-97db-dd79bf165ca6.png">
青Cubeに埋め込んでみる
<img width="548" alt="スクリーンショット 2017-02-23 4.55.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/45245ba9-0550-e59c-d915-789f7c27b3f4.png">
複数用意
<img width="391" alt="スクリーンショット 2017-02-23 4.56.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/f7f161c5-e6ae-d47f-c211-9f7640a6ecbc.png">

アウトライン楽しい :)