UGUI源码解析(MaskableGraphic)

MaskableGraphic

UGUI源码解析(MaskableGraphic)

 

MaskableGraphic是一个抽象类,继承了Graphic, IClippable, IMaskable, IMaterialModifier接口,派生了RawImage,Image和Text,如果派生自这个类,那么表示这个组件能被遮罩

 

方法:

继承IMaterialModifier接口

需要实现GetModifiedMaterial方法。这个方法在Graphic的Rebuild方法中调用,用于重建图像时,获取修改后的Material,来实现遮罩效果。

 

继承IClippable接口

MaskableGraphic继承了IClippable,需要实现RecalculateClipping,Cull和SetClipRect方法。RecalculateClipping在MaskUtilities中被调用,Cull和SetClipRect在RectMask2D中被调用。

 

继承IMaskable接口

MaskableGraphic继承了IMaskable,需要实现RecalculateMasking方法。RecalculateMasking在MaskUtilities中被调用,用于图像的遮罩。

 

GetModifiedMaterial方法

  • 如果需要重新计算模板,便从父RectTransform中获取overrideSorting为true的Canvas,赋值给rootCanvas,然后通过MaskUtilities.GetStencilDepth从rootCanvas获取模板深度。
  • 如果模板深度大于0,且没有Mask组件或Mask组件没有激活,就把baseMaterial,stencilID,operation等参数添加到StencilMaterial中,并把之前旧的m_MaskMaterial从StencilMaterial中移除,用新的baseMaterial替换m_MaskMaterial,并返回。

 

Cull剔除方法

如果validRect为false,或者输入的clipRect与所属Canvas的矩形区域不重合,调用UpdateCull方法,设置cull为true

 

UpdateCull(bool cull)方法

把cull赋值给canvasRenderer.cull。如果canvasRenderer.cull发生变化时,发送事件m_OnCullStateChanged,m_OnCullStateChanged.Invoke(cull),再调用OnCullingChanged方法

 

SetClipRect方法

根据输入的validRect,为canvasRenderer开启(EnableRectClipping(clipRect))或关闭矩形裁剪(DisableRectClipping)。

 

OnEnable方法

设置重新计算模板m_ShouldRecalculateStencil为true,更新裁剪的父对象UpdateClipParent,设置Material为Dirty,SetMaterialDirty。如果Mesh组件不为空,调用MaskUtilities.NotifyStencilStateChanged重新计算Mask。

 

OnDisable方法

设置重新计算模板m_ShouldRecalculateStencil为true,设置Material为Dirty,SetMaterialDirty,更新裁剪的父对象UpdateClipParent。从StencilMaterial移除了m_MaskMaterial,并设置m_MaskMaterial为空,如果Mesh组件不为空,调用MaskUtilities.NotifyStencilStateChanged重新计算Mask。

 

OnValidate方法

仅在Editor下调用,设置重新计算模板m_ShouldRecalculateStencil为true,更新裁剪的父对象UpdateClipParent,设置Material为Dirty,SetMaterialDirty。

 

OnTransformParentChanged方法

设置重新计算模板m_ShouldRecalculateStencil为true,更新裁剪的父对象UpdateClipParent,设置Material为Dirty,SetMaterialDirty。

 

重写OnCanvasHierarchyChanged方法

在isActiveAndEnabled为true的条件下,设置重新计算模板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。

 

RecalculateClipping方法

会调用UpdateClipParent方法,更新m_ParentMask(父对象中的RectMask2D组件)。

 

RecalculateMasking方法

设置m_ShouldRecalculateStencil为true,调用SetMaterialDirty。

 

字段:

CullStateChangedEvent字段

当遮罩状态值发生变化时调用

 

public bool maskable

决定这个组件能否被遮罩

 

 

 

MaskUtilities

Mask相关的工具类,提供跟遮罩相关的功能方法,提供的函数均为静态函数

 

Notify2DMaskStateChanged

  • 遍历Mask的所有子对象,找到所有的IClippable接口的组件,调用IClippable的RecalculateClipping方法,重新计算裁剪Clip。
  • 这个方法会在RectMask2D的OnEnable,OnDisable以及编辑器模式的OnValidate方法中调用。

 

NotifyStencilStateChanged方法

  • 遍历Mask的所有子对象,找到所有的IMaskable接口的组件,调用IMaskable的RecalculateMasking方法,重新计算遮罩Mask。
  • 在Mask的OnEnable,OnDisable和编辑器模式下的OnValidate方法中被调用。
  • 在MaskableGraphic的OnEnable,OnDisable方法中,如果Mask组件不为空时,也会被调用。

 

FindRootSortOverrideCanvas(Transform start)方法

查找start的监视面板中根物体的Canvas

 

GetStencilDepth方法

  • 如果rootCanvas就是当前的tranform,返回0;
  • 否则,从当前的Transform往上遍历,找到MaskEnabled为true,并是激活的Mask组件,便depth加1,直至找到rootCanvas,break;

 

bool IsDescendantOrSelf(Transform father, Transform child)

判断child是否为father或者其子物体

 

RectMask2D GetRectMaskForClippable(IClippable clippable)

先获取到所有这个IClippable 组件的父物体上的RectMask2D组件列表,遍历所有的RectMask2D组件,如果当前的这个组件所在的游戏物体为IClippable 组件的物体或者这个组件的isActiveAndEnabled属性为false,那么跳过这个,继续查找下一个,

获取到所有这个IClippable 组件的父物体上的Canvas组件列表,只要当当前这个RectMask2D组件的物体不是其中所有任意一个的Canvas所在物体的子物体或者其本身,或者其Canvas的overrideSorting为true时,返回null,

否则,才返回这个符合条件的RectMask2D组件

 

GetRectMasksForClip(RectMask2D clipper, List<RectMask2D> masks)

根据给定的clipper组件,获取到它父物体上的所有RectMask2D组件列表和Canvas组件列表,遍历RectMask2D组件列表,如果当前遍历到的组件为隐藏状态,那么跳过继续下一个,

遍历Canvas组件列表,只要当前这个RectMask2D组件的物体不是其中所有任意一个的Canvas所在物体的子物体或者其本身,或者其Canvas的overrideSorting为true时,那么这个RectMask2D组件就不被加入到masks返回列表中,否则加入到这个列表中

 

 

上一篇:Unity面试题加强版二之《unity编辑器基础》


下一篇:XMPP客户端开发(2)--发送接收消息