IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> UIGU源码分析13:MaskGraphic -> 正文阅读

[移动开发]UIGU源码分析13:MaskGraphic

源码13:MaskGraphic

public abstract class MaskableGraphic : Graphic, IClippable, IMaskable, IMaterialModifier
{
	...    
}

继承MaskGraphic 的有Image Text RawImage 基本可以使用显示的UI组件都继承了MaskGraphic

MaskableGraphic除了继承Graphic外 还继承了三个接口


IClippable

IClippable 被裁剪者 通常和裁剪者IClipper配套使用 看IClippable接口的源码注释

   public interface IClippable
    {
        /// <summary>
        ///可被裁剪的对象
        /// GameObject of the IClippable object
        /// </summary>
        GameObject gameObject { get; }

        /// <summary>
        ///可被裁剪的父对象状态发生变化的时候使用
        /// Will be called when the state of a parent IClippable changed.
        /// </summary>
        void RecalculateClipping();

        /// <summary>
        /// 可被裁剪的对象RectTransform
        /// The RectTransform of the clippable.
        /// </summary>
        RectTransform rectTransform { get; }

        /// <summary>
        /// 在给给定的裁剪范围中进行裁剪计算
        /// Clip and cull the IClippable given a specific clipping rect
        /// </summary>
        /// <param name="clipRect">The Rectangle in which to clip against.</param>
        /// <param name="validRect">Is the Rect valid. If not then the rect has 0 size.</param>
        void Cull(Rect clipRect, bool validRect);

        /// <summary>
        /// 设置可被裁剪的对象的裁剪范围
        /// Set the clip rect for the IClippable.
        /// </summary>
        /// <param name="value">The Rectangle for the clipping</param>
        /// <param name="validRect">Is the rect valid.</param>
        void SetClipRect(Rect value, bool validRect);

        /// <summary>
        /// Set the clip softness for the IClippable.
        ///
        /// The softness is a linear alpha falloff over clipSoftness pixels.
        /// </summary>
        /// <param name="clipSoftness">The number of pixels to apply the softness to </param>
        void SetClipSoftness(Vector2 clipSoftness);
        

IClipper 目前只有RectMask2D组件继承实现

也就是说通常裁剪的时候 是裁减者RectMask2D设置一个裁减矩形给被裁减者MaskableGraphic


这里先分析下MaskGraphic 是如何设置应用裁剪相关内容 如何裁剪在RectMask2D在分析

SetClipRect MaskableGraphic将裁减矩形发送到canvasRenderer渲染器中

public virtual void SetClipRect(Rect clipRect, bool validRect)
{
    if (validRect)
        canvasRenderer.EnableRectClipping(clipRect);
    else
        canvasRenderer.DisableRectClipping();
}

RecalculateClipping 重新计算获取父对象中的RectMask2D组件 (m_ParentMask)

/// <summary>
    /// See IClippable.RecalculateClipping
    /// </summary>
    public virtual void RecalculateClipping()
    {
        UpdateClipParent();
    }
    
    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);
        }

        // don't re-add it if the newparent is inactive
        if (newParent != null && newParent.IsActive())
        newParent.AddClippable(this);

        m_ParentMask = newParent;
	}

Cull 剔除方法 如果validRect为false,或者输入的clipRect与所属Canvas的矩形区域不重合,调用UpdateCull方法,设置cull为true,把cull赋值给canvasRenderer.cull。如果canvasRenderer.cull发生变化时,发送事件m_OnCullStateChanged,m_OnCullStateChanged.Invoke(cull),并调用SetVerticesDirty,设置顶点的Dirty,等待重绘。

    public virtual void Cull(Rect clipRect, bool validRect)
    {
        var cull = !validRect || !clipRect.Overlaps(rootCanvasRect, true);
        UpdateCull(cull);
    }

    private void UpdateCull(bool cull)
    {
        if (canvasRenderer.cull != cull)
        {
            canvasRenderer.cull = cull;
            UISystemProfilerApi.AddMarker("MaskableGraphic.cullingChanged", this);
            m_OnCullStateChanged.Invoke(cull);
            OnCullingChanged();
        }
    }

