Stencil (模板测试/蒙版测试):
与深度测试,透明度测试类似,决定一个片元是否被扔掉。深度测试的比较数据在深度缓冲中,透明度测试的比较对象是颜色缓冲中的值,而模版测试的比较数据在Stencil中,并且模板测试要先于深度测试与透明度测试,在fragment函数之前就会执行模板测试。
Ref 就是参考值,当参数允许赋值时,会把参考值赋给当前像素
ReadMask 对当前参考值和已有值进行mask操作,默认值255,一般不用
WriteMask 写入Mask操作,默认值255,一般不用
Comp 比较方法。是拿Ref参考值和当前像素缓存上的值进行比较。默认值Always
Pass 当模版测试和深度测试都通过时,进行处理
Fail 当模版测试和深度测试都失败时,进行处理
ZFail 当模版测试通过而深度测试失败时,进行处理
Comp :
Always
Greater - 大于
GEqual - 大于等于
Less - 小于
LEqual - 小于等于
Equal - 等于
NotEqual - 不等于
Always - 永远通过
Never - 永远通不过
pass,Fail,ZFail:
Keep 保持(即不把参考值赋上去,直接不管)
Zero 归零
Replace 替换(拿参考值替代原有值)
IncrSat 值增加1,但不溢出,如果到255,就不再加
DecrSat 值减少1,但不溢出,值到0就不再减
Invert 反转所有位,如果1就会变成254
IncrWrap 值增加1,会溢出,所以255变成0
DecrWrap 值减少1,会溢出,所以0变成255
模板测试示例1:被cube挡住sphere也能显示出来
效果如图:
代码如下:
Shader "MyShader/003"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_RefVal("stencil ref value",int)=0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Tags{"LightMode"="ForwardBase" "Queue"="2"}
ZTest Always//Always指的是直接将当前像素颜色(不是深度)写进颜色缓冲区中
Stencil
{
Ref[_RefVal]
Comp GEqual//比较成功条件 大于等于
Pass Replace//条件成立 写入STENCIL ENABLE
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
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
}
}
}
sphere的stencil ref value设为3,cube的stencil ref value设为2,虽然cube挡住了sphere,但sphere也能显示出来。
模板测试示例2:被cube挡住sphere也能显示出来
效果和模板测试示例1的效果一样,但模板测试示例1中的物体共用一个shader。而这个是分别用一个shader,Stencil不一样,并且Tags中的Queue也不一样。
背景的shader:
Shader "MyShader/stencilBackground"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_RefValue("stencil ref value",int)=0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Tags{"LightMode"="ForwardBase" "Queue"="Geometry"}
Stencil
{
Ref[_RefValue]
Pass Replace
Fail Replace
ZFail Replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
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:
Shader "MyShader/stencilSphere"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_RefValue("stencil ref value",int) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Tags{"LightMode" = "ForwardBase" "Queue" = "Geometry+1"}
//ColorMask 0//不输出任何颜色值
//ColorMask r//只输出r通道的颜色值
Stencil
{
Ref[_RefValue]
Comp GEqual
Pass Replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
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:
Shader "MyShader/stencilCube"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_RefValue("stencil ref value",int)=0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Tags{"LightMode"="ForwardBase" "Queue"="Geometry+2"}
Stencil
{
Ref[_RefValue]
Comp GEqual
Pass Replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
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
}
}
}
Tags中的Queue值越小就越先渲染,所以先渲染背景,再渲染小球,最后再渲染长方体。模板测试使得被挡住的小球也能显示出来。
模板测试示例3:区域蒙版
使用前:
使用后:
长方体cube的代码:
Shader "MyShader/stencilBase"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_RefValue("stencil ref value",int)=0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Tags{"LightModel"="ForwardBase" "Queue"="Geometry"}
Stencil
{
Ref[_RefValue]
Comp Always
Pass Replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
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
}
}
}
小球sphere的代码:
Shader "MyShader/stencilAdd"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_RefValue("stencil ref value",int) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Tags{"LightModel" = "ForwardBase" "Queue" = "Geometry+1"}
Stencil
{
Ref[_RefValue]
Comp Equal
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
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
}
}
}