Unity3d:UGUI源码,Rebuild优化

2023-08-24 15:32:13 浏览数 (2)

Image怎么绘制的

Unity中渲染的物体都是由网格(Mesh)构成的,而网格的绘制单元是图元(点、线、三角面) 绘制信息都存储在Vertexhelper类中,除了顶点外,还包括法线、UV、颜色、切线。

Rebuild概念

Canvas负责将子节点的UI元素的网格合并,并生成相应的渲染指令再发送到Unity的图形管道的过程。所以Canvas就是渲染UI的组件,当UI发生变化就要执行一次Batch,它是影响性能更大的元凶。注意Canvas的Batch只会影响其子节点,但不会影响其子Canvas。

Rebuild的程序流程

  1. Image,Text都是继承Graphic,Graphic有ICanvasElement接口,实现rebuild函数
代码语言:javascript复制
   public interface ICanvasElement
   {
       /// <summary>
       /// Rebuild the element for the given stage.
       /// </summary>
       /// <param name="executing">The current CanvasUpdate stage being rebuild.</param>
       ///  // 根据CanvasUpdate的不同阶段重建元素
       void Rebuild(CanvasUpdate executing);
  1. CanvasUpdateRegistry监听Canvas的willRenderCanvases事件,这个事件会在渲染前进行每帧调用
代码语言:javascript复制
   public class CanvasUpdateRegistry
   {
         //布局重建队列,当UI元素的布局需要更新时将其加入队列
       private readonly IndexedSet<ICanvasElement> m_LayoutRebuildQueue = new IndexedSet<ICanvasElement>();

       //图形重建队列,当UI元素的图像需要更新时将其加入队列
       private readonly IndexedSet<ICanvasElement> m_GraphicRebuildQueue = new IndexedSet<ICanvasElement>();

       protected CanvasUpdateRegistry()
       {
           //监听了Canvas的willRenderCanvases事件,这个事件会在渲染前进行每帧调用
           Canvas.willRenderCanvases  = PerformUpdate;
       }
  1. PerformUpdate收集布局重建队列,图形重建队列调用ICanvasElement.Rebuild完成重建

何时加入重建

通过设置“脏数据”实现的,包括布局(Layout)、材质(Material)和顶点(Vertices)三部分,设置布局为脏,将进行布局重建,设置顶点或材质为脏,则进行图形重建。布局重建会将自身加入m_LayoutRebuildQueue中,图形重建则会将自身加入m_GraphicRebuildQueue中,等待被调用。 SetLayoutDirty:加入到布局重建队列 SetVerticesDirty,SetMaterialDirty:材质,顶点变换加入到图形重建队列

布局重建:位置或者大小 ;

图像重建:顶点变化,材质变化(大小,旋转以及文字变化、图片的修改)

优化

主要目标,把Profile里Canvas.SendWillRenderCanv参数调小。通过限制顶点数量,顶点变化等。

  1. text属性改变(“123”–>“1234”),触发SetLayoutDirty:在做倒计时相关,按照每1s改变,不要实时改变
  2. 改文字,图片颜色,触发SetVerticesDirty(顶点改变),所以改图片颜色最好是改材质球颜色
  3. layout组件引起重建问题
  4. text 描边,阴影性能问题 一个字符产生4个顶点, 如果再加上Shadow则相当于又把Text复制了一遍产生8个, Outline则会将Text复制4遍产生20个顶点。 用相应的shader替换
  5. text渐变
  6. Image格式选择 Image:顶点数量取决于Image Type的选择。 ①Simple 4 个顶点; ②Sliced 勾选FillCenter的顶点数是 36 个,不勾选是 32 个; ③Tiled 取决于Rectranform 设置的大小和原图大小,铺开了 N 张图就是 4*N 个; ④Filled 选择比较多,但最少也有4个。 所以对于Image首选Simple模式其次则是Sliced模式且不勾选FillCenter
  7. 动静分离 :Canvas.SendWillRenderCanvases()与Canvas.BuildBatch()的计算是以Canvas为根节点进行的,不同Canvas不会影响另外一个Canvas。但是,大量的动静分离反而影响Canvas的合批,所以可以针对性的对战斗UI,主界面做分离

源码中查看影响重建因素

触发SetLayoutDirty

Graphic:

  1. protected override void OnRectTransformDimensionsChange():当UI的RectTransform更改时的回调,只要继承UIBehavior即可获取回调

Image:

  1. protected override void OnCanvasHierarchyChanged():父画布的状态改变

Text:

  1. text属性改变:在做倒计时相关,按照每1s改变,不要实时改变
  2. public bool supportRichText:设置是否开启富文本时,开关规则(只要状态跟上次不同,SetLayoutDirty一下,而不是开启后实时Dirty)
  3. public bool resizeTextForBestFit:设置是否允许文本自动调整大小时,开关规则
  4. public int resizeTextMinSize:允许的最小文本大小
  5. public int resizeTextMaxSize:设置最大文本大小
  6. public TextAnchor alignment:文本相对其 RectTransform 的定位。
  7. public int fontSize:文本大小
  8. public HorizontalWrapMode horizontalOverflow:水平溢出模式
  9. public VerticalWrapMode verticalOverflow:垂直溢出模式
  10. public float lineSpacing:行间距,指定为字体行高的一个因子。值为 1 时将生成标准行间距
  11. public FontStyle fontStyle:字体样式

触发SetVerticesDirty:顶点变化

Graphic:

  1. public virtual Color color:颜色,所以改图片颜色最好是改材质球颜色
  2. protected override void OnRectTransformDimensionsChange():当UI的RectTransform更改时的回调,只要继承UIBehavior即可获取回调

Image:

  1. public Type type:Simple,Sliced等
  2. public bool preserveAspect:是否保持高宽比,开关规则
  3. public bool fillCenter
  4. public FillMethod fillMethod:填充模式
  5. public float fillAmount
  6. public bool fillClockwise
  7. public int fillOrigin
  8. public bool useSpriteMesh:图片透明部分裁剪
  9. protected override void OnCanvasHierarchyChanged():父画布改变

RawImage:

  1. public Texture texture
  2. public Rect uvRect

Shadow:

  1. public Color effectColor
  2. public Vector2 effectDistance
  3. public bool useGraphicAlpha

Text:

  1. public virtual string text
  2. public bool supportRichText
  3. public bool resizeTextForBestFit
  4. public int resizeTextMinSize
  5. public int resizeTextMaxSize
  6. public TextAnchor alignment
  7. public bool alignByGeometry:使用区段的字形几何执行水平对齐,而不是字形指标。 这可以导致更好的拟合左和右对齐,但可能会导致不正确的定位当试图覆盖多个字体(如专业轮廓字体)上
  8. public int fontSize
  9. public HorizontalWrapMode horizontalOverflow
  10. public VerticalWrapMode verticalOverflow
  11. public float lineSpacing
  12. public FontStyle fontStyle

触发SetMaterialDirty:材质改变

Graphic:

  1. public virtual Material material

Mask:

  1. public bool showMaskGraphic:
  2. protected override void OnEnable()
  3. protected override void OnDisable()
  4. protected override void OnValidate():编辑器用

MaskableGraphic:

  1. public bool maskable
  2. protected override void OnTransformParentChanged()
  3. protected override void OnCanvasHierarchyChanged()
  4. public virtual void RecalculateMasking():为此元素和所有子元素重新计算遮罩。

触发SetAllDirty,全改变

Image间接继承自Graphic,当它的Sprite发生变化时,会调用SetAllDirty函数 SetAllDirty改变时机

Graphic:

  1. protected override void OnTransformParentChanged() 父物体改变
  2. protected override void OnEnable()
  3. protected override void Reset():赋值默认值,只在编辑器下有用,可无视
  4. protected override void OnDidApplyAnimationProperties():动画属性改变
  5. protected override void OnValidate():脚本加载或Inspector中的任何值被修改时会调用,只在编辑器下有用,可无视

Image:

  1. static void RebuildImage(SpriteAtlas spriteAtlas) 图集改变
  2. sprite属性改变
  3. overrideSprite 临时修改图片
  4. public override void SetNativeSize() 设置大小

Text:

  1. public void FontTextureChanged():字体纹理被修改:TTF动态字体,Text每次赋值的时候Unity会生成贴图,以及保存每个字的UV信息,那么显示字体的时候根据UV信息去生成的贴图里取最终渲染在屏幕上。
  2. font属性更改

0 人点赞