IMaskable

IMaskable 被遮罩者 同IClippable类似也有个遮罩者 Mask组件(必须有一个MaskGraphic组件)

这里只分析作为IMaskable Mask后面再分析

IMaskable 只有一个实现方法RecalculateMasking

        public virtual void RecalculateMasking()
        {
            // Remove the material reference as either the graphic of the mask has been enable/ disabled.
            // This will cause the material to be repopulated from the original if need be. (case 994413)
            StencilMaterial.Remove(m_MaskMaterial);
            m_MaskMaterial = null;
            m_ShouldRecalculateStencil = true;
            SetMaterialDirty();
        }

设置m_ShouldRecalculateStencil为true,调用SetMaterialDirty 也就是启用Mask的时候,会让所有IMaskable子物体的StencilValue发生变化,并标记重建。

IMaterialModifier

MaskGraphic 也实现了IMaterialModifier接口,主要就是配合实现遮罩效果,因为遮罩效果正是通过材质实现的

        public virtual Material GetModifiedMaterial(Material baseMaterial)
        {
            var toUse = baseMaterial;

            if (m_ShouldRecalculateStencil)
            {
                if (maskable)
                {
                    var rootCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform);
                    m_StencilValue = MaskUtilities.GetStencilDepth(transform, rootCanvas);
                }
                else
                    m_StencilValue = 0;

                m_ShouldRecalculateStencil = false;
            }

            // if we have a enabled Mask component then it will
            // generate the mask material. This is an optimization
            // it adds some coupling between components though :(
            if (m_StencilValue > 0 && !isMaskingGraphic)
            {
                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;
        }

GetModifiedMaterial方法是再被标记重建后 在Rebulid中调用

如果需要重新计算模板,便从父RectTransform中获取overrideSorting为true的Canvas,赋值给rootCanvas,然后通过MaskUtilities.GetStencilDepth从rootCanvas获取模板深度。

如果模板深度大于0,且没有Mask组件或Mask组件没有激活,就把baseMaterial,stencilID,operation等参数添加到StencilMaterial中,并把之前旧的m_MaskMaterial从StencilMaterial中移除,用新的baseMaterial替换m_MaskMaterial,并返回


其他补充

  protected override void OnEnable()
    {
        base.OnEnable();
        m_ShouldRecalculateStencil = true;
        UpdateClipParent();
        SetMaterialDirty();

        if (isMaskingGraphic)
        {
            MaskUtilities.NotifyStencilStateChanged(this);
        }
    }

组件刚激活时 设置重新计算模板标记为True,更新被裁剪得父对象 设置Material为Dirty,SetMaterialDirty。从StencilMaterial移除了m_MaskMaterial,并设置m_MaskMaterial为空,如果Makk组件不为空,调用MaskUtilities.NotifyStencilStateChanged重新计算Mask。

   protected override void OnDisable()
    {
        base.OnDisable();
        m_ShouldRecalculateStencil = true;
        SetMaterialDirty();
        UpdateClipParent();
        StencilMaterial.Remove(m_MaskMaterial);
        m_MaskMaterial = null;

        if (isMaskingGraphic)
        {
            MaskUtilities.NotifyStencilStateChanged(this);
        }
    }

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


StencilMaterial

    /// <summary>
    /// Dynamic material class makes it possible to create custom materials on the fly on a per-Graphic basis,
    /// and still have them get cleaned up correctly.
    /// </summary>
    public static class StencilMaterial
    {
       	private static List<MatEntry> m_List = new List<MatEntry>();
    	...
    }

StencilMaterial是一个静态类,负责管理模板材质。维护了一个MatEntry类型的列表:

private static List m_List = new List();

外部可以调用Add、Remove和ClearAll方法来对这个List进行操作。

Add方法,会创建一个MatEntry,并将输入的baseMat以及其他参数赋值给MatEntry,并创建了赋值baseMat的customMat,并将stencilID,operation等参数赋值给customMat,实际上赋值customMat的shader参数。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-03-17 22:19:09  更:2022-03-17 22:20:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 18:39:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码