UGUI的Mask也是通过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
一个材质可以给它设置模板的Ref值
然后可以通过模板比较Comp 过滤掉改像素
可以实现遮罩 以及一些其它的效果
mask遮罩shader
Shader "Unlit/Mask"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Geometry"}
//ColorMask 0
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(0,1,1,1);
}
ENDCG
}
}
}
其它的shader加上下面的代码就能实现遮罩的效果
Tags { "RenderType"="Opaque" "Queue"="Geometry+1"}
Stencil
{
Ref 1
Comp equal
}
这也是为什么 UGUI的源码 都需要加上一堆Stencil 主要是为了都支持遮罩 然后如果是不需要遮罩的话可以新建一个UGUI材质 另外什么背面剔除啊都可以开一下 奉上一个优化的shader
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
Shader "UI/NoMask"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
//不需要模板测试 不需要遮罩
// _StencilComp ("Stencil Comparison", Float) = 8
// _Stencil ("Stencil ID", Float) = 0
// _StencilOp ("Stencil Operation", Float) = 0
// _StencilWriteMask ("Stencil Write Mask", Float) = 255
// _StencilReadMask ("Stencil Read Mask", Float) = 255
// _ColorMask ("Color Mask", Float) = 15
// [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
//不需要模板测试 不需要遮罩
// Stencil
// {
// Ref [_Stencil]
// Comp [_StencilComp]
// Pass [_StencilOp]
// ReadMask [_StencilReadMask]
// WriteMask [_StencilWriteMask]
// }
//背面剔除可以打开
//Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
//ColorMask [_ColorMask]
Pass
{
Name "Default"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile __ UNITY_UI_CLIP_RECT
// #pragma multi_compile __ UNITY_UI_ALPHACLIP
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
// float4 worldPosition : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
sampler2D _MainTex;
fixed4 _Color;
fixed4 _TextureSampleAdd;
// float4 _ClipRect;
float4 _MainTex_ST;
v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
// OUT.worldPosition = v.vertex;
OUT.vertex = UnityObjectToClipPos(v.vertex);
OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
OUT.color = v.color * _Color;
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
// #ifdef UNITY_UI_CLIP_RECT
// color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
// #endif
// #ifdef UNITY_UI_ALPHACLIP
// clip (color.a - 0.001);
// #endif
return color;
}
ENDCG
}
}
}