Mask
是UGUI组件,限制子元素的可视区域
原理:Alpha测试 + 遮罩裁剪(Stencil/Alpha Clip)
用途:滚动列表、引导层、Popup窗口裁剪、半透明遮罩背景
种类:
Mask
(软裁剪,基于Alpha Cutoff)RectMask2D
(矩形硬裁剪,基于Viewport Rect)总结:Mask = 限制UI显示范围的剪刀
类型 | 生活比喻 |
---|---|
Mask | ️ 窗户贴雾膜,透光但不透视 |
RectMask2D | 按正方形切割的窗户 |
引导层圆形/不规则遮罩 | 黑夜中打手电筒,只照亮一个区域 |
总结:Mask = 窗口,引导层 = 聚光手电筒
需求 | 说明 |
---|---|
圆形遮罩 | 高亮头像、按钮、道具位置 |
多区域遮罩(多个洞) | 引导多个地方,比如同时提示两三个技能按钮 |
不规则多边形遮罩 | 圆角矩形、任意形状,匹配UI风格 |
动态遮罩移动/缩放动画 | 引导过程中,遮罩位置、大小、形状实时变化 |
透明黑幕+高亮区域 | 90%遮住,10%突出重要区域,突出视觉引导 |
Mask类型 | 优势 | 局限 |
---|---|---|
Mask |
支持不规则图形 | 性能差,产生Overdraw |
RectMask2D |
性能好,硬裁剪,零Overdraw | 只能矩形遮罩 |
Custom Shader Mask |
支持任意形状,优化灵活 | 需要手写Shader |
✅ 推荐方案:自定义透明遮罩Shader
特性 | 实现方式 | 性能 |
---|---|---|
黑幕半透明背景 | 全屏Canvas Image,颜色半透明黑 | 极小开销 |
不规则透明洞(圆形/椭圆/矩形等) | Shader绘制透明区域,透明区域不渲染 | 优化Overdraw |
动态控制洞的位置、大小、形状 | 用MaterialPropertyBlock 传参实时调洞的位置、半径 |
动态开销小 |
Shader "UI/GuideMask"
{
Properties
{
_MaskCenter ("Center", Vector) = (0.5, 0.5, 0, 0)
_MaskRadius ("Radius", Float) = 0.2
_MaskSoftness ("Softness", Float) = 0.01
_Color ("Color", Color) = (0, 0, 0, 0.7)
}
SubShader
{
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _Color;
float2 _MaskCenter;
float _MaskRadius;
float _MaskSoftness;
struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; };
struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; };
v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; }
fixed4 frag (v2f i) : SV_Target
{
float2 uv = i.uv;
float dist = distance(uv, _MaskCenter);
float alpha = smoothstep(_MaskRadius, _MaskRadius - _MaskSoftness, dist);
return fixed4(_Color.rgb, _Color.a * alpha);
}
ENDCG
}
}
}
特点:
错误代码 | 问题描述 | 性能影响 |
---|---|---|
多层嵌套 Mask /Mask2D |
每层一个遮罩,Overdraw叠加 | GPU Fillrate爆炸 |
大量透明遮罩图片 | 遮罩用PNG透明图片叠加,像素多次覆盖 | 多次Blend,掉帧 |
动态SetActive切换引导层遮罩 | 每次引导都激活/禁用节点,引发Canvas Rebuild | Rebuild频发 |
不用PropertyBlock更新Shader参数 | 每次动态变化新建一个Material实例 | 打断Batch,GC Alloc |
引导层遮罩和ScrollView Mask叠加使用 | 滚动列表内有Mask,再加引导Mask,遮罩套遮罩 | ⚠️ 卡爆GPU,掉帧明显 |
技巧 | 说明 |
---|---|
✅ 自定义Shader实现遮罩 | 减少Overdraw,提升性能 |
✅ 动态传参用MaterialPropertyBlock | 改Shader参数不新建Material,Batch不打断,GC 0分配 |
✅ 全局单例管理引导层遮罩 | 只存在一个遮罩节点,动态更新参数控制不同引导场景 |
✅ 只Update真正变化时刷新 | 位置、尺寸有变化才刷新,避免每帧无脑刷新 |
✅ 避免与ScrollView嵌套Mask | 引导遮罩单独Canvas,渲染在最顶层,减少Mask套娃 |
✅ 遮罩区可点击传递 | 遮罩洞外可阻挡,洞内可穿透,提升引导体验(设置blocksRaycasts = false 的区域) |
Mask就像:舞台布景上的聚光灯
- 舞台太暗,打灯引导观众看哪里;
- 灯光太多,观众眼花;
- 聚光精准,舞台清晰,焦点突出。
总结:
少裁剪,轻遮盖,洞精准,光通透!
能剪不盖,能透不涂,能准不泛,能省必省!