Искать

Лучшие советы по оптимизации Unity UI

Last updated: January 2019

What you will get from this page: Tips on how to create optimized UI elements for your content, including dividing up your canvases, avoiding the use of Camera.main and Layout Groups, smart pooling of UI objects and more.

You’ll find many more in this great session by Unity engineer Ian Dundore, Выжимаем все из Unity: советы по увеличению производительности (section on Unity UI starts at 23:38).

Разделяйте холсты

Проблема: изменение одного или нескольких элементов на холсте засоряет весь холст.

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 actually displayed.

Процесс создания объектов может быть затратным с точки зрения ресурсов. Элементы интерфейса лучше собирать в пакеты, чтобы на их отображение требовалось как можно меньше вызовов отрисовки. Генерация пакетов тоже требует ресурсов, поэтому повторное создание элементов без крайней необходимости нежелательно. Проблема заключается в том, что изменение одного или нескольких элементов требует нового анализа всего холста для определения оптимального способа отрисовки элементов.

Многие создают интерфейс всей игры на единственном холсте с тысячей элементов. При таком варианте изменение одного элемента может привести к пиковому потреблению ресурсов процессора на несколько миллисекунд (подробнее о причинах можно узнать на отметке 24:55 доклада Иэна).

Решение: разделите холсты.

Каждый холст будет островом, изолирующим элементы одного холста от другого. Таким образом, разделение холстов — это основной способ решения проблем батчинга элементов интерфейса в Unity.

Кроме того, холсты можно вкладывать один в другой, что позволит создавать сложные интерфейсы, не путаясь при этом между несколькими холстами. Дочерние холсты также позволяют изолировать содержимое как от родительского холста, так и от холстов одного уровня, при этом сохраняется их геометрия и батчинг вызовов.

Разделяя холсты и вкладывая их друг в друга, постарайтесь группировать объекты в порядке их обновления. Например, динамические элементы лучше отделять от статичных (на отметке 29:36 записи Иэн приводит хороший пример разумного разделения холстов).

Оптимальное использование графического рейкастера

Проблема: оптимальное использование графического рейкастера:

Graphic Raycaster — это компонент, посредством которого вы работаете с интерфейсом. Он переводит прикосновения и нажатия в события, а затем рассылает их всем необходимым элементам интерфейса. Этот компонент необходим для всех холстов, где предусмотрено взаимодействие пользователя с интерфейсом, включая дочерние холсты.

Несмотря на свое название, это на самом деле не настоящий рейкастер: по умолчанию он лишь проверяет графические элементы интерфейса. Он берет набор элементов интерфейса на холсте, которые должны управляться пользователем, и отслеживает, над RectTransform какого элемента интерфейса, помеченного на холсте с Graphic Raycaster как интерактивный, пользователь нажал кнопку, клавишу или экран.

Суть в том, что не каждый элемент интерфейса должен обновляться.

Решение: выключите параметр Raycast Target у статических и неинтерактивных элементов.

Рассмотрим текст или кнопку. Выключение параметра Raycast Target непосредственно уменьшит количество проверок пересечений, которые Graphic Raycaster проводит в каждом кадре.

Советы по оптимизации Unity UI

Проблема: в некоторых случаях Graphic Raycaster ведет себя как настоящий рейкастер.

Если задать параметру Render Mode вашего холста значение Worldspace Camera или Screen Space Camera, то ему можно будет задать маску блокирования. Маска блокирования определяет алгоритм построения лучей, будь то в 2D или 3D, для того, чтобы определить, не мешает ли какой-либо физический объект взаимодействию с интерфейсом.

Решение: построение лучей посредством 2D- или 3D-физики может увеличить потребление ресурсов, поэтому используйте эту функцию с умом.

Не забывайте также сократить число графических рейкастеров, выключая их на неинтерактивных холстах интерфейса, поскольку они не требуют отслеживания ввода.

Избегайте использования Camera.main

Проблема: холстам World Space требуется информация о том, на какой камере происходит взаимодействие их содержимого и пользователя.

Настраивая холст для рендеринга в мировом пространстве или в экранном пространстве камеры, можно указать, в какой камере будет происходить генерация событий ввода для графического рейкастера интерфейса. Этот параметр необходим для холстов с экранным пространством камеры (Screen Space - Camera) и называется Render Camera.

Unity UI optimization tips screen space camera

Однако этот параметр не является обязательным для холстов мирового пространства, и в их случае он называется Event Camera.

