Слишком большое количество draw calls (вызовов отрисовки) может разрушить производительность приложения. Они замедляют анимации, быстрее расходуют заряд батареи и делают интерфейс «тормозным» — особенно на мобильных устройствах. Вот что можно с этим сделать:

  • Объединяйте текстуры и материалы: используйте атласы текстур, чтобы сгруппировать несколько текстур в одну и сократить количество переключений материалов.

  • Оптимизируйте Canvas (канвас): разделяйте статические и динамические элементы интерфейса по разным канвасам, чтобы избежать лишней перерисовки.

  • Батчинг: следите, чтобы элементы UI использовали один и тот же материал, одинаковое значение по оси Z и общие текстуры — это позволит им объединяться в один батч.

  • Сокращайте обновления Canvas: выносите часто меняющиеся элементы — такие как полоски здоровья или таймеры — в отдельный канвас.

  • Используйте инструменты профилирования: анализируйте draw calls с помощью Unity Profiler и Frame Debugger, чтобы находить узкие места.

Небольшой совет: стремитесь удерживать количество draw calls в диапазоне примерно 50–200 для плавной работы, особенно на мобильных устройствах. Используйте панель Stats в Unity, чтобы в реальном времени следить за количеством батчей и вызовов SetPass.

Что такое draw calls в UI Unity

Unity
Unity

Разбор понятия Draw Call

Draw call — это по сути команда, отправляемая на GPU, которая говорит ему, как именно нужно нарисовать конкретные объекты. В неё входят детали о том, какие текстуры, шейдеры и буферы использовать. В документации Unity говорится:

«Чтобы вывести геометрию на экран, Unity отправляет draw calls в графический API. Draw call сообщает графическому API, что именно рисовать и как это делать».

На практике всё устроено не так просто. Сначала CPU должен подготовить ресурсы и управление состояниями перед тем, как GPU вообще начнёт работу. Часто эти подготовительные шаги требуют больше усилий, чем само рисование. Например, каждый раз при смене материала происходит изменение состояния рендера, что добавляет системе дополнительную работу. Чем больше разных материалов используется, тем сложнее становится процесс.

Если вы хотите, чтобы несколько элементов UI объединялись в один draw call (процесс, который называется батчингом), они должны использовать один и тот же материал. Когда используются разные материалы, Unity создаёт отдельный draw call для каждого. Например, плохо оптимизированная таблица в интерфейсе может привести к тому, что для её отображения потребуется до 19 draw calls.

Есть и другие факторы, которые увеличивают количество draw calls. Перекрывающиеся элементы или изображения с альфой, равной 0, по-прежнему участвуют в работе рендера. Кроме того, по умолчанию Unity не упаковывает текстуры UI и спрайтов в атлас, что тоже может приводить к избыточной нагрузке по draw call-ам.

Далее разберёмся, как отслеживать и анализировать эти draw calls в Unity.

Как проверять draw calls в Unity

Чтобы управлять количеством draw calls и оптимизировать их, нужно понимать, как они устроены. В Unity есть встроенные инструменты для анализа производительности, которые сильно упрощают эту задачу. Панель Stats — хорошая отправная точка: она показывает данные в реальном времени для последнего отрисованного кадра. В том числе количество батчей (draw calls) и вызовов SetPass (смен материалов). Вызовы SetPass особенно заметно влияют на производительность.

Включить панель Stats можно в окне Game, пока ваш проект запущен в режиме Play. Для более глубокого анализа незаменим Frame Debugger: он позволяет «поставить на паузу» воспроизведение на конкретном кадре и разобрать отдельные draw calls, чтобы понять, какие элементы UI создают проблемы.

Основные способы сокращения количества draw calls 

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

Батчинг и группировка Canvas

Компонент Canvas в Unity играет ключевую роль в отрисовке элементов UI: он генерирует меши и отправляет draw calls на GPU. Однако у этого подхода есть существенный минус: Unity заново пересчитывает весь Canvas каждый раз, когда меняется любая его часть. Для сложного интерфейса это может серьёзно ударить по производительности.

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

