DomDomm 发表于 2022-1-4 10:14

UGUI源码解析(二十七)总结篇

1、渲染细节

当使用Unity UI 制作用户界面时,记住,所有的被Canvas绘制的图形都是被放在透明渲染队列。这意味着,Unity UI产生的图形都会使用透明混合(alpha blending)从后向前渲染。有一个重要的性能点要注意:图形上的每一个像素都会被采样,即使它被另一个不透明的图形完全覆盖。在移动设备上,大量的的过度绘制(overdraw)可以快速超出GPU填充率的上限。

2、合批过程(Canvases)

合批过程是指Canvas合并UI元素的网格,并且生成发送给Unity渲染管线的命令。Canvas使用的网格都是从绑定在Canvas上的CanvasRenderer获得,但是不包含子Canvas的网格。UGUI的层叠顺序是按照Hierarchy中的顺序从上往下进行的,也就是越靠上的组件,就会被绘制在越底部。所有相邻层的可Batch的UI元素(具有相同材质和纹理),就会在一个DrawCall中完成。

UGUI合批策略

[*]父节点Z != 0,则下面的元素都无法合批了。子UI元素Z值不为0时,会被视为3D UI,不参与合批。
[*]设置Canvas.overrideSorting为true
[*]设置Canvas.sortingOrder为窗口在Hierarchy下的排列顺序
[*]设置Canvas.sortingLayerID为0
[*]设置Canvas.sortingLayerName为SortingLayer.IDToName(0)
[*]根据功能适用性,合理使用Atlas图集。
[*]慎用Mask组件

3、重绘过程(Graphics)

重绘过程是指Unity UI 的 图形组件的排版和网格被重新计算。这在 CanvasUpdateRegistry类中执行。当Canvas组件触发WillRenderCanvases事件时都会调用这个方法。这个事件每一帧都会执行一次。在CanvasUpdateRegistry内部,需要关注的方法是PerformUpdate。

PerformUpdate执行三个步骤:

[*]标记为dirty的排版组件通过ICanvasElement.Rebuild方法重建布局,排版重建分成三个过程(PreLayout, Layout 和 PostLayout)。
[*]任何注册过的裁剪组件(如mask),需要去裁剪所有可剔除的组件。这是通过ClippingRegistry.Cull实现的。
[*]被标记为dirty的图形组件,通过ICanvasElement.Rebuild方法重建它们的图形元素,图形重建包含两个过程(PreRender 和 LatePreRender)。

布局重建:
自动布局系统按以下顺序评估和执行布局:

[*]通过调用ILayoutElement组件上的CalculateLayoutInputHorizontal来计算布局元素的最小值,首选值和灵活宽度。这是以自下而上的顺序进行的,孩子在父母面前计算,这样父母可以在他们自己的计算中考虑到孩子的信息。
[*]通过调用ILayoutController组件上的SetLayoutHorizontal,根据父对象的可用宽度,来计算和设置子对象布局元素的宽度。这是按照自上而下的顺序执行的,因为孩子的父母分配的子宽度需要根据父母的可用宽度进行分配。在这一步之后,布局元素的Rect变换具有新的宽度。
[*]通过调用ILayoutElement组件的CalculateLayoutInputVertical来计算布局元素的最小值,首选值和灵活高度。这是以自下而上的顺序进行的,孩子在父母面前计算,这样父母可以在他们自己的计算中考虑到孩子的信息。
[*]通过调用ILayoutController组件的SetLayoutVertical,根据父对象的可用高度,来计算和设置子对象布局元素的高度。这是按照自上而下的顺序执行的,因为子女的高度需要根据父母的可用高度计算,子女是在父母之后计算的。在这一步之后,布局元素的Rect变换有了新的高度。

何时触发布局重建:

[*]更改LayoutElement布局元素的属性时,比如修改Min Width,Preferred Width等属性。
[*]在OnEnable和OnDisable中
[*]OnRectTransformDimensionsChange(RectTransform大小发生改变时)
[*]OnValidate (只能编辑器中,非运行状态)
[*]OnDidApplyAnimationProperties(应用动画属性时)

图形重建:
Rebuild方法
在Canvas渲染前被调用,在这个方法里会调用UpdateGeometry和UpdateMaterial更新顶点和材质。
UpdateGeometry方法
调用DoMeshGeneration方法,如果rectTransform不为空,且宽高都大于0,调用OnPopulateMesh,实际上只是把顶点和三角形信息保存到了s_VertexHelper里。然后获取所有的IMeshModifier类型的组件,(IMeshModifier是一个接口,需要依据顶点信息的组件继承自它,例如Shadow就间接继承自它),调用IMeshModifier的ModifyMesh方法,修改Mesh信息。最后将s_VertexHelper里修改后的信息设置给canvasRenderer。概括的说就是,把顶点和三角形信息进行修改,并设置给CanvasRenderer。
UpdateMaterial方法
更新canvasRenderer的材质和纹理。在给canvasRenderer设置材质时,会遍历所有IMaterialModifier类型的组件,调用IMaterialModifier.GetModifiedMaterial方法,用于重建图像时,获取修改后的Material,来实现遮罩效果。

推荐大神写的一篇自定义绘制的博文:
页: [1]
查看完整版本: UGUI源码解析(二十七)总结篇