UI Optimization In Unity
On my previous article, I have tried to explain some main optimization topics in Unity. In this article, I will be focusing on Optimizing the UI. You might be surprised how UI might slow down your game with an unproper design. The main reason is that UI system does not have the functionality to update a single entity within the Canvas.
As Unity suggests :
Because of the way Unity handles UI rendering, a canvas element that changes its position, scale, or rotation forces the canvas to rebuild. Changing the contents of a UI object such as text also forces this rebuild.
“When a Canvas has been marked as containing geometry that requires rebatching, the Canvas is considered dirty.
Geometry is provided to Canvases by Canvas Renderer components.”
Meaning, even though there’s only one game object that changes on the next frame, the whole Canvas is being redrawn — as Unity engine tries to arrange the Canvas as optimal as possible. Unity defines the end result caused by refreshing the whole Canvas as a result of change within a single or more elements as “dirtying the Canvas”.
So why is this a problem? Let’s dig into some detail:
Batching is the process in which the Canvas caches the meshes that represent its UI elements. The cached batch is being used until a change within an UI element dirties the Canvas. The process of redrawing the cached batch is called rebuilding.
The rebuilding process is performed with the calling of ICanvasElement.Rebuild method. As you can guess, each call of this method causes Unity to recalculate the layout and graphic components — and of course, creating a load on the device. Placing the all of the UI elements within a single Canvas is not a good idea for this particular reason. Even if there’s a single element that is being updated within the Canvas, it will force the Unity Engine to redraw the Canvas completely, including the unchanged elements. Certainly, this means redundant load on the CPU/GPU and may be noticed with spikes on the Profiler.
The solution is pretty simple as provided in the beginning. By seperating the Canvas into 2 Canvases namely Active and Static (or whatever you want to call them), we can prevent the static UI elements from redrawning redundantly. As Unity suggests, childing the Canvases will also isolate their contect from each other.
As Unity suggests, a dirty child Canvas will not cause the parent to rebuild its geometry, and vice versa. Unity recommends us to differentiate the active and static Canvases; meaning that the UI elements that are being dynamically changed should be put into a different Canvas game object than the static ones.
Raycasts Within Images
Our interactions with the UI are being processed by the Graphic Raycaster component of Unity, which gathers our input and processes them out as events. The image component (which is also a default component in buttons) has a field “Raycast Target”.
You might have mistakenly placed some UI buttons/images onto each other, you might faced a problem that you could not click to a certain element as another one is placed above it. By unchecking the “Raycast Target” field, we simply change the component to an uninteractable one.
There’s no point on having a static object with “Raycast Target” value set to true. Make sure to uncheck the uninteracting ones so that Graphic Raycaster will have lower the amount of checks on each frame.
Additional Optimizations
Another interesting fact is that if you want to turn off a Canvas group; turning off the Canvas component within the Canvas game object is more efficient than turning off the entire Canvas game object.
Unity also suggests us to avoid using Layout Groups if possible, as it will be using GetComponents call.
I had no idea regarding pooling the UI objects in a correct way. Rather than first reparenting and then disabling an UI object, it is better to parent it first and then disabling it — as it will only dirty the old hieararchy.
For more detailed information in optimizing your UI, I highly recommend you to check out Unity’s article on this topic from the link below :