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
Pass 当模版测试和深度测试都通过时,进行处理
Fail 当模版测试和深度测试都失败时,进行处理
ZFail 当模版测试通过而深度测试失败时,进行处理
pass,Fail,ZFail都属于Stencil操作,他们参数统一如下:
2、实践
下面结合案例,说一下Stencil的使用
现在有一个球和面片,通过Stencil模版测试把stencil值一致的物体渲染为蓝色。
为了更直观使用了两个shader,面片是Panel,球是Sphere。
注意:
球如果是优先渲染的话,会导致深度值无法比较。所以本案例:面片先渲染,并且设置好stencil的值;球后渲染,并且判断stencil的值。
文件结构:
Shader "Stencil/Panel"
{
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
}
}
}
MaskTest2
Stencil里,比较条件设置为总通过,通过操作设置为替换Ref值;
这样球部分的像素Stencil值就是1
Stencil
{
Ref 1
Comp Always
Pass Replace
}
Shader "Stencil/Sphere"
{
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);
}