UGUI浅析

简单分析UGUI和NGUI差异

Posted by Bob on September 11, 2018

NGUIArenMook开发的是一款收费Unity插件($95),多用于做Unity游戏UI系统。作者曾被Unity招安一年开发了官方版本UI系统UGUI,最终与Unity意见相左离开了,但至今他的NGUI仍然维护中,国内游戏NGUI使用率相对更高一些。UIGUI仅开源部分C#代码,核心代码是未开源,NGUI源码完全可自行优化或扩展。

UGUI

Renderer
  • CanvasRenderer
Canvas Render Mode
  • overlay 无需摄像机,贴着摄像机镜头渲染,永远在最上面
  • camera 距摄像机一定距离渲染, 可前后穿插粒子和3d模型等
  • worldSpace 融合到3D世界
Canvas Scale Mode
  • Constant Pixel Size:使UI保持自己的尺寸,与屏幕尺寸无关。

  • Scale With Screen Size:根据屏幕尺寸适配UI

    a、Match Width Or Height:Match属性是屏幕的宽度和高度对UI大小的适配影响。

    b、Expand:缩放时不裁剪UI,当屏幕分辨率和设定不同时,选择变化较小的方向进行缩放。(白话:尽量等比缩放,把你放到屏幕中,完全显示在屏幕中)

    c、Shrink:缩放时裁剪UI,当屏幕分辨率和设定不同时,选择变化较大的方向进行缩放。(白话:尽量等比缩放,撑满屏幕的高或宽,会溢出屏幕)

  • Constant Physical Size:使UI元素保持相同的物理大小,与屏幕尺寸无关。

基本设置

如果Render Mode设置为camera,并设置为平行投影,其orthographicSize的含义为屏幕高度的一半, 单位不是px而是unit坐标, 约定设计分辨率为1280x720,则size=3.6(Camera.Size=Screen Height/2/Pixel To Units),上半屏幕刚好可看到3.6个单位大小为1的cube和3.6个100pixel的sprite。

image

如果Scale Mode设置为Match Width Or Height,取值为1,整体缩放值的是以高来做适配。高度不同分辨率高度完全可见,宽度可视范围不同。

image

如果Sprite图片的Pixels Per Unit 设置的是100,也就是图片的100个像素对应到一个Unity3D单位。修改 Reference Pixels Per Unit 与 Pixels Per Unit 后,点下 Image 的 Set Native Size来设定图片原始大小。

image

ui大小 pixels spritePixelsPerUnit referencePixelsPerUnit
100 100 100 100
200 100 100 200
50 100 200 100

可推导如下公式:

ui rectTransform width/height = pixels/(spritePixelsPerUnit / referencePixelsPerUnit)

VertexHelper
  • positions、colors、uv0s、uv1s、normals、tangents
RectTransform
  • Achors 锚框

a、四个锚点在重合时,UI尺寸固定,但可能位置会超出父节点。

b、四个锚点全部分开时,UI会随着父节点的尺寸改变而变化。

c、锚点左右两边分开时,UI的height不会随父节点的变化而改变,width会随着父节点的改变而改变。

d、锚点上下两边分开时,UI的width不会随父节点的变化而改变,height会随着父节点的改变而改变。

  • Pivot 旋转、缩放等操作注册点
  • 只能针对父级结节,不能跨层级锚点
Sorting
  • Camera的depth值越小,越先渲染
  • 同一个Canvas中,Hierarchy的顺序决定了控件的层级关系,越往下显示越靠前,用SetSiblingIndex等设置深度。
  • 不同Canvas用sortingLayer 和 sortingOrder
  • z轴排序
  • ParticleSystem融合UI用Sorting Order调整层级
Canvas.SendWillRenderCanvas
  • layoutRebuildQueue、graphicRebuildQueue(变化的对象在渲染前触发,没有轮询)
Hidden
  • Scale=0,Alpha Group=0 没有Mesh,不渲染
  • null sprite,Color.a = 0,屏幕外物体,仍然渲染
