Search Unity

Healt-Bar Bad Canvas Performance

Discussion in 'UGUI & TextMesh Pro' started by LeekAndRibs, Apr 11, 2021.

  1. LeekAndRibs

    LeekAndRibs

    Joined:
    Mar 7, 2017
    Posts:
    49
    Hi guys,

    At the end of a larger project, I started working on the performance and realized that around 25% of computing Power(on mobile) are used for moving HealthBars above the units. I created a small test project to reproduce this.

    The Components are:
    - Camera
    - Canvas Screen - Camera(set to our Scene Camera)
    Bildschirmfoto 2021-04-11 um 23.35.57.png
    Prefabs:
    - 3D Cube(as Player)
    - UI HealthBar(with a simple TextMeshProUGUI and Image as childs)
    - All Raycasts and special options on Image and TMPro are disabled Bildschirmfoto 2021-04-11 um 21.48.36.png

    The HealthBar has a script attached:
    Code (CSharp):
    1.  
    2. public class SimpleFollow : MonoBehaviour
    3. {
    4.     public Transform Target;
    5.     RectTransform mRectTransform;
    6.  
    7.     private void Start()
    8.     {
    9.         mRectTransform = GetComponent<RectTransform>();
    10.     }
    11.  
    12.     // Update is called once per frame
    13.     void Update()
    14.     {
    15.         mRectTransform.anchoredPosition = Creator.Instance.TheMainCamera.WorldToScreenPoint(Target.position);
    16.     }
    17. }
    18.  
    Then I create 100 player objects and 100 health bars:
    Code (CSharp):
    1.  
    2. public class Creator : MonoBehaviour
    3. {
    4.     public static Creator Instance;
    5.     public Camera TheMainCamera;
    6.  
    7.  
    8.     public GameObject PlayerPrefab;
    9.     public SimpleFollow HealthBarPrefab;
    10.  
    11.     // Start is called before the first frame update
    12.     void Start()
    13.     {
    14.         Instance = this;
    15.  
    16.         for(int i = 0; i < 100; i++)
    17.         {
    18.             Transform t = Instantiate(PlayerPrefab).transform;
    19.             t.position = new Vector3(Random.Range(-10, 10), Random.Range(-10, 10), Random.Range(-10, 10));
    20.             SimpleFollow s = Instantiate(HealthBarPrefab, FindObjectOfType<Canvas>().transform);
    21.             s.Target = t;
    22.         }
    23.     }
    24.  
    25. }
    26.  
    As long as none of the player objects or the camera is moved, everything is perfect:

    Bildschirmfoto 2021-04-11 um 23.42.28.png
    But as soon as I move a single player object or the camera, the FPS drops drastically:

    Bildschirmfoto 2021-04-11 um 20.40.09.png
    As I understood, this is normal, as the entire canvas has to be recalculated as soon as one of the child objects has changed in its properties. The solution can be to create your own sub-canvas for dynamic elements. However, this only makes sense if there are other elements within the canvas that don't have to be changed in every frame anyway (which is not the case in this test project) ... I have already thought about dividing the 100 bars into 10 sub-canvas so that when you change a single health bar you don't have to recalculate all the other 99, but only 9, but this idea doesn't really convince me either.

    Within the editor, the 4ms per frame can be coped with, but the impact on the smartphone is four times higher, which is of course noticeable. Is there a solution for this problem, or do I have to live with the FPS drop on mobile?

    I thank you in advance for any answer :)

    edit: Unity Version 2020.2.3f1

    Best,
    Coco07
     
    Last edited: Apr 12, 2021
  2. LeekAndRibs

    LeekAndRibs

    Joined:
    Mar 7, 2017
    Posts:
    49