Для эффективного батчинга следите, чтобы элементы UI внутри одного канваса имели одинаковое значение по оси Z, использовали одни и те же материалы и текстуры. Unity применяет методы батчинга в порядке приоритета: сначала SRP Batcher и статический батчинг, затем GPU instancing и, в последнюю очередь, динамический батчинг. Поддержание аккуратной и понятной иерархии UI и отказ от лишней вложенности также помогают сохранять производительность, хотя вложенность при этом остаётся полезным инструментом для логической группировки элементов.

Атлас материалов и текстур

Переключение материалов может заметно увеличить количество draw calls, потому что каждое такое переключение заставляет GPU менять состояние рендера. Использование атласов текстур помогает снизить эту нагрузку: несколько текстур объединяются в одно изображение, и потребность в частой смене текстур уменьшается. Например, применение атласов спрайтов в некоторых случаях позволяет сократить количество draw calls с 58 до всего лишь 5.

При создании атласов спрайтов придерживайтесь размеров, кратных степени двойки: 512×512, 1024×1024 или 2048×2048. Такие размеры улучшают сжатие текстур и позволяют эффективно использовать мип-карты. Старайтесь группировать в одном атласе логически связанные текстуры и избегать смешивания несвязанных ассетов — это может излишне раздувать размер текстуры и снижать пользу от оптимизации. Дополнительно атласы спрайтов упрощают работу с материалами, уменьшив количество уникальных материалов в проекте. Для процедурного контента можно рассмотреть динамические атласы текстур, которые подгружаются на разных этапах работы приложения.

Сокращение обновлений Canvas 

Обновления Canvas могут быть ресурсоёмкими, особенно если элементы UI часто меняются. Чтобы уменьшить нагрузку, выносите компоненты, которые обновляются чаще всего — например, полоски здоровья, счётчики очков или уведомления — в отдельные канвасы. В этом случае Unity будет перерисовывать только те части интерфейса, которые действительно меняются, оставляя статичные элементы нетронутыми.

Ещё один способ улучшить производительность — минимизировать анимации и эффекты, которые заставляют Canvas постоянно обновляться. Для более эффективной работы используйте анимационную систему Unity или оптимизированные библиотеки твининга, либо вынесите чисто декоративные анимации в отдельные канвасы. Кроме того, применение объектного пула для элементов, которые часто создаются и уничтожаются — таких, как индикаторы урона или всплывающие подсказки, — помогает сократить количество дорогих перестроек Canvas. Группировка динамических элементов в под-Canvas в зависимости от частоты обновления ещё сильнее упрощает и ускоряет работу интерфейса.

Пошаговое руководство по устранению проблем с draw calls в Unity UI

Опираясь на описанные выше приёмы оптимизации, вот практическое руководство, которое поможет найти, исправить и убедиться, что проблемы с draw calls в Unity устранены.

Найдите проблемные области с помощью профилирования

Начните с открытия Unity Profiler и переключения на модуль Rendering. Обратите внимание на количество батчей, вызовов SetPass, треугольников и вершин — их аномально высокие значения могут указывать на узкие места по производительности. Для более детального анализа используйте Frame Debugger: он позволяет поставить воспроизведение на паузу на конкретном кадре и разобрать отдельные draw calls. Помните, что профилирование в режиме Editor отражает работу внутри редактора Unity, а режим Player даёт более точную картину, так как анализирует собранную сборку игры. Чтобы точнее локализовать пики нагрузки, используйте Profiler Markers для пометки нужных участков кода.

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

После того как вы нашли проблемные места, перестройте структуру интерфейса. Разделите статические и динамические UI-элементы, разместив их на разных канвасах. Убедитесь, что все элементы внутри одного канваса используют одинаковое значение по оси Z, одни и те же материалы и текстуры — это необходимо для батчинга. Отключайте компоненты Graphic Raycaster на тех канвасах, где не требуется взаимодействие с пользователем, а также снимайте флаг «Raycast Target» у статичных или неинтерактивных элементов UI.

Как уже обсуждалось выше, объединение материалов и текстур — ключ к эффективному батчингу. Используйте Sprite Atlas в Unity, чтобы собрать несколько мелких текстур в одну большую. Например, в платформере можно создать атлас, куда войдут все текстуры платформ — это существенно снизит количество draw calls.

Старайтесь не создавать лишние уровни наложения UI-элементов. Если сложное наслаивание всё-таки необходимо, рассмотрите вариант слияния перекрывающихся элементов во время выполнения, чтобы уменьшить число батчей. Для анимированных элементов интерфейса используйте анимации, задаваемые кодом, или твининговые библиотеки вместо Animator, особенно если элементы редко меняют своё состояние. При использовании пула объектов для UI убедитесь, что вы отключаете объект перед сменой родителя в иерархии — так вы избежите дополнительных перестроек Canvas.

Результаты тестирования с помощью инструментов профилирования

После проведения оптимизаций измерьте их влияние на FPS, загрузку CPU и GPU. Используйте время кадра в миллисекундах, чтобы убедиться, что игра укладывается в целевой «бюджет кадра». Для большинства игр целевым значением считают 60 FPS, тогда как VR-приложениям для поддержания эффекта присутствия обычно требуется не менее 90 FPS.

Инструмент Profile Analyzer особенно полезен для сравнения профайлов «до» и «после» изменений, наглядно показывая, насколько выросла производительность. Всегда тестируйте на целевых устройствах, так как поведение игры может сильно отличаться в зависимости от железа. Проводите профилирование регулярно на протяжении всего цикла разработки, чтобы сформировать базовый «профиль производительности» проекта. Начинайте с выключенного Deep Profiling, так как он сам по себе замедляет выполнение, и включайте его только тогда, когда нужны более детальные данные. Если после оптимизации draw calls игра укладывается в бюджет по кадру, имеет смысл подключить Memory Profiler, чтобы найти другие потенциальные узкие места. Для более глубокого анализа, завязанного на конкретное железо, комбинируйте встроенные профайлеры Unity с инструментами профилирования, доступными на целевых платформах. Такой многоуровневый подход помогает убедиться, что оптимизации действительно работают на разных устройствах и платформах.

Сравнение методов оптимизации draw calls

Понимание и сравнение различных методов оптимизации draw calls помогает добиться лучшей производительности UI в Unity.

Сравнительная таблица

Выбор подходящей техники оптимизации зависит от структуры вашего интерфейса, типа контента и целевых показателей по производительности. Ниже приведён обзор основных методов:

Техника

Лучший сценарий применения

Влияние на производительность

Возможные недостатки

Батчинг и группировка Canvas

Сложные интерфейсы с частыми обновлениями

Сокращает количество перестроек Canvas и draw calls

Требует внимательного проектирования иерархии UI

Атласирование материалов и текстур

Сцены с большим разнообразием текстур

Снижает количество переключений текстур и draw calls

Увеличивает использование памяти под текстуры и требует управления атласами

Сокращение обновлений Canvas

Интерфейсы с анимациями или динамическим контентом

Ограничивает количество лишних перестроек Canvas

Может потребовать изменений в коде или альтернативных подходов к анимации

Статический батчинг

Неподвижные, статичные элементы

Существенно снижает количество draw calls

Увеличивает потребление памяти и не подходит для динамических объектов

Динамический батчинг

Небольшие однотипные объекты

Автоматически сокращает количество draw calls

Ограничен по количеству вершин и требует использования схожих материалов

GPU instancing (инстансинг на GPU) 

Множество одинаковых объектов

Сильно уменьшает количество draw calls и нагрузку на CPU

Требует шейдеров с поддержкой instancing и даёт меньше гибкости для индивидуальных настроек объектов

Эта таблица служит быстрым справочником, который помогает взвесить сильные и слабые стороны каждого метода. Ниже мы подробнее разберём ключевые аспекты этих техник.

Канвас-батчинг сосредоточен на группировке похожих элементов UI, чтобы минимизировать накладные расходы на рендеринг. Этот подход довольно эффективен, но хуже работает с динамическим контентом, который часто меняется. Атласирование материалов и текстур, напротив, снижает нагрузку от переключения текстур за счёт объединения их в один атлас. Однако такой подход увеличивает использование памяти под текстуры и требует аккуратного управления самим атласом.

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

Статический батчинг отлично подходит для неподвижных объектов, объединяя их в меньшее число draw calls, но он неприменим к динамическим элементам. Динамический батчинг, в свою очередь, автоматически группирует небольшие однотипные объекты, чтобы уменьшить количество draw calls, однако имеет ограничения — по количеству вершин и по единообразию материалов. GPU instancing особенно эффективен, когда нужно отрисовать большое количество идентичных объектов: он заметно снижает нагрузку на CPU, но требует шейдеров с поддержкой instancing и даёт меньше свободы в индивидуальной настройке каждого объекта.

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

Заключение

Оптимизация draw calls в UI Unity критически важна для обеспечения плавной работы на мобильных устройствах, а это напрямую влияет на вовлечённость пользователей. Поскольку draw calls могут быть ресурсоёмкими — часто нагружая CPU на этапе подготовки сильнее, чем сама отрисовка, — их сокращение становится ключевым шагом на пути к созданию эффективных и отзывчивых приложений.

Помимо чисто технического аспекта, оптимизация draw calls даёт и стратегические преимущества. Она помогает повысить частоту кадров, снизить энергопотребление и упростить будущие обновления. В обратную сторону, игнорирование оптимизации ведёт к заметным проблемам: ускоренному разряду батареи и «тормозящему» интерфейсу — а это отталкивает пользователей и снижает удержание.

Применяя описанные техники, разработчики могут создавать приложения, которые не только работают быстрее, но и стимулируют более длительные сессии использования, в итоге повышая удовлетворённость и лояльность аудитории.

FAQs

Как использовать инструменты Unity, чтобы найти и исправить проблемы с draw calls?

Чтобы разобраться с проблемами, связанными с draw call в Unity, начните с Unity Profiler. Этот инструмент даёт ключевые данные о производительности рендеринга, включая метрики вроде количества draw calls, батчей и вызовов SetPass. Эти показатели помогают локализовать области, где требуется оптимизация, особенно если вы сталкиваетесь с избыточным количеством draw call или неэффективным батчингом.

Далее перейдите к Frame Debugger, чтобы детально разобрать каждый кадр. Он показывает, как обрабатываются draw calls, и выявляет проблемы с производительностью — например, сломанный батчинг или лишние вызовы SetPass. Имея такую подробную картину, вы можете точечно вносить изменения, повышать производительность проекта и снижать лаги.

С какими сложностями связана работа с атласами текстур в Unity и как их решать?

Использование атласов текстур в Unity может заметно ускорить работу, но вместе с тем приносит свои проблемы. Одна из ключевых — нагрузка на память GPU. Слишком большие атласы могут приводить к просадкам производительности, таким как промахи кэша, если их размер выходит за оптимальные рамки для рендеринга. Например, очень большие текстуры (вроде 8192×8192) могут просто не поддерживаться на некоторых устройствах. Кроме того, они могут вызывать неэффективный выбор мип-уровней, особенно если на экране используется только небольшая часть атласа. Ещё одна распространённая проблема — видимые швы на нормал-картах, особенно в случае с тайлинговых текстурами.

Чтобы справиться с этими сложностями, имеет смысл использовать несколько более мелких, специализированных под задачу атласов — так легче управлять памятью и улучшать работу мип-карт. Полезным приёмом также является texture streaming, когда загружаются только те части текстуры, которые действительно нужны в данный момент. Кроме того, важно подбирать размер атласа с учётом возможностей целевой платформы и аккуратно настраивать параметры сжатия, чтобы найти баланс между производительностью и качеством картинки.

Почему разделение статических и динамических UI-элементов по разным канвасам улучшает производительность в Unity?

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

Отделяя статические элементы (которые не меняются) от динамических (которые обновляются часто), вы снижаете нагрузку на CPU, уменьшаете количество draw calls и помогаете удерживать стабильную частоту кадров. Такой подход особенно полезен для сложных интерфейсов, где статичные визуальные элементы сочетаются с интерактивными компонентами.


Если хочется разбираться в Unity не только на уровне профайлера, но и собрать игру от прототипа до релиза, обратите внимание на курс «Unity Game Developer. Basic». Он закрывает базовый стек Unity и C#, работу с игровыми уровнями, интерфейсом и оптимизацией, а итогом станет собственная игра, подготовленная к публикации в сторе.

Для знакомства с форматом обучения и экспертами приходите на бесплатные демо-уроки:

  • 2 декабря: «Как создать свою первую игру на Unity за 2 часа». Записаться

  • 9 декабря: «Как использовать AI себе на пользу в Unity разработке». Записаться

Комментарии (0)