模板測試 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
}
}
}
即可完成