- Home /
Disabling canvas renderer optimization
Unity's UI optimization tutorial mentions that one way to optimize hiding parts of the UI would be by Disabling Canvas Renderers.
However, they don't exactly say how this should be done, and I haven't found that on the current documentation for Canvas Renderers or the legacy one (since this tutorial was checked with Unity 5.3).
The only thing they say is that what should be done is to
[...] place the UI to be shown/hidden onto its own Canvas or Sub-canvas and then to merely enable/disable the Canvas Renderer component attached to that Canvas or Sub-canvas.
Is there a way to actually enable/disable the Canvas Renderer component or is there another optimized way to stop rendering UI Graphic components from a Sub-canvas without discarding VBO data?
I know that I can hide the UI objects by disabling the Canvas, disabling the GameObject or setting the Canvas Group alpha to 0, but I really need to make a WebGL build as optimized as possible, since the client needs it to run on an iPad, so please help me if you can.
Thanks.
Answer by Scoutas · Feb 07, 2017 at 02:03 AM
It's as simple as disabling the Canvas component, as it's the thing that's handling all the rendering of the UI.
Did a test with thousands of Canvas objects, and it did increase the render time by around 1ms for me, and disabling the Canvas component removed that delay.
Hi Scoutas, thank you for your answer.
I'm not sure if that is the case, but can you tell me if there were any lag spikes when disabling or reenabling the Canvas objects?
The reason why I'm in doubt is because the documentation states that, when disabling a Canvas Renderer component attached to the Canvas or Sub-Canvas:
[...] this will not eli$$anonymous$$ate the UI’s Graphics from the GraphicRegistry and so they will still be present in the list of components to check for a Graphic Raycast. It does not disable any $$anonymous$$onoBehaviours within the hidden UI, and so these $$anonymous$$onoBehaviours will still receive Unity lifecycle callbacks, such as Update.
I believe that this doesn't happen when the Canvas component is disabled, since the Event System stop logging information about raycasting of those components under the disabled Canvas.
As a comparison, recently, by exa$$anonymous$$ing the Toggle source code, I've noticed that what they do to stop rendering the target graphic when the toggle is off is by using graphic.canvasRenderer.SetAlpha(0f);
Even though this actually disables the rendering and keeps the graphic in the GraphicRegistry since raycast still apply to the invisible object, it doesn't affect the rendering of the graphic's children. If it did, it would be just as the documentation says things should behave and it would be the answer to my problems.
By disabling the canvas component, on the other hand, the rendering of all the elements inside said canvas actually stop, but I believe it also eli$$anonymous$$ates those graphics from the GraphicRegistry, since the now invisible buttons are not clickable anymore.
So either:
There might be an overhead when enabling/disabling the Canvas component that should not be present when disabling the canvas renderer of attached to a Canvas (even though I'm not quite sure how that should be done)
That is how things should be done and the Event System checks the raycast for the UI's Graphics under the disabled Canvas, but doesn't say that those Graphics were checked. But I'm inclined to say that is not the case, since the Toggle behaves differently.
Thank you for your help.
Okay, I did a tiny ammount of digging around. I'm not exactly sure how it all worked before, but right now, each UI element has it's own CanvasRenderer component inside of them (e.g. an Image has it's own CanvasRenderer and it's dependant on the Image component, so it can't be removed).
Anyway, did some tests. The rendering is actually not the most demanding thing from this whole thing. Did a test again, using lots and lots of canvases and buttons. The rendering for that only really took around 0.5ms at most. Setting the alpha of the renderers actually removed that 0.5ms delay, and I could still use the buttons that were in the UI.
On the other hand, the EventSystem is rather demanding. With around 800 buttons altogether, one click jumped the delay from ~0.8ms, to 5-6ms.
Anyway, the take-away is this: There's no actual way to disable the CanvasRenderer. If you disable the UIComponent of it, you lose the raycasting target and can't actually interact with any of them.
Of course, I tested this all out with built-in Unity UI buttons, so I would guess that more complex imagery and such would be a little more demanding, but setting the alpha of these components to 0, actually reduces the rendering load. You would have to play around with some setting of it afterwards, so that it wouldn't turn back on when you don't want to and such.
As for disabling the children alphas - I used a code that would get every single CanvasRenderer component from the Canvas children and set all their alphas to 0.
public class Alpha : $$anonymous$$onoBehaviour{
public GameObject canvas;
void Start(){
CanvasRenderer[] canvasRenderers = canvas.GetComponentsInChildren<CanvasRenderer>();
foreach(CanvasRenderer c in canvasRenderers){
c.SetAlpha(0);
}
}
}
It's not that demanding, and it does the job.
I'm sorry if I am misunderstanding your question, because it feels a little bit like I am, but I hope you'll get something out of this all.
Yeah, I guess the best option would be to set the alpha of the canvas renderer of each child object inside a canvas, like you did, whenever I need to disable/enable objects.
$$anonymous$$y problem was more with the lack of clear information on Unity's UI optimization tutorial than everything, but I guess this solution is the closest thing to how the tutorial said it should behave.
Thanks
Answer by sddayord · Feb 07, 2017 at 05:38 PM
Hi,
not 100% sure on this but try:
Canvas c;
c.GetComponent<CanvasRenderer>().cull = false;
The problem with this is that this doesn't seem to propagate to the children so you may need to individually reference their canvas components although I don't know if this will be faster. It may be a Unity issue at this point you never know. I tried it on 5.2
Answer by Bertlapp · Mar 28, 2019 at 09:04 PM
Nice,
This did the trick for my dynamic scroll list filled with score views and Facebook picture.
Answer by PuzzledBoy · May 06, 2019 at 08:38 AM
I don't think exist a way to disable "Canvas Renderer".
you can log the dirty state change by call "RegisterDirtyLayoutCallBack" or "RegisterDirtyVerticesCallBack" on Awake
and you can find out that "CanvasRenderer.cull = false" or "CanvasRenderer.SetAlpha(0)"
still cause a dirty.
The UI optimization tutorial said that
"One possible, but hacky, workaround is to place the UI to be shown/hidden onto its own Canvas or Sub-canvas and then to merely enable/disable the Canvas component on this object."
So the poper way to do that is create a Canvas Component and disable it.
Your answer
Follow this Question
Related Questions
Unity UI Position 2 Answers
UI doesn't render after scene reload. 0 Answers
Problem with build version 1 Answer
Play MP4 on UI? (Unity 3D 2018.2) 0 Answers