Image怎么绘制的
Unity中渲染的物体都是由网格(Mesh)构成的,而网格的绘制单元是图元(点、线、三角面) 绘制信息都存储在Vertexhelper类中,除了顶点外,还包括法线、UV、颜色、切线。
Rebuild概念
Canvas负责将子节点的UI元素的网格合并,并生成相应的渲染指令再发送到Unity的图形管道的过程。所以Canvas就是渲染UI的组件,当UI发生变化就要执行一次Batch,它是影响性能更大的元凶。注意Canvas的Batch只会影响其子节点,但不会影响其子Canvas。
Rebuild的程序流程
- Image,Text都是继承Graphic,Graphic有ICanvasElement接口,实现rebuild函数
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);
- CanvasUpdateRegistry监听Canvas的willRenderCanvases事件,这个事件会在渲染前进行每帧调用
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;
}
- PerformUpdate收集布局重建队列,图形重建队列调用ICanvasElement.Rebuild完成重建
何时加入重建
通过设置“脏数据”实现的,包括布局(Layout)、材质(Material)和顶点(Vertices)三部分,设置布局为脏,将进行布局重建,设置顶点或材质为脏,则进行图形重建。布局重建会将自身加入m_LayoutRebuildQueue中,图形重建则会将自身加入m_GraphicRebuildQueue中,等待被调用。 SetLayoutDirty:加入到布局重建队列 SetVerticesDirty,SetMaterialDirty:材质,顶点变换加入到图形重建队列
布局重建:位置或者大小 ;
图像重建:顶点变化,材质变化(大小,旋转以及文字变化、图片的修改)
优化
主要目标,把Profile里Canvas.SendWillRenderCanv参数调小。通过限制顶点数量,顶点变化等。
- text属性改变(“123”–>“1234”),触发SetLayoutDirty:在做倒计时相关,按照每1s改变,不要实时改变
- 改文字,图片颜色,触发SetVerticesDirty(顶点改变),所以改图片颜色最好是改材质球颜色
- layout组件引起重建问题
- text 描边,阴影性能问题 一个字符产生4个顶点, 如果再加上Shadow则相当于又把Text复制了一遍产生8个, Outline则会将Text复制4遍产生20个顶点。 用相应的shader替换
- text渐变
- Image格式选择 Image:顶点数量取决于Image Type的选择。 ①Simple 4 个顶点; ②Sliced 勾选FillCenter的顶点数是 36 个,不勾选是 32 个; ③Tiled 取决于Rectranform 设置的大小和原图大小,铺开了 N 张图就是 4*N 个; ④Filled 选择比较多,但最少也有4个。 所以对于Image首选Simple模式其次则是Sliced模式且不勾选FillCenter
- 动静分离 :Canvas.SendWillRenderCanvases()与Canvas.BuildBatch()的计算是以Canvas为根节点进行的,不同Canvas不会影响另外一个Canvas。但是,大量的动静分离反而影响Canvas的合批,所以可以针对性的对战斗UI,主界面做分离
源码中查看影响重建因素
触发SetLayoutDirty
Graphic:
- protected override void OnRectTransformDimensionsChange():当UI的RectTransform更改时的回调,只要继承UIBehavior即可获取回调
Image:
- protected override void OnCanvasHierarchyChanged():父画布的状态改变
Text:
- text属性改变:在做倒计时相关,按照每1s改变,不要实时改变
- public bool supportRichText:设置是否开启富文本时,开关规则(只要状态跟上次不同,SetLayoutDirty一下,而不是开启后实时Dirty)
- public bool resizeTextForBestFit:设置是否允许文本自动调整大小时,开关规则
- public int resizeTextMinSize:允许的最小文本大小
- public int resizeTextMaxSize:设置最大文本大小
- public TextAnchor alignment:文本相对其 RectTransform 的定位。
- public int fontSize:文本大小
- public HorizontalWrapMode horizontalOverflow:水平溢出模式
- public VerticalWrapMode verticalOverflow:垂直溢出模式
- public float lineSpacing:行间距,指定为字体行高的一个因子。值为 1 时将生成标准行间距
- public FontStyle fontStyle:字体样式
触发SetVerticesDirty:顶点变化
Graphic:
- public virtual Color color:颜色,所以改图片颜色最好是改材质球颜色
- protected override void OnRectTransformDimensionsChange():当UI的RectTransform更改时的回调,只要继承UIBehavior即可获取回调
Image:
- public Type type:Simple,Sliced等
- public bool preserveAspect:是否保持高宽比,开关规则
- public bool fillCenter
- public FillMethod fillMethod:填充模式
- public float fillAmount
- public bool fillClockwise
- public int fillOrigin
- public bool useSpriteMesh:图片透明部分裁剪
- protected override void OnCanvasHierarchyChanged():父画布改变
RawImage:
- public Texture texture
- public Rect uvRect
Shadow:
- public Color effectColor
- public Vector2 effectDistance
- public bool useGraphicAlpha
Text:
- public virtual string text
- public bool supportRichText
- public bool resizeTextForBestFit
- public int resizeTextMinSize
- public int resizeTextMaxSize
- public TextAnchor alignment
- public bool alignByGeometry:使用区段的字形几何执行水平对齐,而不是字形指标。 这可以导致更好的拟合左和右对齐,但可能会导致不正确的定位当试图覆盖多个字体(如专业轮廓字体)上
- public int fontSize
- public HorizontalWrapMode horizontalOverflow
- public VerticalWrapMode verticalOverflow
- public float lineSpacing
- public FontStyle fontStyle
触发SetMaterialDirty:材质改变
Graphic:
- public virtual Material material
Mask:
- public bool showMaskGraphic:
- protected override void OnEnable()
- protected override void OnDisable()
- protected override void OnValidate():编辑器用
MaskableGraphic:
- public bool maskable
- protected override void OnTransformParentChanged()
- protected override void OnCanvasHierarchyChanged()
- public virtual void RecalculateMasking():为此元素和所有子元素重新计算遮罩。
触发SetAllDirty,全改变
Image间接继承自Graphic,当它的Sprite发生变化时,会调用SetAllDirty函数 SetAllDirty改变时机
Graphic:
- protected override void OnTransformParentChanged() 父物体改变
- protected override void OnEnable()
- protected override void Reset():赋值默认值,只在编辑器下有用,可无视
- protected override void OnDidApplyAnimationProperties():动画属性改变
- protected override void OnValidate():脚本加载或Inspector中的任何值被修改时会调用,只在编辑器下有用,可无视
Image:
- static void RebuildImage(SpriteAtlas spriteAtlas) 图集改变
- sprite属性改变
- overrideSprite 临时修改图片
- public override void SetNativeSize() 设置大小
Text:
- public void FontTextureChanged():字体纹理被修改:TTF动态字体,Text每次赋值的时候Unity会生成贴图,以及保存每个字的UV信息,那么显示字体的时候根据UV信息去生成的贴图里取最终渲染在屏幕上。
- font属性更改