/// <summary> /// Perform material modification in this function. /// 获取修改后的材质 /// 默认的实现为替换材质,根据是否父物体为 Mask 组件,修改 Stencil 值,通过shader 的模板功能实现遮罩 /// </summary> public virtual Material GetModifiedMaterial(Material baseMaterial) { var toUse = baseMaterial; if (m_ShouldRecalculateStencil) { var rootCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform); m_StencilValue = maskable ? MaskUtilities.GetStencilDepth(transform, rootCanvas) : 0; m_ShouldRecalculateStencil = false; } // if we have a enabled Mask component then it will // generate the mask material. This is an optimisation // it adds some coupling between components though :( Mask maskComponent = GetComponent <Mask>(); if (m_StencilValue > 0 && (maskComponent == null || !maskComponent.IsActive())) { var maskMat = StencilMaterial.Add(toUse, (1 << m_StencilValue) - 1, StencilOp.Keep, CompareFunction.Equal, ColorWriteMask.All, (1 << m_StencilValue) - 1, 0); StencilMaterial.Remove(m_MaskMaterial); m_MaskMaterial = maskMat; toUse = m_MaskMaterial; } return(toUse); }
protected override void OnEnable() { base.OnEnable(); m_ShouldRecalculateClipRects = true; ClipperRegistry.Register(this); MaskUtilities.Notify2DMaskStateChanged(this); }
public virtual void PerformClipping() { // if the parents are changed // or something similar we // do a recalculate here if (m_ShouldRecalculateClipRects) { MaskUtilities.GetRectMasksForClip(this, m_Clippers); m_ShouldRecalculateClipRects = false; } // get the compound rects from // the clippers that are valid bool validRect = true; Rect clipRect = Clipping.FindCullAndClipWorldRect(m_Clippers, out validRect); if (clipRect != m_LastClipRectCanvasSpace) { for (int i = 0; i < m_ClipTargets.Count; ++i) { m_ClipTargets[i].SetClipRect(clipRect, validRect); } m_LastClipRectCanvasSpace = clipRect; m_LastClipRectValid = validRect; } for (int i = 0; i < m_ClipTargets.Count; ++i) { m_ClipTargets[i].Cull(m_LastClipRectCanvasSpace, m_LastClipRectValid); } }
protected override void OnEnable() { base.OnEnable(); if (graphic != null) { graphic.canvasRenderer.hasPopInstruction = true; graphic.SetMaterialDirty(); } MaskUtilities.NotifyStencilStateChanged(this); }
protected override void OnValidate() { base.OnValidate(); m_ShouldRecalculateClipRects = true; if (!IsActive()) { return; } MaskUtilities.Notify2DMaskStateChanged(this); }
protected override void OnDisable() { // we call base OnDisable first here // as we need to have the IsActive return the // correct value when we notify the children // that the mask state has changed. base.OnDisable(); m_ClipTargets.Clear(); m_Clippers.Clear(); ClipperRegistry.Unregister(this); MaskUtilities.Notify2DMaskStateChanged(this); }
/// Stencil calculation time! public virtual Material GetModifiedMaterial(Material baseMaterial) { if (graphic == null) { return(baseMaterial); } var rootSortCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform); var stencilDepth = MaskUtilities.GetStencilDepth(transform, rootSortCanvas); if (stencilDepth >= 8) { Debug.LogError("Attempting to use a stencil mask with depth > 8", gameObject); return(baseMaterial); } int desiredStencilBit = 1 << stencilDepth; // if we are at the first level... // we want to destroy what is there if (desiredStencilBit == 1) { var maskMaterial = StencilMaterial.Add(baseMaterial, 1, StencilOp.Replace, CompareFunction.Always, m_ShowMaskGraphic ? ColorWriteMask.All : 0); StencilMaterial.Remove(m_MaskMaterial); m_MaskMaterial = maskMaterial; var unmaskMaterial = StencilMaterial.Add(baseMaterial, 1, StencilOp.Zero, CompareFunction.Always, 0); StencilMaterial.Remove(m_UnmaskMaterial); m_UnmaskMaterial = unmaskMaterial; graphic.canvasRenderer.popMaterialCount = 1; graphic.canvasRenderer.SetPopMaterial(m_UnmaskMaterial, 0); return(m_MaskMaterial); } //otherwise we need to be a bit smarter and set some read / write masks var maskMaterial2 = StencilMaterial.Add(baseMaterial, desiredStencilBit | (desiredStencilBit - 1), StencilOp.Replace, CompareFunction.Equal, m_ShowMaskGraphic ? ColorWriteMask.All : 0, desiredStencilBit - 1, desiredStencilBit | (desiredStencilBit - 1)); StencilMaterial.Remove(m_MaskMaterial); m_MaskMaterial = maskMaterial2; graphic.canvasRenderer.hasPopInstruction = true; var unmaskMaterial2 = StencilMaterial.Add(baseMaterial, desiredStencilBit - 1, StencilOp.Replace, CompareFunction.Equal, 0, desiredStencilBit - 1, desiredStencilBit | (desiredStencilBit - 1)); StencilMaterial.Remove(m_UnmaskMaterial); m_UnmaskMaterial = unmaskMaterial2; graphic.canvasRenderer.popMaterialCount = 1; graphic.canvasRenderer.SetPopMaterial(m_UnmaskMaterial, 0); return(m_MaskMaterial); }
protected override void OnDisable() { base.OnDisable(); m_ShouldRecalculateStencil = true; SetMaterialDirty(); UpdateClipParent(); StencilMaterial.Remove(m_MaskMaterial); m_MaskMaterial = null; if (GetComponent <Mask>() != null) { MaskUtilities.NotifyStencilStateChanged(this); } }
protected override void OnValidate() { base.OnValidate(); if (!IsActive()) { return; } if (graphic != null) { graphic.SetMaterialDirty(); } MaskUtilities.NotifyStencilStateChanged(this); }
private void UpdateClipParent() { var newParent = (maskable && IsActive()) ? MaskUtilities.GetRectMaskForClippable(this) : null; // if the new parent is different OR is now inactive // 移出旧遮罩父物体的控制 if (m_ParentMask != null && (newParent != m_ParentMask || !newParent.IsActive())) { m_ParentMask.RemoveClippable(this); UpdateCull(false); } if (newParent != null && newParent.IsActive()) { newParent.AddClippable(this); } m_ParentMask = newParent; }
protected override void OnDisable() { // we call base OnDisable first here // as we need to have the IsActive return the // correct value when we notify the children // that the mask state has changed. base.OnDisable(); if (graphic != null) { graphic.SetMaterialDirty(); graphic.canvasRenderer.hasPopInstruction = false; graphic.canvasRenderer.popMaterialCount = 0; } StencilMaterial.Remove(m_MaskMaterial); m_MaskMaterial = null; StencilMaterial.Remove(m_UnmaskMaterial); m_UnmaskMaterial = null; MaskUtilities.NotifyStencilStateChanged(this); }