Canvas off on

Hi, Quick question:

I’ve got two canvases. How to switch one ON and OFF effectively. EFFECTIVELY

No way. Canvas (and it’s graphic elemts) makes a huge amount of unnecessary calculations OnEnable. Moving it or resizing triggers same calculations. That’s why all unity ways of hiding and showing objects back will not be effective with canvas. Maybe, you can hide and show it fast enough by adding canvas group at top and setting it’s alpha=0, raycastTarget=false;, but this sounds like a perversion. And probaly will be not effective because it will continue to render and animate.
Currently I know only one solution for this, don’t do complex GUI in Unity, that’s it.

So are you saying that it is okay for a canvas to get dirtied? cuz every time something is changed on canvas it gets dirtied.

Yes, it’s canvas normal behaviour. It gets dirtied for every possible reason and regenerates meshes, recalculates layouts and masks, and doing a lot of different stuff every time you change something.
But if change happend in chind canvas, it won’t make parent canvas dirty. So splitting your canvas into subcanvases should improve performance for animations and alike. Still, enabling the parent canvas will probably make all children dirty.

1 Like

so like if there is a scroll rect in the canvas. I should put that into a subcanvas right?

In general, group your stuff on different canvases by changing occasions:

  • one canvas for changing never (static images, etc)
  • one canvas for occasional changes together
  • one canvas to update frequently

or in any other ways you want, but your goal is to only change what actually needs to change.
If you want to show/hide a group of stuff (window or something), put it on a canvas and show/hide the canvas. It won’t trigger rebuild.

Please consider watching this Unite presentation. It worth it, believe me.

6 Likes

Thanks.

I watched the video. It was very informative. Thanks for recommending. Now HOW should i do? coding wise?

What should i actually write to Show/hide canvas?

Here’s my observations so far.
I think method#2 is better, right?
Im using laptop profiler.

 public void LoadCanvasClick(string CanvasName  ) {
        if (CanvasName == "Canvas1") {

            Canvas1.gameObject.SetActive(true);

            Canvas2.gameObject.SetActive(false);
         
        }
        else if (CanvasName == "Canvas2") {
            Canvas2.gameObject.SetActive(true);
            Canvas1.gameObject.SetActive(false);
       
        }
     
}

the before button press: profiler at smooth 1000fps takes 1 ms
after button press profiler spike hits 30fps, Huge spike

Method#2

public void LoadCanvasClick(string CanvasName  ) {
        if (CanvasName == "Canvas1") {

        
            Canvas2_canvasgroup.alpha = 0;
            Canvas2_canvasgroup.blocksRaycasts = false;
            Canvas1_canvasgroup.alpha = 1;
            Canvas21_canvasgroup.blocksRaycasts = true;
        }
        else if (CanvasName == "Canvas2") {

            Canvas2_canvasgroup.alpha = 1;
            Canvas2_canvasgroup.blocksRaycasts = true;
            Canvas1_canvasgroup.alpha = 0;
            Canvas1_canvasgroup.blocksRaycasts = false;
        }
    
}

the before button press: profiler at smooth 1000fps( takes 1 ms)
after button press profiler hits 250fps (takes 4ms). occasional hits to 250fps but stays at the bed of 1000fps.

In the video (if i remember correctly) he said that even if it’s set to alpha 0 it’s still rendered,
but on the other hand if the canvas is deactivated it doesn’t recieve calls for geometry redo.
So on mobile for example i think the performance would constantly be lower with the alpha 0.
Also bear in mind that if you have decent PC, the results might be good enough in your case but not so on low-ish-end PCs.
In build game the spike might not even be noticable maybe? Is your UI very complex?

1 Like

Yes, I realise this that why i stated im using laptop. i know on laptop frame rate is better/

No ui is simple. It just Leaderboard UI. What i did was scrollrect was In separate canvas. so three canvas, since 3 leaderboards. and nonmoving stuff in another canvas. so total of 4 canvases. this was before watching the video.
i should just add canvas component with the scroll rect right?

I just need to know am i being paranoid with this stuff. I have a very shitty phone that i only use for testing. Its very low end. And buggy. the game seems to run fine on it tbh. No stuttering. But this keeping spikes low shit is messing with me head.

plus the game is only 2d single player.

Maybe you see a spike in the profiler, but does it really effect anything in the game? Usually switching from one UI to another is not a very performance-critical event in a game.

1 Like

APPARENTLY it doesnt, empirically its fine. All good. but main point of this post is to find out IF there is something shady going on under the hood.

Highly suggest against two canvas. I would recommend turning sub game object under the canvas on and off.
that being said, code below does exactly what you want. Put it on an empty GameObject at the root (not a child of either of the canvas) and drag your canvas game objects to the script. press S to Switch. again!, this is not a good idea.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestScript : MonoBehaviour {
    public GameObject Canvas1;
    public GameObject Canvas2;
    // Use this for initialization
    void Start () {
        Canvas1.SetActive(true);
        Canvas1.SetActive(false);
    }
   
    // Update is called once per frame
    void Update () {
        //Simulate an event the canvas needs to be switched
        if(Input.GetKeyDown(KeyCode.S))
        {
            Canvas1.SetActive(!Canvas1.activeSelf);
            Canvas2.SetActive(!Canvas2.activeSelf);
        }
    }
}
1 Like

Yeah, this was the first thing that i did. But what’s the optimal solution. This is the first solution. Seeking the optimum solution here.

optimal solution according to me: have 1 canvas. everything you need to toggle can be a child of the canvas. if those children need interaction events then ray cast block and alpha test only the image component in those game objects. Also suggest using layout group to improve event times.

1 Like

Have you tried layer-based rendering? You may add LayerCanvas1, LayerCanvas2 for canvases respectively and then enable/disable those layers in your camera rendering layers list? But you also should add canvas group on canvases and check their intercatable and lblockraycast flags when swithcing because I believe elements hidden this way will remain clickable.

2 Likes
   public GameObject Canvas1;
   Canvas1.SetActive(false);

Have you read this?

1 Like