UGUI源码解析——Mask

Posted Hello Bug.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UGUI源码解析——Mask相关的知识,希望对你有一定的参考价值。

一:前言

Mask是遮罩组件,继承自UIBehaviour、ICanvasRaycastFilter、IMaterialModifier
它遮罩的形状由Graphic决定,所以可以利用不同的Graphic实现不同形状的遮罩
它的实现原理是利用了StencilBuffer(模板缓存)

在Mask的GetModifiedMaterial方法中生成一个材质将StencilBuffer值设置为特定值
在MaskableGraphic的GetModifiedMaterial方法中生成一个材质,这个材质在渲染时会取出StencilBuffer的值,判断是否与特定值相等,如果相等才进行渲染


二:模板缓存原理

Mask组件会赋给父级和子级UI一个特殊的材质,这个材质会给Image的每个像素点进行标记并放在一个称为Stencil Buffer的缓存内,首先将父级每个像素点的标记设置为一个特定值,子级UI进行渲染的时候会去检查这个Stencil Buffer内的标记是否与这个特定值相等,如果相等则进行渲染,否则不渲染

模板缓存步骤:如下两张图片,父对象是绿色图片,子对象是红色图片
如果没有添加Mask组件则先将绿色图片每个像素颜色绘制在屏幕上,再将红色每个像素颜色绘制在屏幕上,重叠区域内红色完全覆盖了绿色
如果添加了Mask组件,在渲染的第一帧先将绿色图片每个像素颜色绘制在屏幕上同时将每个像素的stencil buffer值设置为1,接下来绘制红色图片,绘制之前先将绘制区域的stencil buffer值取出来,如果是1则继续绘制如果是0则不进行绘制,从而实现了遮罩效果



​​三:源码解析

——OnEnable

调用NotifyStencilStateChanged方法重新设置所有遮罩材质,最终调用了Graphic类中的SetMaterialDirty方法去更新材质


——OnDisable

从StencilMaterial中移除m_MaskMaterial和m_UnmaskMaterial并置为空,调用NotifyStencilStateChanged方法重新设置所有遮罩材质,最终调用了Graphic类中的SetMaterialDirty方法去更新材质


——GetModifiedMaterial

继承自IMaterialModifier接口,MaskableGraphic也继承了这个接口,通过这个新材质设置修改模板缓冲值
分为两个部分来看
第一部分:处理只有一个Mask的情况
首先查找对象的根画布,接着计算自身到根画布之间Mask的个数,如果只有自身一个Mask则stencilDepth为0,desiredStencilBit则为1,desiredStencilBit表示实际要写入模板缓冲的参考值,
此时通过StencilMaterial.Add获得一个新材质(StencilOp.Replace-2,CompareFunction.Always-8)并将这个材质返回,此时父对象模板缓冲区的参考值为1
接着再获取一个新材质(StencilOp.Zero-1,CompareFunction.Always-8),这个材质实际是用来清除模板缓冲区的,以避免不要影响后续的渲染
第二部分:处理嵌套Mask的情况
与第一部分类似,只不过最后会传入两个参数:readMask(读取掩码)和writeMask(写入掩码)

以上是关于UGUI源码解析——Mask的主要内容,如果未能解决你的问题,请参考以下文章

UGUI源码解析——Mask

UGUI源码解析——Mask

UGUI源码解析——Mask

UGUI源码分析Unity遮罩之Mask详细解读

UGUI源码分析Unity遮罩之Mask详细解读

UGUI源码分析Unity遮罩之Mask详细解读