7 Unity GUI Optimization Tips For Your Game

Unity has many optimization problems as well as best practices for GUI implementation, here are some of them!

1. Canvases

Description:

The Canvas is the basic component of Unity UI. It generates meshes that represent the UI elements placed on it, regenerates the meshes when UI elements change, and issues draw calls to the GPU so that the UI is displayed.

Generating these meshes can be expensive. UI elements need to be collected into batches so that they’re drawn in as few draw calls as possible. Because batch generation is expensive, we want to regenerate them only when necessary.

Problem:

When an element is changed, the whole canvas is reanalyzed.

Many users build their entire game’s UI in one single canvas with thousands of elements. So, when they change one element, they can experience a CPU spike costing multiple milliseconds.

Solution:

Divide up your canvases.

2. Graphic Raycaster

Description:

The Graphic Raycaster is the component that translates your input into UI Events. It translates screen/touch input into Events, and then sends them to interested UI elements. You need a Graphic Raycaster on every Canvas that requires input, including sub-canvases.

Problem:

The Graphic Raycaster performs intersection checks on UI elements that are interested in receiving input. However, not all UI elements are interested in receiving updates.

Solution:

Disable Raycast Target property for all non-interactive elements. For example, a text on a button. Turning off the Raycast Target will reduce the number of intersection checks the Graphic Raycaster must perform each frame.

3. Camera.main

Description:

When setting up a Canvas, you can specify which Camera to anticipate where interaction events should come from. There is an optional setting for World Space canvases called the Event Camera.

If you leave the Event Camera field blank on a World Space Canvas, it uses the game’s main camera (Camera.main).

Problem:

Unity will access Camera.main between 7–10 times per frame, per Graphic Raycaster, per World Space Canvas. Camera.main also calls Object.FindObjectWithTag every time it’s accessed!

Solution:

Avoid the use of Camera.main. If you use World Space canvases, always assign an Event Camera. Do not leave this setting empty!

4. Pooling UI Objects

Description:

Pooling is a useful way to avoid constant creation and deletion of objects.

Problem:

Often, pooling UI objects involves re-parenting and disabling, but this causes the hierarchy to be dirtied twice, and dirtying the new hierarchy too.

Solution:

Disable the object first, then re-parent it into the pool. When removing an object, re-parent it first, update your data, then enable it.

6. Hiding a Canvas

Description:

At times, you may want to hide your UI canvas or a group of components. There are a few ways to do it.

Problem:

Any way of hiding the canvas that leaves it enabled, even if invisible, leaves it prone to dirtying, which can reduce performance.

Solution:

Disable the entire canvas. If you want only a certain group of elements to disappear, group them on their own separate canvas.

6. Texture Atlases

Description:

A Texture Atlas is a large texture with a group of different textures. Every object (effect particles, textures) that share the same material are on the same draw call and will be sent to the GPU at once.

Problem:

Huge impact on the performance of your game when you have a ton of effects/textures. Text also is a major cause of extra draw calls as they are on a separate atlas which causes extra batching.

Solution:

Pack your sprites together to reduce draw calls by using Texture Atlases. Tip: TexturePacker is a really good tool for creating texture atlases.

7. Stacking UI

Description:

Any enabled GUI element causes a draw call, regardless of its position.

Problem:

UI objects that are off-screen and enabled increases the number of draw calls. Stacking UI images/text on top of each other causes more overdraw and will slow things down.

Solution:

Disable game objects and UI elements that are off-screen, or change the parent of an off-screen UI game object to a non-UI game object.

Other Unity UI Performance Tips

Limit the usage of ‘Best Fit’ and ‘Rich Text’ in Text components. Don’t use dynamic, use bitmap/static fonts if possible. Limit the usage of Outline/Shadow components on Text game objects. Bake the effect in the bitmap font instead. Stick to ‘simple’ sprites if possible. Avoid large ‘tiled’ sprites. Flatten out the transform hierarchy. The more nesting the more transform calculations needed to position children correctly. Uncheck “Pixel Perfect” in the Canvas settings. Big performance hitter. Screen Space Overlay UI is slightly faster than Screen Space Camera. In Overlay the UI is drawn on top of the screen immediately avoiding all the culling and sorting that Camera space has to go through. Prefer enabling/disabling the canvas itself instead of the entire gameobject. Avoiding OnEnable/OnDisable callbacks on the entire hierarchy which could be expensive. Updated pooled objects properties first before enabling it when borrowing an object from the pool. This avoids unnecessary dirtying of the object’s hierarchy With ScrollRects with many items, attach a Canvas (with no Pixel Perfect) to the scroll rect so that scrolling the items won’t dirty out the elements in the outer canvases

References

College, U. (2017, Septemeber 16). Unity3D Object Pooling — How to use them & why you should. Retrieved from YouTube: https://www.youtube.com/watch?v=7UswSdevSpw

Unity. (2019, January). Some of the best optimization tips for Unity UI. Retrieved from Unity: https://unity3d.com/how-to/unity-ui-optimization-tips

Unity. (n.d.). Unity UI Performance tips — Sharing my findings. Retrieved from Unity: https://forum.unity.com/threads/unity-ui-performance-tips-sharing-my-findings.524916/