Unity Shader之模板測試
一沙一世界,一花一天堂
一、Stencil testing
當片段着色器處理完一個片段之後,模板測試(Stencil Test)會開始執行,和深度測試一樣,它也可能會丟棄片段。接下來,被保留的片段會進入深度測試,它可能會丟棄更多的片段。模板測試是根據又一個緩衝來進行的,它叫做模板緩衝(Stencil Buffer),我們可以在渲染的時候更新它來獲得一些很有意思的效果。
一個模板緩衝中,(通常)每個模板值(Stencil Value)是8位的。所以每個像素/片段一共能有256種不同的模板值。我們可以將這些模板值設置爲我們想要的值,然後當某一個片段有某一個模板值的時候,我們就可以選擇丟棄或是保留這個片段了。
二、模板函數
2.1 調用函數
- Stencil
- {
- Ref 1//Reference Value ReadMask 255 WriteMask 255 Comp Always //Comparison Function Pass Replace
- Fail Keep
- ZFail Replace
- }
2.2 參數說明
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
三、案例
3.1 描邊
- Shader "ShaderCookbook/stencil_outline" {
- Properties {
- _MainTex("Texture", 2D) = "white" {}
- _OutLineWidth("Width", float) = 0.01
- _OutLineColor("Color", color) = (1, 1, 1, 1)
- }
- SubShader {
- Tags {
- "RenderType" = "Opaque"
- }
- LOD 100
-
- Stencil {
- Ref 0 Comp Equal Pass IncrSat
- }
-
- Pass {
- CGPROGRAM
-
-
-
-
- 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 {
- // sample the texture
- fixed4 col = tex2D(_MainTex, i.uv);
- return col;
- }
- ENDCG
- }
-
- Pass {
- CGPROGRAM
-
-
-
- struct appdata {
- float4 vertex: POSITION;
- float4 normal: NORMAL;
- };
-
- struct v2f {
- float4 vertex: SV_POSITION;
- };
-
- fixed4 _OutLineColor;
- float _OutLineWidth;
- v2f vert(appdata v) {
- v2f o;
- v.vertex = v.vertex + normalize(v.normal) * _OutLineWidth;
- o.vertex = UnityObjectToClipPos(v.vertex);
- return o;
- }
- fixed4 frag(v2f i) : SV_Target {
- // sample the texture
- fixed4 col = _OutLineColor;
- return col;
- }
- ENDCG
- }
- }
- }
3.2 百寶箱
遮罩層:
- Shader "ShaderCookbook/StencilEnumMask"
- {
- Properties
- {
- _MainTex ("Texture", 2D) = "white" {}
- [ForceInt]
- _StencilRef("StencilRef",float) = 0
- [Enum(UnityEngine.Rendering.CompareFunction)]
- _StencilComp("StencilComp",int) =0
- [Enum(UnityEngine.Rendering.StencilOp)]
- _StencilOp("StencilOp",int)=0
-
- [ForceInt]
- _StencilReadMask("ReadMask",int)=255
- [ForceInt]
- _StencilWriteMask("WriteMask",int)=255
- [MaterialToggle]
- _ZWrite("zWrite",float)=0
- }
- SubShader
- {
- Tags { "RenderType"="StencilMaskOpaque"
- "Queue" = "Geometry-100"
- "IgnoreProjector" = "True" }
- LOD 100
-
-
- Pass
- {
- ColorMask 0
- ZWrite [_ZWrite]
-
- Stencil{
- Ref [_StencilRef]
- Comp[_StencilComp]
- Pass[_StencilOp]
- ReadMask[_StencilReadMask]
- WriteMask[_StencilWriteMask]
- }
-
- CGPROGRAM
- // make fog work
-
-
- struct appdata
- {
- float4 vertex : POSITION;
- float2 uv : TEXCOORD0;
- };
-
- struct v2f
- {
- float2 uv : TEXCOORD0;
- UNITY_FOG_COORDS(1)
- 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);
- UNITY_TRANSFER_FOG(o,o.vertex);
- return o;
- }
- fixed4 frag (v2f i) : SV_Target
- {
- // sample the texture
- fixed4 col = tex2D(_MainTex, i.uv);
- // apply fog
- UNITY_APPLY_FOG(i.fogCoord, col);
- return col;
- }
- ENDCG
- }
- }
- }
顯示層:
-
-
- Shader "ShaderCookbook/StencilEnum"
- {
- Properties
- {
- _MainTex ("Texture", 2D) = "white" {}
- [ForceInt]
- _StencilRef("StencilRef",float) = 0
- [Enum(UnityEngine.Rendering.CompareFunction)]
- _StencilComp("StencilComp",int) =0
- [Enum(UnityEngine.Rendering.StencilOp)]
- _StencilOp("StencilOp",int)=0
-
- [ForceInt]
- _StencilReadMask("ReadMask",int)=255
- [ForceInt]
- _StencilWriteMask("WriteMask",int)=255
- }
- SubShader
- {
- Tags { "RenderType"="opaque" }
- LOD 100
-
-
- Pass
- {
-
- Stencil{
- Ref [_StencilRef]
- Comp[_StencilComp]
- Pass[_StencilOp]
- ReadMask[_StencilReadMask]
- WriteMask[_StencilWriteMask]
- }
-
- CGPROGRAM
- // make fog work
-
-
- struct appdata
- {
- float4 vertex : POSITION;
- float2 uv : TEXCOORD0;
- };
-
- struct v2f
- {
- float2 uv : TEXCOORD0;
- UNITY_FOG_COORDS(1)
- 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);
- UNITY_TRANSFER_FOG(o,o.vertex);
- return o;
- }
- fixed4 frag (v2f i) : SV_Target
- {
- // sample the texture
- fixed4 col = tex2D(_MainTex, i.uv);
- // apply fog
- UNITY_APPLY_FOG(i.fogCoord, col);
- return col;
- }
- ENDCG
- }
- }
- }
Ad
這裏推薦一款可視化shader編程工具,對美術同學非常友好,就像建模工具中的材質編輯器一樣