UGUI源码剖析(CanvasUpdateSystem 画布刷新系统)
Runtime类图分析
CanvasUpdateRegistry
管理着两个队列:
private readonly IndexedSet<ICanvasElement> m_LayoutRebuildQueue = new IndexedSet<ICanvasElement>();private readonly IndexedSet<ICanvasElement> m_GraphicRebuildQueue = new IndexedSet<ICanvasElement>();
m_LayoutRebuildQueue是通过RegisterCanvasElementForLayoutRebuild
和TryRegisterCanvasElementForLayoutRebuild方法添加元素。
m_GraphicRebuildQueue是通过RegisterCanvasElementForGraphicRebuild
和TryRegisterCanvasElementForGraphicRebuild方法添加元素。
二者通过UnRegisterCanvasElementForRebuild移除注册元素。
在构造函数中向Canvas的willRenderCanvases 事件注册了更新函数(PerformUpdate),以用来响应重建。
Canvas.willRenderCanvases += PerformUpdate;
Canvas在渲染前会调用willRenderCanvases,即执行PerformUpdate ,方法如下:
private void PerformUpdate(){UISystemProfilerApi.BeginSample(UISystemProfilerApi.SampleType.Layout);CleanInvalidItems();m_PerformingLayoutUpdate = true;m_LayoutRebuildQueue.Sort(s_SortLayoutFunction);for (int i = 0; i <= (int)CanvasUpdate.PostLayout; i++){for (int j = 0; j < m_LayoutRebuildQueue.Count; j++){var rebuild = instance.m_LayoutRebuildQueue[j];try{if (ObjectValidForUpdate(rebuild))rebuild.Rebuild((CanvasUpdate)i);}catch (Exception e){Debug.LogException(e, rebuild.transform);}}}for (int i = 0; i < m_LayoutRebuildQueue.Count; ++i)m_LayoutRebuildQueue[i].LayoutComplete();instance.m_LayoutRebuildQueue.Clear();m_PerformingLayoutUpdate = false;// now layout is complete do culling...ClipperRegistry.instance.Cull();m_PerformingGraphicUpdate = true;for (var i = (int)CanvasUpdate.PreRender; i < (int)CanvasUpdate.MaxUpdateValue; i++){for (var k = 0; k < instance.m_GraphicRebuildQueue.Count; k++){try{var element = instance.m_GraphicRebuildQueue[k];if (ObjectValidForUpdate(element))element.Rebuild((CanvasUpdate)i);}catch (Exception e){Debug.LogException(e, instance.m_GraphicRebuildQueue[k].transform);}}}for (int i = 0; i < m_GraphicRebuildQueue.Count; ++i)m_GraphicRebuildQueue[i].GraphicUpdateComplete();instance.m_GraphicRebuildQueue.Clear();m_PerformingGraphicUpdate = false;UISystemProfilerApi.EndSample(UISystemProfilerApi.SampleType.Layout);}
流程如下:
首先调用 CleanInvalidItems删除不可用(为null或者IsDestroyed)的元素。
布局更新开始设置标识位m_PerformingLayoutUpdate为true。
对m_LayoutRebuildQueue依据父对象的数量进行排序:m_LayoutRebuildQueue.Sort(s_SortLayoutFunction)。
分别以PreLayout,Layout,PostLayout的参数顺序调用每一个元素的Rebuild方法。
其中在Rebuild之前需要判断这个元素是否有效(不为空且为Unity的Object类型)。
调用所有元素的LayoutComplete方法。
清除布局重建序列中的所有元素m_LayoutRebuildQueue.Clear()。
布局更新结束设置标志位m_PerformingLayoutUpdate = false。
完成布局后,调用组件的修剪方法ClipperRegistry.instance.Cull()。
图形更新开始设置标识位m_PerformingGraphicUpdate为true。
以PreRender,LatePreRender,MaxUpdateValue的参数顺序调用每一个元素的Rebulid方法。
其中在Rebuild之前需要判断这个元素是否有效(不为空且为Unity的Object类型)。
调用所有元素的GraphicUpdateComplete方法。
清除图形重建序列中的所有元素m_GraphicRebuildQueue.Clear()。
图形更新结束设置标志位m_PerformingGraphicUpdate = false。
CanvasUpdate
定义重建时的优先级顺序:
public enum CanvasUpdate{/// <summary>/// Called before layout./// </summary>Prelayout = 0,/// <summary>/// Called for layout./// </summary>Layout = 1,/// <summary>/// Called after layout./// </summary>PostLayout = 2,/// <summary>/// Called before rendering./// </summary>PreRender = 3,/// <summary>/// Called late, before render./// </summary>LatePreRender = 4,/// <summary>/// Max enum value. Always last./// </summary>MaxUpdateValue = 5}
ICanvasElement
需要在Canvas绘制更新调用前重建的元素接口。
/// <summary>/// This is an element that can live on a Canvas./// </summary>public interface ICanvasElement{/// <summary>/// Rebuild the element for the given stage./// </summary>/// <param name="executing">The current CanvasUpdate stage being rebuild.</param>void Rebuild(CanvasUpdate executing);/// <summary>/// Get the transform associated with the ICanvasElement./// </summary>Transform transform { get; }/// <summary>/// Callback sent when this ICanvasElement has completed layout./// </summary>void LayoutComplete();/// <summary>/// Callback sent when this ICanvasElement has completed Graphic rebuild./// </summary>void GraphicUpdateComplete();/// <summary>/// Used if the native representation has been destroyed./// </summary>/// <returns>Return true if the element is considered destroyed.</returns>bool IsDestroyed();}
Rebuild实际的重建方法。
LayoutComplete在布局重建完成后回调。
GraphicUpdateComplete在图形重建完成后回调。
IsDestroyed判断当前元素是否已经不需要参与重建了。
ClipperRegistry
内部维护着一个IClipper接口的列表
readonly IndexedSet<IClipper> m_Clippers = new IndexedSet<IClipper>();
提供Register方法加入一个IClipper到此列表中,
Unregister移除m_Clippers 列表中的指定IClipper,
在Cull方法中遍历此列表,分别调用它们的PerformClipping方法。
脏标记
标记延迟执行,优化重新渲染的手段。
详情请见:游戏设计模式:https://gpp.tkchu.me/dirty-flag.html
例如在Graphic 中存在三种脏标分别代表三种等待重建。
尺寸改变时(RectTransformDimensions):LayoutRebuild 布局重建;
尺寸、颜色改变时:Vertices to GraphicRebuild 图像重建;
材质改变时:Material to GraphicRebuild 图像重建。
层级改变(OnTransformParentChanged)、应用动画属性(OnDidApplyAnimationProperties) :All to Rebuild 重建所有,包括布局重建和图像重建。
UGUI源码剖析(CanvasUpdateSystem 画布刷新系统)相关推荐
- [UGUI源码剖析]—Rebuild 网格重建(画布刷新)系统
几个比较重要的类和接口: Canvas.CanvasUpdateRegistry.ClipperRegistry.LayoutRebuilder.LayoutGroup.Graphics.Maskab ...
- CanvasUpdateSystem 画布刷新系统
制作UI过程,添加Canvas组件将会打断和之前元素DrawCall的合并,每个Canvas都会开始一个全新的DrawCall,当Canvas需要重绘的时候会调用SendWillRenderCanva ...
- UGUI源码解析(LayoutSystem布局系统)
Runtime类图 ILayoutElement 布局元素接口,是布局的接收方.如果某个类实现了这个接口,那么就会在应用布局时自动完成对它的位置信息及大小的布局计算. ILayoutControlle ...
- UGUI源码剖析(Image)
Runtime类图分析 Image继承了MaskableGraphic, ISerializationCallbackReceiver, ILayoutElement, ICanvasRaycastF ...
- UGUI源码分析:GridLayoutGroup网格布局组件与ContentSizeFitter尺寸调节组件
系列 UGUI源码分析系列总览 相关前置: UGUI CanvasUpdateSystem源码分析 UGUI源码分析:LayoutSystem布局系统 UGUI源码分析:LayoutGroup中的纵横 ...
- UGUI源码分析:LayoutGroup中的纵横布局组件(HorizontalOrVerticalLayoutGroup)
系列 UGUI源码分析系列总览 相关前置: UGUI CanvasUpdateSystem源码分析 UGUI源码分析:LayoutSystem布局系统 文章目录 系列 UML图一览 LayoutGro ...
- Python猫荐书系统之四:《Python源码剖析》
大家好,新一期的荐书栏目如期跟大家见面了. 先来看看今天的主角是谁:<Python源码剖析--深度探索动态语言核心技术>,2008年出版,作者 @陈儒 ,评分8.7分. 是的,你没看错,出 ...
- ugui源码_UGUI 源码笔记(一)文件结构和部分组件使用
这是我阅读 UGUI 源码记录的相关笔记,共三部分.文件结构和部分组件使用.输入事件.核心部分 ZeroyiQ:UGUI 源码笔记(一)文件结构和部分组件使用 ZeroyiQ:UGUI 源码笔记(二) ...
- Chrome源码剖析、上--多线程模型、进程通信、进程模型
Chrome源码剖析.上 原著:duguguiyu. 整理:July. 时间:二零一一年四月二日. 出处:http://blog.csdn.net/v_JULY_v. 说明:此Chrome源码剖析很大 ...
- Chrome源码剖析 上--多线程模型 进程通信 进程模型
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! Chro ...
最新文章
- android开发获取应用本身耗电量_别找了,Android常用自动化工具全在这儿了!
- 导致用户体验差造成网站跳出率过高的原因有哪些?
- struts2.0和struts1.x的区别
- CSDN移动博文集锦之Android核心分析 (Z)
- Android之用命令uninstall卸载apk和用 -i 过滤日志忽略大小写
- 【51单片机快速入门指南】9:省电模式(低功耗)
- host ntrip 千寻rtk_最新测量干货:南方银河1和银河1Plus RTK设备连接千寻cors账号的设置方法...
- mybatis $和#源代码分析
- 数字音频特效的软件实现项目
- 设计海报|字符海报怎么玩?
- 北大AI第八讲 李航 自然语言处理的现实与挑战
- 张量(tensor)的理解
- 支持IE8的文件上传
- python3 下 tkinter 的网页监控小程序
- Android 动画丢帧问题
- Windows Mobile 6.x 下改Tahoma字体+微软雅黑说明
- USB接口、手机接口
- 下载kaggle比赛的数据集
- 淘宝网店商品哪个时间段是最佳上架时间?
- Kubernetes Scheduler源码分析--启动过程与多队列缓存(续)
热门文章
- 盛语小智教育机器人是骗人的_盛语小智机器人骗局揭露【是不是真的有效】多久可以见...
- cv::Mat转换为QImage错误
- sphinx linux,sphinx使用及其简单配置方法
- 关于用EAC抓轨的测试 (转载)
- vue从零搭建一个前中后台权限管理模板
- 百钱买百鸡问题的解法与思路
- WORD2003无法打开WORD2000文档解决方法
- RuntimeError: Cannot re-initialize CUDA in forked subprocess. To use CUDA with multiprocessing, you
- 自己动手写ORB特征
- 网络狂飙(netspeeder) v3.28 游戏版 怎么用