A Unity Editor tool that automatically optimizes selected UI game objects (including Prefabs) to save you time.
For starters, import the package located in the Releases section into your project.
Now then, inside the Unity Editor, select any number of game objects anywhere: in the scene's Hierarchy, in the Project window or in Prefab Edit Mode.
Next, go to Tools > JGM > Optimize Selected UI GameObjects and press it.
It will automatically optimize the selected game objects (including Prefabs) with the supported techniques.
🛠️ Using more Canvases
Every time a single UI element inside a Canvas changes (e.g. change 1 Text or Image), the whole Canvas has to generate the meshes and draw them all over again (very costly).
🛠️ Separating objects between static and dynamic Canvases
- Static Canvas: contains UI elements that are never going to change; good examples of these are background images, labels, and so on.
- Incidental Dynamic Canvas: contains UI elements that only change in response to something, such as a UI button press or hover action.
- Continuous Dynamic Canvas: contains UI elements that change regularly, such as animated elements.
🛠️ Disabling Raycast Target for non-interactive elements
For all Image components that are not part of a Button, disable the Raycast Target (basically disable it in all images except for buttons).
Each time there is a UI input (click, tap, scroll, etc.) Unity's GraphicsRaycaster iterates over all the Raycast Targets in the scene, so the less we have the more processing we save.
🛠️ Hiding UI elements by disabling the parent Canvas component
To avoid the Canvas regeneration, it's good habit to split the UI into different Canvases, and instead of disabling a LayoutGroup, disable an entire Canvas.
🛠️ Avoiding Animator components
Unity's Animator components are meant for 3D avatar animations primarily. Using it for UI elements causes extra processing.
Instead, the best approach is to use a custom tweening tool such as DOTween.🛠️ Explicitly defining the event camera for World Space Canvases
Always set the Event Camera in a World Space Canvas as if there is no Camera assigned, it will call FindObjectWithTag("Main Camera") on every single frame! ☠️
🛠️ Don't use alpha to hide UI elements
Even though the Image's color property is set to alpha 0, it will still cause a draw call.
Instead, disable the game object itself, or set the alpha of a Canvas Group to 0. This will prevent any draw calls from this object and its childs (0 draw calls).🛠️ Make sure to use a RectMask2D
Like this, any element that is not inside the Scroll Rect, will not be drawn saving plenty of draw calls.
🛠️ Disable Pixel Perfect for ScrollRects
Pixel Perfect makes UI elements appear sharper, but since in a Scroll Rect there's going to be movement, we won't notice it and we'll save a lot of processing.
The Scroll Rect should be on a separate Canvas with this setting off and other UI elements appearing in the same screen, would be in another Canvas with this setting on.
🛠️ Manually stop ScrollRect motion
We can use ScrollRect.StopMovement() to stop the motion once the ScrollRect.velocity is below a certain threshold to reduce regeneration frequency.
🛠️ Using empty UIText elements for full-screen interaction
For a Button that's going to be interactable full-screen, for the Button's Target Graphic, don't use an Image that fills the whole screen and has a color alpha set to 0 (as transparency breaks batching processes).
Instead, for the Button's Target Graphic, use a Text with no Font or Text defined.
🛠️ Reduce Game Objects inside Prefabs
Wherever possible, try to reduce the number of game objects inside of a Prefab, maybe in some occasions it's possible to merge 3 game objects with Images into 1 single game object with 1 Image.
🛠️ Avoid Layout Groups when possible
Whenever possible, try to avoid using Layout Groups, specially nested Layout Groups, as it's very costly performance wise.
🛠️ Adjust texture compression formats
Always adjust texture compression formats for your UI Sprite assets, to reduce memory footprint. Available compression types can be found here.
🛠️ Use Sprite Atlases always
Use Sprite Atlases for grouping single Sprites into one big texture to reduce the number of draw calls.
🛠️ Take order into account to prevent Batch Breaks
Order in UI hierarchies matters. If you have in a hierarchy this order:
- SpriteA1
- SpriteB1
- SpriteA2
- SpriteB2
- SpriteA3
- SpriteB3
(meaning 'A' Sprites are from a specific Sprite Atlas and 'B' Sprite are from another one) it will issue 6 draw calls because the batches are breaking as all Sprites from one Atlas are not consecutively in line. To prevent this Batch Break, order them as in:
- SpriteA1
- SpriteA2
- SpriteA3
- SpriteB1
- SpriteB2
- SpriteB3
As a result, this will only issue 2 draw calls.
✅ Disabling Raycast Target for non-interactive elements
✅ Avoiding Animator components
✅ Make sure to use a RectMask2D
✅ Disable Pixel Perfect for ScrollRects