unity ShaderLab 基礎之【模板測試 StencilTest】StencilTest命令詳解

模板測試 StencilTest

【說明】:模板測試,用於處理重合的像素該如何顯示。與深度和透明測試不同的是,模板測試可以更自由跟獨立的自定義顯示。
【原理】:屏幕的每個像素都有一個stencil值,在同一個像素上,所有shader的stencil都共享這一個值,當有其他帶有stencil值的像素與其重合時就能獲取到該值,並根據自身的stencil值處理或。
【舉例1】:典型的應用就是遮罩顯示。你可以選擇每次重合都增加1,然後再指定某個物體,當值達到某個數量級再顯示。
【舉例2】:比如,有個隱身的怪物,你只有使用聖水噴霧才能讓他現行,但必須噴3次纔行,這樣,空中就存在了3次疊加的霧,透過這個3層霧就能看到怪物了。但你偏一下角度,透過兩層霧就看不到。
【舉例3】:紅警、魔獸爭霸、星際爭霸中的迷霧系統。

模板測試與透明測試、深度測試的關係與區別

共同點:這三大測試都是用於決定 是否顯示當前像素
不同點:深度測試是用於處理前後遮擋關係,透明測試用於處理透明閾值,而模板測試屬於處理像素重合關係。雖然野可以說是遮擋關係,但模板測試並不像深度測試那樣着重與前後順序,模板只關注重疊及自定義觸發條件。

Stencil完整語法:

stencil{
	Ref referenceValue //每個像素都有一個stencil值,在同一個像素上,所有shader的stencil都共享這一個值,當有其他帶有遮罩像素與其重合時就能獲取到該值,並根據自身的stencil值處理觸發小狗
	ReadMask  readMask  //讀遮罩
	WriteMask writeMask  //寫遮罩
	Comp comparisonFunction   //條件判斷  大於小於等觸發
	Pass stencilOperation    //滿足條件後,相應的處理辦法   是替換值還是增長值等
	Fail stencilOperation    //沒有通過模板測試怎麼辦
	ZFail stencilOperation    //通過了模板測試怎麼辦
}

模板語法

參數 說明 實例
Ref ref用來設定參考值(範圍0-255)。這個值用來與stencilbuffer比較
ReadMask ReadMask 從字面意思的理解就是讀遮罩,readMask將和referenceValue以及stencilBufferValue進行按位與(&)操作,readMask取值範圍也是0-255的整數,默認值爲255,二進制位11111111,即讀取的時候不對referenceValue和stencilBufferValue產生效果,讀取的還是原始值
WriteMask WriteMask是當寫入模板緩衝時進行掩碼操作(按位與【&】),writeMask取值範圍是0-255的整數,默認值也是255,即當修改stencilBufferValue值時,寫入的仍然是原始值。
Comp Comp是定義參考值(referenceValue)與緩衝值(stencilBufferValue)比較的操作函數,默認值:always
Pass Pass是定義當模板測試(和深度測試)通過時,則根據(stencilOperation值)對模板緩衝值(stencilBufferValue)進行處理,默認值:keep
Fail Fail是定義當模板測試(和深度測試)失敗時,則根據(stencilOperation值)對模板緩衝值(stencilBufferValue)進行處理,默認值:keep
ZFail ZFail是定義當模板測試通過而深度測試失敗時,則根據(stencilOperation值)對模板緩衝值(stencilBufferValue)進行處理,默認值:keep

模板對比

指令 說明 實例
Greater 大於,只渲染大於該值的像素。 alphatest greater [_alphaValue] //類似於摳圖
Less 小於,只渲染小於該值的像素。 類似於反向摳圖
GEqual 大於等於
LEqual 小於等於
Equal 等於
NotEqual 不等於
Always 總是
Never 永不
Off 關閉 alphatest Off

模板操作

指令 說明 實例
Keep 保留當前緩衝中的內容,即stencilBufferValue不變
Zero 將0寫入緩衝,即stencilBufferValue值變爲0。
Replace 將參考值寫入緩衝,即將referenceValue賦值給stencilBufferValue。
IncrSat stencilBufferValue加1,如果stencilBufferValue超過255了,那麼保留爲255,即不大於255。
DecrSat stencilBufferValue減1,如果stencilBufferValue超過爲0,那麼保留爲0,即不小於0。
Invert 將當前模板緩衝值(stencilBufferValue)按位取反
IncrWrap 當前緩衝的值加1,如果緩衝值超過255了,那麼變成0,(然後繼續自增)
DecrWrap 當前緩衝的值減1,如果緩衝值已經爲0,那麼變成255,(然後繼續自減) 。

實例:遮罩
將此shader付給遮罩物體

Shader "Custom/st1" {
	SubShader{
		Tags { "RenderType" = "Opaque" "Queue" = "Geometry-1"}
			CGINCLUDE
				struct appdata {
					float4 vertex : POSITION;
				};
				struct v2f {
					float4 pos : SV_POSITION;
				};
				v2f vert(appdata v) {
					v2f o;
					o.pos = UnityObjectToClipPos(v.vertex);
					return o;
				}
				half4 frag(v2f i) : SV_Target {
					return half4(1,1,0,1);
				}
			ENDCG
			Pass {
				ColorMask 0
				ZWrite Off
				Stencil
				{
					Ref 1
					Comp Always
					Pass Replace
				}
				CGPROGRAM
					#pragma vertex vert
					#pragma fragment frag
				ENDCG
			}
	}
}

將此shader付給被遮罩物體

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'


Shader "Custom/st2" {
	Properties{
	_MainTex("Base (RGB)", 2D) = "white" {}
	}
		SubShader{
			Tags { "Queue" = "Geometry" "RenderType" = "Opaque" }
			LOD 100
			Pass {
				Stencil
				{
					Ref 2
					Comp Equal
				}
				CGPROGRAM
					#pragma vertex vert
					#pragma fragment frag
					#pragma multi_compile_fog
					#include "UnityCG.cginc"
					struct appdata_t {
						float4 vertex : POSITION;
						float2 texcoord : TEXCOORD0;
					};
					struct v2f {
						float4 vertex : SV_POSITION;
						half2 texcoord : TEXCOORD0;
						UNITY_FOG_COORDS(1)
					};
					sampler2D _MainTex;
					float4 _MainTex_ST;
					v2f vert(appdata_t v)
					{
						v2f o;
						o.vertex = UnityObjectToClipPos(v.vertex);
						o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
						UNITY_TRANSFER_FOG(o,o.vertex);
						return o;
					}
					fixed4 frag(v2f i) : SV_Target
					{
						fixed4 col = tex2D(_MainTex, i.texcoord);
						UNITY_APPLY_FOG(i.fogCoord, col);
						UNITY_OPAQUE_ALPHA(col.a);
						return col;
					}
				ENDCG
			}
	}
}

即可完成

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章