Batching
  • 穿插重叠、旋转等导致打断合批
  • z != 0 不合批
  • localposition不断更新(即使值没有变化)导致不断重建
  • Canvas.BuildBatch更新所有DC:WatigForJob、PutGeometryJobFence、BatchRenderer.Flush*。canvas内任何可视元素的改变(“改变”是指影响UI元素外观的任何变动,包括修改sprite renderer的sprite、transform的position和scale、文本网格的text等。修改Image、Text的color属性,会改变UIVertex.color;修改RectTransform的Size、Anchors、Pivot等,会改变UIVertex.position)都会触发canvas的rebuild,Rebuilding batches是一件很重的事。为了减少batching开销,我们可以合并Sprite、Text等来平衡draw call和batching开销,或把变化的元素提取一个单独Canvas,做到动静分离。
  • Mesh合并在C++ Native端做的,融合了多线程操作,大量动态元素合批效率高。
  • Mask(Stencil buffer)导致DrawCall上升。换RectMask2D可提升一点性能。
  • 修改Image的Color属性实际是修改顶点色,会导致Mesh重建,但材质不变,不会产生额外的DC。如果修改Image的Material的Tint Color属性,不会导致Mesh重建,但修改了Material,会导致多一个DC。
  • Frame Debugger (封闭API,无法了解合批细节)
Raycast
  • Event、Raycasters基于事件回调机制,效率略高,不需要绑定collider
  • Image、Text组件不需要事件触发的将Raycast Target勾去掉
  • FullScreen事件
using UnityEngine;
using System.Collections;

namespace UnityEngine.UI
{
    public class NonDrawRaycast : MaskableGraphic
    {
        protected NonDrawRaycast()
        {
            useLegacyMeshGeneration = false;
        }

        protected override void OnPopulateMesh(VertexHelper vh)
        {
            vh.Clear();
        }
    }
}
OverDraw
  • Image:中间空的边框图不勾FillCenter
  • PolygonImage贴图更紧凑,Fill rate更低。
Altas
  • 保持所有Sprite统一设置贴图属性,否则分离成多张
  • Sprite的tag和assetbundle name设置
  • Sprite Packer
  • Sprite Altas(2017)
基本组件
  • Canvas 有世界和屏幕坐标
  • Image可以设置Material
  • Nav可视化编辑
扩展组件

NGUI

Renderer
  • MeshRenderer
UIRoot
  • Scaling Style
Achors
  • Target 可以指定任意GameObject,有设置时序问题。
Sorting
  • Camera的depth值越小,越先渲染
  • UIPanel的sorting order、widget的depth、RenderQueue共同影响排序.可以很细粒度手工控制。
  • ParticleSystem融合UI用Render Queue调整层级
  • 3D模型可用RenderTexture或Render Queue融合UI层级
  • Mask使用透明度裁剪
Batching
  • Mesh Renderer来做渲染,合批在C#层做的
  • DrawCall Tool
Hidden
  • Color.a = 0 没有Mesh,不渲染
  • SetActive(false) 不渲染,保留Mesh
  • Scale = 0 保留Mesh,仍然渲染
UIGeometry
UILabel
  • Font.CahceFontForText(动态创建更新FontTexture产生的消耗,当文字color、size等变化都会导致FontTexture扩大或更新)
  • Shadow
  • Outline/Outline8(Mesh增加)
  • Text Mesh Pro插件
UISprite
  • Tiled Mode(Mesh增加,节约纹理尺寸)
UIPanel
  • UIPanel.FillDrawCall(更新单个DC)
  • 触发UIPanel.FillAllDrawCalls(更新所有DC)原因:1.添加或删除元素时,穿插了其他的UIDrawCall。2.添加或删除的元素自成一个UIDrawCall。避免方式:1.尝试让插入的元素合入现有的UIDrawCall。2.Scale=0或者Alpha接近0来隐藏。
  • UIPanel.LateUpdate(每帧轮询所有widget)、UICamera.Upate、UIRect.Update、UIRoot.Update
  • Clip做裁剪
Altas
Raycast
  • 需要绑定collider,通过SendMessage发出事件