Unity的优化系列(四):Canvas Overlay代替Screen Space Camera

发表于2017-10-11
评论0 3.8k浏览

Unity提供了用于创建 UI 的画布。画布上有渲染模式如下 ︰

  • 屏幕空间相机 Screen Space Camera
  • 屏幕空间覆盖 Screen Space Overlay
  • 世界空间 World Space

让我们了解哪种模式是更好的,让我们以一个非常简单的示例测试这三项。


1屏幕空间相机


让我们创建一个Unity项目︰

脚本 ︰ MoveCamera.cs

  1. 在你的场景建立一个Canvas。
  2. 设置渲染模式为:  Screen Space Camera
  3. 将Main Camera,拖到render camera 选项(其他相机也可以)。
  4. 用sprite或图像中作为一个背景。
  5. 才Canvas内创建尽可能多的panels 和 UI的Texts 和Images
  6. 添加到Camera上的脚本。

using UnityEngine;   
using System.Collections;  
public class MoveCamera : MonoBehaviour  
{  
    private float velocity = 0.0f;  
    private float smoothTime = 0.3f;  
    private bool moveCamera = false;  
    public Vector3 initialPosition;  
    public Vector3 targetPosition;  
    public float lerpSpeed;  
    public float initialZ;  
    public float targetZ;  
    public Camera cam;  
    void Update ()  
    {  
        if (Input.GetMouseButtonDown (0)) {  
            initialPosition = transform.position;  
            targetPosition = new Vector3 (transform.position.x   Random.Range (-5, 5), transform.position.y                 Random.Range (-5, 5), transform.position.z);  
            initialZ = transform.eulerAngles.z;  
            targetZ = initialZ   Random.Range (-50, 50);  
            moveCamera = true;  
            lerpSpeed = 0;  
        }  
        if (moveCamera) {  
            CameraMovementMethod ();  
        }  
    }  
    private void CameraMovementMethod ()  
    {  
        lerpSpeed = Mathf.SmoothDamp (lerpSpeed, 1.0f, ref velocity, smoothTime);  
        cam.transform.position = Vector3.Lerp (initialPosition, targetPosition, lerpSpeed);  
        cam.transform.eulerAngles = new Vector3 (0, 0, Mathf.LerpAngle (initialZ, targetZ, lerpSpeed));  
    }  
}  


  1. Build部署到 Android 手机、 创建debugging build ,允许自动连接到profiler
  2. 在手机上运行该项目的,然后在处理随便点击屏幕
  3. 在Unity编辑器中profiler上搜索 "canvas",你会看到。:


 正如你从图片中可以看到,有很多的画布的调用Calls,特别注意到CanvasRender.OnTransformChanged

每当相机移动大约每个帧上 50 调用。

注意   调用次数是依赖于Canvas上的 使用的UI 元素个数

我们可以更好地理解这与下面 gif:



你可以看到上面,在游戏中移动Canvas相关的摄像机,因此每个UI 元素在画布上不得不由Unity引擎重新定位。因此越多的UI元素,就需要更多的处理


那么,解决方案是什么?


2屏幕空间覆盖


在刚刚的测试项目中我们把 Canvas的渲染模式改为 Screen Space Overlay ,并重复之前的步骤,同样想在观察Profiler。

大约我们优化它约 90%


正如你可以看到以上,UI 画布保持原样在Unity空间,摄像机运动的不影响 UI Canvas根本。画布保持静态。


因此,不需要任何重新定位或所需的处理。


实现了高的优化。


3世界空间


在世界空间模式,画布渲染手动更改为 World Space,测试结果和第一种一样。

结论 


考虑screen space camera 类型的呈现进行大量的调用,所以非常推荐使用Overlay 绘制画布,使你的游戏在移动设备上更顺畅。(当然了这种只是限于纯UI),但是另外两种模式是有其特殊用处的!


ForEach 循环优化



这是个老生常谈的话题, 主要还是产生GC的问题:

public class ForEachLoopTest : MonoBehaviour  
{   
    #region PUBLIC_DECLARATIONS  
    public List<GameObject> emptyGameObjects;  
    #endregion  
    #region UNITY_CALLBACKS  
    void Update()  
    {  
        if (Input.GetKey(KeyCode.Space))  
        {  
            UpdateTextValue();  
        }  
    }  
    #endregion  
    #region PUBLIC_METHODS  
    public void UpdateTextValue()  
    {  
        foreach (var item in emptyGameObjects)  
        {  
            // PROCESS ITEMS IN LIST  
        }  
//        for (int i = 0; i < emptyGameObjects .Count; i )  
//        {  
        // PROCESS ITEMS IN LIST  
//        }  
    }  
    #endregion   
}  


按下空格键 ,当是10~30大小的循环时  会看到如上图的 效果: 每帧产生 40GC


foreach (SomeType sin someList)

    s.DoSomething();


现在编译, 编译器预处理的代码:

using (SomeType.Enumerator enumerator = this.someList.GetEnumerator())  
{  
    while (enumerator.MoveNext())  
    {  
        SomeType s = (SomeType)enumerator.Current;  
        s.DoSomething();  
    }  
}  


在每次迭代时,会创建一个 enumerator对象。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论