官方文檔地址:
https://docs.unity3d.com/Manual/SL-Stencil.html
參考博客:
http://blog.csdn.net/onafioo/article/details/53943264
http://blog.csdn.net/u013833399/article/details/47340447
(因表述的內容都大致一樣,一些內容直接引用自原作者)
1.簡介
在Unity中一個像素會有多個緩存信息,模版緩存(其實Stencil不應該被翻譯成模版,但網上都這么寫)是其中之一。
模板緩沖區可以為屏幕上的每個像素點保存一個無符號整數值,
通過一些比較來改變當前像素區域模版緩沖的值,從而改變深度關系,似乎UGUI的Mask也是通過其實現的
延遲光照中Stencil有一些限制,具體看unity的文檔,這里只介紹正向光照中的使用
Stencil所在的渲染管線中的順序位置:
Stencil的所有參數如下
Stencil { Ref 1//Reference Value ReadMask 255 WriteMask 255 Comp Always //Comparison Function Pass Replace Fail Keep ZFail Replace }
Ref 就是參考值,當參數允許賦值時,會把參考值賦給當前像素
ReadMask 對當前參考值和已有值進行mask操作,默認值255,一般不用
WriteMask 寫入Mask操作,默認值255,一般不用
Comp 比較方法。是拿Ref參考值和當前像素緩存上的值進行比較。默認值always
- Greater - 大於
- GEqual - 大於等於
- Less - 小於
- LEqual - 小於等於
- Equal - 等於
- NotEqual - 不等於
- Always - 永遠通過
- Never - 永遠通不過
Pass 當模版測試和深度測試都通過時,進行處理
Fail 當模版測試和深度測試都失敗時,進行處理
ZFail 當模版測試通過而深度測試失敗時,進行處理
pass,Fail,ZFail都屬於Stencil操作,他們參數統一如下:
- Keep 保持(即不把參考值賦上去,直接不管)
- Zero 歸零
- Replace 替換(拿參考值替代原有值)
- IncrSat 值增加1,但不溢出,如果到255,就不再加
- DecrSat 值減少1,但不溢出,值到0就不再減
- Invert 反轉所有位,如果1就會變成254
- IncrWrap 值增加1,會溢出,所以255變成0
- DecrWrap 值減少1,會溢出,所以0變成255
2.實踐
下面結合案例,說一下Stencil的使用
現在有一個球和面片,通過Stencil模版測試把stencil值一致的物體渲染為藍色
為了更直觀使用了兩個shader,面片是shader1,球是shader2
球肯定是優先渲染,並且設置好stencil的值,面片后渲染,並且判斷stencil的值
文件結構:
MaskTest2是球的shader

Shader "Unlit/MaskTest2" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags{ "RenderType" = "Opaque" "Queue" = "Geometry" } Stencil { Ref 1 Comp Always Pass Replace } Pass { 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; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { return fixed4(1,1,1,1); } ENDCG } } }
Stencil里,比較條件設置為總通過,通過操作設置為替換Ref值
這樣球部分的像素Stencil值就是1
Stencil { Ref 1 Comp Always Pass Replace }
MaskTest1是面片的Shader

Shader "Unlit/MaskTest1" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags{ "RenderType" = "Opaque" "Queue" = "Geometry+1" } Stencil { Ref 1 Comp equal } Pass { 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; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { return fixed4(0,0,1,1); } ENDCG } } }
Stencil里,比較條件是和Ref值一致時,才會執行渲染
否則跳出
Stencil { Ref 1 Comp equal }
藍色是片段shader里寫好的
fixed4 frag (v2f i) : SV_Target { return fixed4(0,0,1,1); }
這樣就可以達到上述效果。
測試工程文件下載:http://files.cnblogs.com/files/hont/StencilMaskTest.zip