MaskableGraphic
MaskableGraphic是一个抽象类,继承了Graphic, IClippable, IMaskable, IMaterialModifier接口,派生了RawImage,Image和Text。
OnEnable方法
设置重新计算模板m_ShouldRecalculateStencil为true,更新裁剪的父对象UpdateClipParent,设置Material为Dirty,SetMaterialDirty。如果Mesh组件不为空,调用MaskUtilities.NotifyStencilStateChanged重新计算Mask。
OnDisable方法
设置重新计算模板m_ShouldRecalculateStencil为true,更新裁剪的父对象UpdateClipParent,设置Material为Dirty,SetMaterialDirty。从StencilMaterial移除了m_MaskMaterial,并设置m_MaskMaterial为空,如果Mesh组件不为空,调用MaskUtilities.NotifyStencilStateChanged重新计算Mask。
OnTransformParentChanged方法,设置重新计算模板m_ShouldRecalculateStencil为true,更新裁剪的父对象UpdateClipParent,设置Material为Dirty,SetMaterialDirty。
UpdateClipParent方法
- 调用MaskUtilities.GetRectMaskForClippable从父对象中找到RectMask2D组件,RectMask2D组件可以根据RectTransform裁剪子对象,子对象超出父RectTransform范围的部分会被裁剪掉。比如,为Canvas添加了RectMask2D组件,超出Canvas矩形范围的部分就被裁剪掉了。
- 如果m_ParentMask不为空,且新的RectMask2D跟之前的m_ParentMask不同,就把自己从RectMask2D的m_ClipTargets裁剪目标中移除RemoveClippable,并在RemoveClippable方法中,调用clippable.SetClipRect(new Rect(), false),关闭矩形裁剪。
- 否则,如果新的RectMask2D是激活的,就把自己添加到RectMask2D的m_ClipTargets裁剪目标中AddClippable。
- 最后,把新的RectMask2D赋值给m_ParentMask。
SetMaterialDirty方法
设置m_MaterialDirty为true,把自己注册到CanvasUpdateRegistry的图像重建序列中,并调用m_OnDirtyMaterialCallback()回调。
StencilMaterial类
StencilMaterial是一个静态类,负责管理模板材质。维护了一个MatEntry类型的列表:
private static List<MatEntry> m_List = new List<MatEntry>();
外部可以调用Add、Remove和ClearAll方法来对这个List进行操作。
Add方法,会创建一个MatEntry,并将输入的baseMat以及其他参数赋值给MatEntry,并创建了赋值baseMat的customMat,并将stencilID,operation等参数赋值给customMat,实际上赋值customMat的shader参数。
继承IClippable接口
MaskableGraphic继承了IClippable,需要实现RecalculateClipping,Cull和SetClipRect方法。RecalculateClipping在MaskUtilities中被调用,Cull和SetClipRect在RectMask2D中被调用。
RecalculateClipping方法
会调用UpdateClipParent方法,更新m_ParentMask(父对象中的RectMask2D组件)。
MaskUtilities.Notify2DMaskStateChanged
- 遍历Mask的所有子对象,找到所有的IClippable接口的组件,调用IClippable的RecalculateClipping方法,重新计算裁剪Clip。
- 这个方法会在RectMask2D的OnEnable,OnDisable以及编辑器模式的OnValidate方法中调用。
Cull剔除方法
如果validRect为false,或者输入的clipRect与所属Canvas的矩形区域不重合,调用UpdateCull方法,设置cull为true,把cull赋值给canvasRenderer.cull。如果canvasRenderer.cull发生变化时,发送事件m_OnCullStateChanged,m_OnCullStateChanged.Invoke(cull),并调用SetVerticesDirty,设置顶点的Dirty,等待重绘。
SetClipRect方法
根据输入的validRect,为canvasRenderer开启(EnableRectClipping(clipRect))或关闭矩形裁剪(DisableRectClipping)。
继承IMaskable接口
MaskableGraphic继承了IMaskable,需要实现RecalculateMasking方法。RecalculateMasking在MaskUtilities中被调用,用于图像的遮罩。
RecalculateMasking方法
设置m_ShouldRecalculateStencil为true,调用SetMaterialDirty。
MaskUtilities.NotifyStencilStateChanged方法
- 遍历Mask的所有子对象,找到所有的IMaskable接口的组件,调用IMaskable的RecalculateMasking方法,重新计算遮罩Mask。
- 在Mask的OnEnable,OnDisable和编辑器模式下的OnValidate方法中被调用。
- 在MaskableGraphic的OnEnable,OnDisable方法中,如果Mask组件不为空时,也会被调用。
继承IMaterialModifier接口
MaskableGraphic还继承了IMaterialModifier,需要实现GetModifiedMaterial方法。这个方法在Graphic的Rebuild方法中调用,用于重建图像时,获取修改后的Material,来实现遮罩效果。
GetModifiedMaterial方法
- 如果需要重新计算模板,便从父RectTransform中获取overrideSorting为true的Canvas,赋值给rootCanvas,然后通过MaskUtilities.GetStencilDepth从rootCanvas获取模板深度。
- 如果模板深度大于0,且没有Mask组件或Mask组件没有激活,就把baseMaterial,stencilID,operation等参数添加到StencilMaterial中,并把之前旧的m_MaskMaterial从StencilMaterial中移除,用新的baseMaterial替换m_MaskMaterial,并返回。
MaskUtilities.GetStencilDepth方法
- 如果rootCanvas就是当前的tranform,返回0;
- 否则,从当前的Transform往上遍历,找到MaskEnabled为true,并是激活的Mask组件,便depth加1,直至找到rootCanvas,break;