ステンシルバッファ,ステンシルテスト
ステンシルバッファとはすべてのピクセルが保持している非負の整数値(8bit)のことです.描画するモデル(material1つ単位)でステンシルバッファの値が決められていてその値と,これから書き込むピクセルのステンシルバッファに保持されている値を比較してそのモデルをフラグメント単位で描画するかしないかを決定することが出来ます.
ステンシル値を書き込んでみる
まず1番シンプルな形から書いていきます.
Shader "Hidden/Stemcil01"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
Stencil{
Ref 1
Comp Less
Pass Replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target
{
return half4(0,0.8,0.9,1);
}
ENDCG
}
}
}
vertexやfragmentのコードも一緒に乗せてはいるんですが大切なのはほんの一部です.今後のサンプル掲載は長くなってしまうのでこの部分だけ載せますね.
Stencil{
Ref 1
Comp Greater//比較処理方法の指定
Pass Replace//比較処理に合格した際の処理内容
}
###結果
これで青いPlaneを描画する際に参照値(今回は1)がこれから描画したい領域のステンシルバッファ値よりも大きいとき(Greater)その領域のステンシルバッファの値を1に書き換える(Replace)っていうサンプルです.
デフォルトのステンシルバッファ値
次にデフォルトでのステンシルバッファの値が気になってきます.予想もつくかもしれませんが0です.念のため確認していきましょう.
Stencil{
Ref 0
Comp Equal
Pass Replace
}
先ほどのように考えていきましょう.これから描画したい領域のステンシルバッファの値が0(Ref値)と等しい(Comp Equal)ならば描画するという物です.よってデフォルトのバッファが0であることがわかりました.
###結果
深度情報による位置関係を崩してみる
こんな感じでデプス関係では明らかに青いplaneの方が前に来ているにも関わらずピンクのplaneが前方に現れるものを作ってみます.
Stencil {
Ref 1
Comp Always
Pass Replace
}
Stencil {
Ref 2
Comp Greater
Pass Replace
}
こんな感じでblueの方はこれから書き込みたい領域のバッファ値と2を比べて大きければ描画します.しかしpinkの方でのステンシルテストの方法alwaysにすると常にステンシルテストをpassすることになってしまうためこのようなことがおきます.
マルチパス
青いplaneは取り合えず2でバッファ値を埋めます.
Stencil{
Ref 2
Comp Greater
Pass Replace
}
ピンクのplaneは背景(何も書かれていないところ)つまりバッファの値が0の部分の領域に描く際にはピンクを1pass目で指定して,先ほど指定した青いplaneによって書き込まれたバッファ値2と等しい際にはグレーを指定しています.
Shader "Hidden/Stemcil01"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
Stencil {
Ref 0
Comp Equal
Pass Replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target
{
return fixed4(0.9, 0.0, 0.85, 1.0);
}
ENDCG
}
Pass
{
Stencil {
Ref 2
Comp Equal
Pass Replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
fixed4 frag(v2f i) : SV_Target
{
return fixed4(0.2, 0.2, 0.2, 1.0);
}
ENDCG
}
}
}
まとめ
導入にすぎませんが色々と面白い活用事例があるので調べてみるとより学ぶモチベーションが上がるかもしれませんね.活用事例がまとまったサイトを1つ上げておきます.
http://tsubakit1.hateblo.jp/entry/2015/11/22/065743