Unity UI optimization tips world space

Если вы оставите поле параметра Event Camera на холсте World Space пустым, холст не перестанет получать события ввода. События будут приходить от главной камеры игры. Чтобы определить, какая из камер главная, можно проверить атрибут Camera.main.

Unity UI optimization tips camera main property

В зависимости от способа программирования в Unity атрибут Camera.main проверяется 7-10 раз за кадр графическим рейкастером и холстом мирового пространства. А вот сам Camera.main вызывает Object.FindObjectWithTag при каждой проверке, что очевидным образом ухудшает производительность.

Решение: избегайте использования Camera.main.

Кэшируйте ссылки на камеры, создавайте систему отслеживания главной камеры. Если вам нужны холсты World Space, то всегда назначайте Event Camera, не оставляйте это поле пустым! Если нужно изменить атрибут Event Camera, то напишите скрипт, который обновит его.

Избегайте Layout Group там, где это возможно

Проблема: каждый элемент интерфейса, стремящийся отметить свою схему как засоренную, выполняет как минимум один вызов GetComponents.

При изменении одного или нескольких элементов схема засоряется. Дочерние элементы измененного элемента делают родительскую схему (Layout) неактуальной.

Немного о системах Layout: система схем — это набор смежных групп схем, которые находятся непосредственно над элементом схемы (Layout Element). Элемент схемы — это не просто компонент Layout Element: изображения интерфейса, текстовые объекты и полосы прокрутки — это тоже элементы схемы. Кроме того, полосы прокрутки также являются группами схемы.

Вернемся к проблеме: каждый элемент интерфейса, помечающий свою схему как засоренную, выполняет как минимум один вызов GetComponents. Этот вызов ищет действительную группу в родительском элементе схемы. Если таковая находится, то вызов проходит по иерархии компонентов Transform, пока не найдет группы схемы или не достигнет корневого элемента иерархии. Следовательно, каждая группа схемы добавляет по одному вызову GetComponents процессу засорения каждого дочернего элемента схемы, сильно снижая производительность вложенных групп схемы.

Решение: избегайте Layout Group там, где это возможно.

Для пропорциональных схем используйте якори. Если интерфейс имеет множество динамично меняющихся элементов, то рассмотрите вариант написания собственной программы, вычисляющей схемы, и убедитесь, чтобы эта программа выполнялась только по запросу, а не после каждого изменения.

Используйте группировку объектов интерфейса с умом

Проблема: объединение объектов интерфейса снижает производительность.

Часто люди объединяют объекты интерфейса путем восстановления вложенности в пул с последующим отключением, что вызывает излишнюю засоренность.

Решение: сначала объект нужно отключить, а потом вернуть его в пул.

Сначала произойдет засорение старой иерархии, но, вернув объект в пул, вы избежите засорения иерархии во второй раз, причем новая иерархия останется незасоренной. Если вы выводите объект из пула, то сначала восстановите его вложенность, затем обновите данные и только потом включайте.

Как скрыть Canvas

Проблема: как скрыть холст

Иногда возникает необходимость скрыть некоторые холсты и элементы интерфейса. Каков наиболее эффективный способ это сделать?

Решение: выключите сам компонент Canvas

Выключенный компонент Canvas перестанет отправлять вызовы отрисовки на графический процессор и перестанет быть видимым, но при этом сохранится буфер вершин выключенного холста с информацией обо всех мешах и вершинах, и при включении заново не потребуется его перестраивать, достаточно будет просто начать его отрисовку заново.

Кроме того, отключение компонента Canvas не создает ресурсоемких обратных вызовов OnDisable/OnEnable в иерархии холста. При этом не забудьте отключить дочерние компоненты, выполняющие ресурсоемкие задачи в каждом кадре.

Оптимальное использование аниматоров для элементов интерфейса

Проблема: использование аниматоров в интерфейсе

Аниматоры помечают свои элементы как засоренные в каждом кадре, даже если анимация не меняется. Аниматоры не имеют проверки пустых команд.

Решение:

Only put animators on dynamic elements that always change. For elements that rarely change or that only change in response to events, for a short period of time, write your own code or tweening system (there are a number on the Asset Store).

Дополнительные ресурсы

Мы очень хотим знать, нравится ли вам наш контент.

Да, хочу больше Нет, могло быть и лучше
Согласен

Мы используем cookie-файлы, чтобы вам было удобнее работать с нашим веб-сайтом. Чтобы узнать больше, щелкните здесь.