20
21

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.

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

Posted at

##アルファブレンディングについて
アルファブレンディングをするためには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をつけてる)
アルファブレンディングが正常に動作した。
スクリーンショット 2017-02-23 2.35.48.png

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

		Blend SrcAlpha OneMinusSrcAlpha

Blendしない場合はBlend Off (Blend指定しないとデフォルトでOffになる)
ちなみにBlend Offにするとこんな感じ
スクリーンショット 2017-02-23 2.37.51.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

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

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

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
		}
	}
}
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はステンシルテストに不合格のため描画されない
スクリーンショット 2017-02-23 3.30.28.png

わかりやすく青Cubeを大きくした。
背後に青Cubeがあり、ステンシルバッファに1が書き込まれているため、ピンクCubeがステンシルテストに合格したのでピンクCubeは描画された。
スクリーンショット 2017-02-23 3.31.43.png

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

結果:ステンシルテストが不合格の場合はデプステストは行われない。
ピンクCubeのステンシルテストをNeverにして必ず不合格にし、緑Cube(ピンクCubeよりQueueが大きい)をピンクCubeより奥に配置した。
緑Cubeが描画されているのでピンクCubeのデプステストが行われていないことがわかる
スクリーンショット 2017-02-23 3.39.51.png
スクリーンショット 2017-02-23 3.40.01.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
		}
	}
}

結果:
スクリーンショット 2017-02-23 4.48.31.png
青Cubeに埋め込んでみる
スクリーンショット 2017-02-23 4.55.38.png
複数用意
スクリーンショット 2017-02-23 4.56.11.png

アウトライン楽しい :)

20
21
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
20
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?