示例: 利用Sphere在Cube身上挖个洞
Shader "Custom/StencilTest"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
//利用模板可实现像素级遮罩(决定哪些像素要丢弃)
//Stencil功能在延迟渲染路径中有一定的限制
//Ref值
_Stencil ("Stencil Ref", Float) = 0
//比较值
_StencilComp ("Stencil Comparison", Float) = 8
//处理方式
_StencilOp ("Stencil Operation", Float) = 0
//0-255
_StencilWriteMask ("Stencil Write Mask", Float) = 255
//0-255
_StencilReadMask ("Stencil Read Mask", Float) = 255
//_ColorMask ABGR(1-2-4-8)
//0表示不写入颜色通道到颜色缓冲区
_ColorMask ("Color Mask", Float) = 15
[Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("ZTest", Float) = 4
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Stencil
{
//三个测试阶段顺序:
//顶点着色器->片元着色器->AlphaTest->StencilTest->DepthTest
//该值用来比较
Ref [_Stencil]
//用Ref值与模板缓冲区中的值进行比较(即,模板测试),默认为: always
Comp [_StencilComp]
//当模板测试、深度测试都通过时要做什么处理。默认: keep.
Pass [_StencilOp]
//模板测试未通过时要做什么处理。 默认: keep.
//Fail stencilOperation
//模板测试通过,但深度测试未通过时要做什么处理。默认: keep.
//ZFail stencilOperation
//也可以显示指定是对Cull Front还是对Cull Back进行判断
//CompFront, PassFront, FailFront, ZFailFront
//CompBack, PassBack, FailBack, ZFailBack
/**
比较函数(Comparison Function):
Greater: 只渲染Ref值比缓冲区中值大的像素
GEqual: 只渲染Ref值比缓冲区中值大的或等于的像素
Less: 只渲染Ref值比缓冲区中值小的像素
LEqual: 只渲染Ref值比缓冲区中值小的或等于的像素
Equal: 只渲染Ref值与缓冲区中值相等的像素
NotEqual:只渲染Ref值与缓冲区中值不相等的像素
Always: 让stencil测试总是通过
Never: 让stencil测试总是失败
*/
/**
模板操作(Stencil Operation):
Keep: 保持缓冲区内容
Zero: 写入0到缓冲区
Replace: 写入Ref值到缓冲区
IncrSat: 增加缓冲区的值,如果缓冲区的值已经达到255,则保持255
DecrSat: 减少缓冲区的值,如果缓冲区的值已经为0,则保持0
Invert: 反转所有位
IncrWrap: 增加缓冲区的值,如果缓冲区的值已经达到255,则变为0
DecrWrap: 减少缓冲区的值,如果缓冲区的值已经为0,则变为255
*/
/**
ReadMask: 默认值为255
if(referenceValue&readMask comparisonFunction stencilBufferValue&readMask) {
通过模板测试
}
*/
/**
WriteMask: 默认值为255
缓冲区的值=referenceValue&writeMask
*/
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
//Cull Off
//Lighting Off
//ZWrite Off
//Blend SrcAlpha OneMinusSrcAlpha
ZTest [_ZTest]
//向颜色缓冲区写入颜色通道值(0: 不写入)
//ColorMask RGBA
ColorMask [_ColorMask]
Pass
{
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
}
}
}
效果
Stencil功能在延迟渲染路径中有一定的限制