1. 程式人生 > >Shader-StencilTest(模版測試)

Shader-StencilTest(模版測試)

模版測試較為複雜,它不像Alpha測試一樣,單單通過簡單的大於小於等運算子來比較,但是和Alpha測試一樣,都是測試畫素點,符合要求的就渲染,不符合要求的就不渲染。瞭解模版測試,需要理解較多術語:

1.GBuffer:幾何緩衝,相當於一個容器

2.RefenceValue:模版值,Guffer中的畫素點就是與這個值按位與後進行比較

3.stencilOperation:比較後進行的操作

4.ReadMask|WriteMask:讀遮罩|寫遮罩

理解了以上的術語,那麼模版測試的公式就差不多可以理解了:其公式為:

referenceValue&readMask comparisonFunction

 stencilBufferValue&readMask

如果滿足了以上公式,就會通過模版測試,反之亦然。

emmmm。。。。。博主還是感覺口說不如實踐,下面用一個穿牆透視的例子來幫助讀者理解模版測試

 

1.首先,在場景中新建三個Cube,並調整位置,使其分別在前,中,後三個位置,並且其大小順序為   中>前>後。

如圖所示:

2.新建三個材質與三個Shader,將三個Shader拖到三個材質上,並將三個材質分別拖到三個遊戲物體上。

3.編寫最前面遊戲物體的Shader,如下:

Shader "Hidden/StencilTestFront"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		ZWrite Off  //深度測試,這裡不作解釋,不理解的可以去unity官方文件上查閱
		Pass
		{
		//CompareFunction:
		//Greater 	當GBufffer中的值大於Ref的值時才渲染(這裡指的是公式中按位與之後的結果的比較,後面都是指的這個,以後不再說明)
		//GEqual 	當GBufffer中的值大於或者等於Ref的值時才渲染
		//Less 	...小於...
		//LEqual 	...小於或者等於...
		//Equal 	...等於...
		//NotEqual 	...不等於...
		//Always 	總是通過
		//Never 	總是不通過


		//Operator:
		//Keep 	保持GBuffer中的值不變
		//Zero 	將0寫入GBuffer
		//Replace 	替換GBuffer中的值為Ref。
		//IncrSat   遞增GBuffer中的值,如果該值等於255,則保持不變
		//DecrSat 	遞減GBuffer中的值,如果該值等於0,則保持不變
		//Invert 	按位取反GBuffer中的值
		//IncrWrap 	遞增GBuffer中的值,如果該值等於255,則變成0
		//DecrWrap 	遞減GBuffer中的值,如果該值等於0,則變成255
			Stencil
			{
				Ref 2  //設定參考值為2
				Comp always   //讓模版測試總是通過
				Pass replace	//如果上面模版測試通過,就將GBuffer中的值替換為Ref的值
			}
			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
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				return col;
			}
			ENDCG
		}
	}
}

 4.編寫middle的Shader,程式碼如下:

Shader "Hidden/StencilTestMiddle"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		// No culling or depth
		//Cull Off ZWrite Off ZTest Always

		Pass
		{
			Stencil
			{
				Ref 2
				Comp NotEqual
			}
			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
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				// just invert the colors
				//col.rgb = 1 - col.rgb;
				return col;
			}
			ENDCG
		}
	}
}

5.編寫Back的Shader,程式碼如下:

Shader "Hidden/StencilTestBack"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		// No culling or depth
		//Cull Off ZWrite Off ZTest Always

		Pass
		{
			Stencil
			{
				Ref 2
			}
			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
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				// just invert the colors
				//col.rgb = 1 - col.rgb;
				return col;
			}
			ENDCG
		}
	}
}

 完成之後,即可檢視效果: