Продолжаем оптимизировать мобильные игры на Unity. Используем профайлер, а также смотрим, куда лезть не стоит

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

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

Также поговорим, на что не стоит обращать внимания в небольших проектах, чтобы не тратить лишнее время ради пары процентов производительности.

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

1. Профайлер

Встроенный в Unity профайлер я всегда использую как стартовую точку. Здесь все интуитивно, даже если пользуешься им первый раз, поэтому игнорировать его точно не стоит. Он наглядно показывает части кода, которые тормозят.

Проблемы обычно возникают, когда код писал кто-то другой — тут придется разобраться, что он делает и как это исправить.

Если профайлер Unity не дал однозначных ответов, переходим к нативным профайлерам — Android Studio или Xcode, в зависимости от платформы.

В более сложных, непонятных ситуациях переходим на специализированные, например, Snapdragon Profiler, Arm Mobile Studio и так далее, в зависимости от девайсов под рукой. Функционал у таких профайлеров плюс-минус одинаковый, просто они под разное «железо».

2. Баннерная реклама

Не так давно был случай, когда я использовал профайлер не совсем корректно. По запросу от команды проводился анализ игры. Вводная была такая: стабильно низкий FPS. И так как речь шла о нем, я проводил замеры не со старта игры, а через некоторое время, и внимательно изучал проект на «плато». Я заметил несколько проблем и почти два дня составлял рекомендации по оптимизации. Выписал огромное количестве рецептов, но по итогу производительность выросла на 10%, что очень мало.

Дальнейший анализ показал, что проблема на самом деле существовала первые 15-20 секунд после старта игры из-за загрузки баннерной рекламы. Как только баннер прогружался — лаги прекращались.

Баннер — это, по сути, браузер, запущенный внутри игры. А браузер довольно тяжелое приложение, которое используется просто, чтобы показать маленькую картинку или анимацию. Пока он загружается, игра может лагать. Такой подход используют абсолютное большинство рекламных сетей. Поэтому, если бы кто-то захотел избавиться от проблемы, то ему бы пришлось написать свой плагин и создать свою компанию, которая продает рекламу.

Поэтому выходов из такой ситуации всего два:

  1. Выключить баннерную рекламу на слабых устройствах и потерять часть монетизации.
  2. Смириться с некоторыми лагами первые 30 секунд (в идеале попытаться как-то это замаскировать), пока баннер загружается.

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

3. Отсечение того, что за кадром

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

Если же уровень большой и объектов действительно много, не забывайте отключать все, что не видно. Например, у анимированных объектов (CullingMode) есть три опции:

  • анимировать всегда (AlwaysAnimate);
  • анимировать, только когда игрок их видит (CullCompletely);
  • анимировать только физику, если ты их не видишь (AnimatePhysics).

По дефолту в Unity стоит «анимировать всегда», поэтому в большинстве случаев эту галочку нужно отключать. 

4. 3D-модели и текстуры

Для небольших проектов этот пункт не особо актуален. Ситуации встречаются двух типов:

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

5. Организация проекта

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

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

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

Пример оптимизации мидкор-проекта

Теперь рассмотрим конкретный кейс из прошлого с примерами советов по оптимизации одного проекта.

Это была мидкорная игра с кораблями на 10 игроков. Но ее проблема заключалась в том, что на средних по производительности устройствах FPS падал до 5 кадров в секунду. И причин тому нашлось несколько.

Скиннинг моделей 

Непомерно много на проекте отнимал скиннинг 3D-моделей — парусов и моряков на палубе было очень много. Unity умеет делать скиннинг на GPU для ускорения, но даже это не всегда помогает, особенно на слабых устройствах где и так GPU очень слаб.

В данном кейсе скиннинг занимал 60 миллисекунд, и уже это приводило к ограничению в 12 FPS, без учёта рендера кадра и прочего.

Что делать?

  • Для начала стоит на всех аниматорах, которые не влияют на симуляцию, а только визуальны, поставить CullingMode на CullCompletely (см. раздел №3 выше). И хорошо бы ещё и на определённом расстоянии от камеры их тоже выключать, даже если видно.
  • Уменьшить количество скин мешей в принципе.
  • Уменьшить количество костей на вершину, иногда сделать на каждый треугольник по одной-две кости, если это не очень критично влияет на визуальную красоту.
  • Уменьшить количество вершин на моделях.
  • Можно переделать анимации и так далее (например, уменьшить количество костей).

Очистка буфера кадра

При рендрере первой камеры (или на старте рендера через SRP) нужно чистить весь буфер кадра, а не только Z и стенсил. Если что-то забыть — ломается маркер начала кадра, что на мобильных GPU критично и некоторые вещи, которые сделаны на аппаратном уровне, могут отрабатывать не так, как ожидается.

Форматы текстур

Хорошие и модные форматы текстур могут не поддерживаться конкретными устройствами. В таких случаях Unity показывает, что они должны весить, например, 0.7 Мб, а на девайсе по факту выходит 2.7 Мб.

Дело в том, что если какой-то оригинальный формат текстур не поддерживается на конкретном девайсе, то Unity распаковывает его в другой формат и использует в несжатом виде. Получается, что текстуры должны весить мало (как показывает Unity), а на самом девайсе они весят в несколько раз больше. Всё потому, что встроенный профайлер показывает только расчетный размер текстуры, если на телефоне будет поддерживаться такой формат.

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

Аллокации

Большое количество аллокаций (выделений памяти).

Обычно считается, сколько делается аллокаций на один кадр. И если их там больше, условно, чем 5-10 Кб на один кадр, то стоит задуматься над поиском и ликвидацией этих мест.

В итоге

Добились 20-30 FPS на слабых устройствах, вместо изначальных 5.

Вернуться в блог