
Это третья статья в серии, которая раскрывает советы по оптимизации для ваших проектов в Unity. Используйте их в качестве руководства для работы на более высоких частотах кадров с меньшими ресурсами. После того как вы попробуете эти лучшие практики, обязательно ознакомьтесь с другими страницами в серии:
Смотрите наши последние руководства по оптимизации для разработчиков и художников Unity 6:
Поймите ограничения вашего целевого оборудования и как профилировать GPU для оптимизации рендеринга вашей графики. Попробуйте эти советы и лучшие практики, чтобы уменьшить нагрузку на GPU.
При профилировании полезно начать с эталона, чтобы понять, какие результаты профилирования вы должны ожидать от конкретных GPU.
Смотрите GFXBench для отличного списка различных эталонов отраслевого стандарта для GPU и графических карт. Сайт предоставляет хороший обзор текущих доступных GPU и как они сравниваются друг с другом.
Смотрите статистику рендеринга
Нажмите кнопку Stats в правом верхнем углу окна игры. Это окно показывает вам информацию о рендеринге в реальном времени о вашем приложении во время режима игры. Используйте эти данные для оптимизации производительности:
- fps: Кадры в секунду
- CPU Main: Общее время обработки одного кадра (и обновления редактора для всех окон)
- CPU Render: Общее время рендеринга одного кадра игрового вида
- Batches: Группы вызовов отрисовки, которые будут отрисованы вместе
- Tris (треугольники) и Verts (вершины): Геометрия сетки
- SetPass calls: Количество раз, когда Unity должна переключать проходы шейдеров для отрисовки объектов на экране; каждый проход может ввести дополнительную нагрузку на ЦП.
Примечание. FPS в редакторе не обязательно переводится в производительность сборки. Мы рекомендуем профилировать вашу сборку для наиболее точных результатов. Время кадра в миллисекундах является более точным показателем, чем кадры в секунду при бенчмаркинге. Узнайте больше в электронной книге Ультимативное руководство по профилированию игр на Unity (издание Unity 6).

Чтобы отрисовать GameObject, Unity отправляет вызов отрисовки в графический API (например, OpenGL, Vulkan или Direct3D). Каждый вызов отрисовки требует много ресурсов. Изменения состояния между вызовами отрисовки, такие как переключение материалов, могут вызвать нагрузку на ЦП.
Аппаратное обеспечение ПК и консолей может обрабатывать много вызовов отрисовки, но нагрузка от каждого вызова все еще достаточно высока, чтобы попытаться их уменьшить. На мобильных устройствах оптимизация вызовов отрисовки имеет решающее значение. Вы можете достичь этого с помощью пакетирования вызовов отрисовки.
Пакетирование вызовов отрисовки минимизирует эти изменения состояния и снижает затраты ЦП на отрисовку объектов. Unity может объединять несколько объектов в меньшее количество пакетов, используя несколько техник:
- Пакетирование SRP: Если вы используете HDRP или URP, включите пакетировщик SRP в вашем активе Pipeline в разделе Дополнительно. При использовании совместимых шейдеров пакетировщик SRP уменьшает настройку GPU между вызовами отрисовки и делает данные материалов постоянными в памяти GPU. Это может значительно ускорить время отрисовки на ЦП. Используйте меньше вариантов шейдеров с минимальным количеством ключевых слов для улучшения пакетирования SRP. Обратитесь к этой документации SRP, чтобы узнать, как ваш проект может воспользоваться этим рабочим процессом отрисовки.
- Инстансирование GPU: Если у вас есть большое количество идентичных объектов (например, здания, деревья, трава и так далее с одинаковой сеткой и материалом), используйте инстансирование GPU. Эта техника объединяет их с помощью графического оборудования. Чтобы включить инстансирование GPU, выберите ваш материал в окне проекта и в инспекторе отметьте Включить инстансирование.
- Статическое пакетирование: Для неподвижной геометрии Unity может уменьшить количество вызовов отрисовки для любых сеток, использующих один и тот же материал. Это более эффективно, чем динамическое пакетирование, но использует больше памяти. Отметьте все сетки, которые никогда не движутся, как Пакетирование Статическое в инспекторе. Unity объединяет все статические сетки в одну большую сетку во время сборки. StaticBatchingUtility также позволяет вам создавать эти статические пакеты самостоятельно во время выполнения (например, после генерации процедурного уровня неподвижных частей).
- Динамическое пакетирование: Для небольших мешей Unity может группировать и преобразовывать вершины на ЦП, а затем рисовать их все за один раз. Примечание. Не используйте это, если у вас нет достаточного количества низкополигональных мешей (не более 300 вершин каждый и 900 общих атрибутов вершин). В противном случае включение этой функции потратит время ЦП на поиск небольших мешей для пакетирования.
Вы можете максимизировать пакетирование, следуя нескольким простым правилам:
- Используйте как можно меньше текстур в сцене. Меньшее количество текстур требует меньше уникальных материалов, что упрощает их пакетирование. Кроме того, используйте текстурные атласы, где это возможно.
- Всегда запекайте световые карты в максимально возможном размере атласа. Меньшее количество световых карт требует меньше изменений состояния материалов, но следите за объемом памяти.
- Будьте осторожны, чтобы случайно не создавать экземпляры материалов. Доступ к Renderer.material в скриптах дублирует материал и возвращает ссылку на новую копию. Это нарушает любое существующее пакетирование, которое уже включает материал. Если вы хотите получить доступ к материалу пакетированного объекта, используйте Renderer.sharedMaterial вместо этого.
- Следите за количеством статических и динамических пакетов по сравнению с общим количеством вызовов отрисовки, используя Профайлер или статистику отрисовки во время оптимизации.
Пожалуйста, обратитесь к документации по пакетированию вызовов отрисовки для получения дополнительной информации.

Отладчик кадров позволяет вам заморозить воспроизведение на одном кадре и пошагово просмотреть, как Unity строит сцену, чтобы выявить возможности для оптимизации. Ищите объекты GameObjects, которые отрисовываются без необходимости, и отключайте их, чтобы уменьшить количество вызовов отрисовки на кадр.
Примечание: Отладчик кадров не показывает отдельные вызовы отрисовки или изменения состояния. Только нативные профайлеры GPU предоставляют вам подробную информацию о вызовах отрисовки и времени. Тем не менее, отладчик кадров все еще может быть очень полезен при отладке проблем с конвейером или пакетными проблемами.
Одно из преимуществ отладчика кадров Unity заключается в том, что вы можете связать вызов отрисовки с конкретным объектом GameObject в сцене. Это упрощает исследование определенных проблем, которые могут быть невозможны в внешних отладчиках кадров.
Для получения дополнительной информации прочитайте документацию по отладчику кадров и посмотрите раздел

Частота заполнения относится к количеству пикселей, которые GPU может отрисовать на экране каждую секунду.
Если ваша игра ограничена частотой заполнения, это означает, что она пытается отрисовать больше пикселей за кадр, чем может обработать GPU.
Отрисовка на одном и том же пикселе несколько раз называется избыточной отрисовкой. Избыточная отрисовка снижает частоту заполнения и требует дополнительной пропускной способности памяти. Наиболее распространенные причины избыточной отрисовки:
- Наложение непрозрачной или прозрачной геометрии
- Сложные шейдеры, часто с несколькими проходами отрисовки
- Неоптимизированные частицы
- Наложение элементов пользовательского интерфейса
Хотя вы хотите минимизировать его влияние, нет универсального подхода к решению проблем с избыточной отрисовкой. Начните с экспериментов с вышеуказанными факторами, чтобы уменьшить их влияние.
Как и на других платформах, оптимизация на консоли часто означает сокращение пакетов вызовов отрисовки. Существует несколько техник, которые могут помочь.
- Используйте отсечение окклюзии, чтобы удалить объекты, скрытые за объектами переднего плана, и уменьшить избыточную отрисовку. Имейте в виду, что это требует дополнительной обработки ЦП, поэтому используйте Профайлер, чтобы убедиться, что перенос работы с ГП на ЦП полезен.
- Инстансирование GPU также может уменьшить ваши пакеты, если у вас много объектов, которые используют одну и ту же сетку и материал. Ограничение количества моделей в вашей сцене может улучшить производительность. Если это сделано искусно, вы можете создать сложную сцену, не делая ее повторяющейся.
- Система SRP Batcher может уменьшить настройку ГП между DrawCalls, объединяя команды Bind и Draw GPU. Чтобы воспользоваться этой пакетной обработкой SRP, используйте столько материалов, сколько необходимо, но ограничьте их небольшим количеством совместимых шейдеров (например, Lit и Unlit шейдеры в URP и HDRP).
Окклюзия отключает GameObjects, которые полностью скрыты (окклюдированы) другими GameObjects. Это предотвращает использование времени ЦП и ГП для рендеринга объектов, которые никогда не будут видны Камере.
Окклюзия происходит для каждой камеры. Это может значительно повлиять на производительность, особенно когда несколько камер включены одновременно. Unity использует два типа окклюзии: окклюзия фрустра и окклюзия объектов.
Окклюзия фрустра выполняется автоматически на каждой Камере. Это предотвращает рендеринг GameObjects, которые находятся за пределами Объема видимости, что помогает оптимизировать производительность.
Вы можете установить дистанции окклюзии по слоям вручную через Camera.layerCullDistances. Это позволяет вам окклюдировать небольшие GameObjects на расстоянии, меньшем, чем стандартный farClipPlane.
Организуйте GameObjects по слоям. Используйте массив layerCullDistances, чтобы назначить каждому из 32 слоев значение меньше farClipPlane (или используйте 0, чтобы по умолчанию использовать farClipPlane).
Unity сначала окклюдирует по слоям, оставляя только GameObjects на слоях, которые использует Камера. После этого окклюзия фрустра удаляет любые GameObjects за пределами фрустра камеры. Окклюзия фрустра выполняется в виде серии заданий, чтобы воспользоваться доступными рабочими потоками.
Каждый тест отсечения слоя очень быстр (по сути, это просто операция с битовой маской). Тем не менее, эта стоимость все равно может накапливаться при очень большом количестве объектов GameObjects. Если это станет проблемой для вашего проекта, вам может понадобиться реализовать какую-то систему для деления вашего мира на "секторы" и отключения секторов, которые находятся за пределами фрустума камеры, чтобы снизить нагрузку на систему отсечения слоев/фрустума Unity.
Occlusion culling удаляет любые объекты GameObjects из игрового вида, если камера не может их видеть. Используйте эту функцию, чтобы предотвратить рендеринг объектов, скрытых за другими объектами, так как они все равно могут рендериться и потреблять ресурсы. Например, рендеринг другой комнаты не нужен, если дверь закрыта и камера не может видеть в комнату.
Включение отсечения окклюзии может значительно увеличить производительность, но также может потребовать больше места на диске, времени ЦП и ОЗУ. Unity создает данные окклюзии во время сборки, а затем необходимо загрузить их с диска в ОЗУ во время загрузки сцены.
Хотя отсечение фрустума за пределами вида камеры является автоматическим, отсечение окклюзии — это запеченный процесс. Просто отметьте ваши объекты как Static.Occluders или Occludees, затем запеките через диалог Window > Rendering > Occlusion Culling.
Посмотрите учебник Working with Occlusion Culling для получения дополнительной информации.

Allow Dynamic Resolution — это настройка камеры, которая позволяет вам динамически изменять масштаб отдельных целевых рендеров, чтобы уменьшить нагрузку на GPU. В случаях, когда частота кадров приложения снижается, вы можете постепенно уменьшать разрешение, чтобы поддерживать стабильную частоту кадров.
Unity запускает это масштабирование, если данные о производительности указывают на то, что частота кадров собирается снизиться из-за привязки к GPU. Вы также можете заранее запустить это масштабирование вручную с помощью скрипта. Это полезно, если вы приближаетесь к ресурсоемкому участку приложения. Если масштабировать постепенно, динамическое разрешение может быть почти незаметным.
Обратитесь к странице руководства dynamic resolution для получения дополнительной информации и списка поддерживаемых платформ.
Иногда вам может понадобиться рендерить с более чем одной точки зрения во время вашей игры. Например, в игре FPS обычно оружие игрока и окружение рисуются отдельно с разными углами обзора (FOV). Это предотвращает искажение объектов на переднем плане при просмотре через широкий угол обзора фона.
Вы можете использовать Camera Stacking в URP для рендеринга более чем одного вида камеры. Тем не менее, для каждой камеры все еще выполняется значительное отсечение и рендеринг. Каждая камера требует некоторой вычислительной мощности, независимо от того, выполняет ли она значимую работу или нет. Используйте только компоненты камеры, необходимые для рендеринга. На мобильных платформах каждая активная камера может использовать до 1 мс времени ЦП, даже когда ничего не рендерит.

В URP, вместо использования нескольких камер, попробуйте пользовательскую Render Objects Renderer Feature. Выберите Add Renderer Feature в активе Renderer Data. Выберите Render Object.
При переопределении каждого Render Object вы можете:
- Связать его с событием и внедрить в конкретный момент цикла рендеринга
- Фильтровать по Render Queue (Прозрачный или Непрозрачный) и LayerMask
- Влиять на настройки Depth и Stencil
- Изменить настройки камеры (угол обзора и смещение позиции)

В HDRP вы можете использовать пользовательские проходы для аналогичного эффекта. Настройка Custom Pass с использованием Custom Pass Volume аналогична использованию HDRP Volume.
Пользовательский проход позволяет вам:
- Изменить внешний вид материалов в вашей сцене
- Изменить порядок, в котором Unity рендерит объекты
- Считывать буферы камеры в шейдеры
Использование Объемов пользовательских проходов в HDRP может помочь вам избежать использования дополнительных камер и связанных с ними накладных расходов. Пользовательские проходы имеют дополнительную гибкость в том, как они могут взаимодействовать с шейдерами. Вы также можете расширить Класс пользовательского прохода с помощью C#.

Когда объекты перемещаются на расстояние, Уровень детализации (LOD) может регулировать или переключать их на использование моделей с более низким разрешением и более простыми материалами и шейдерами. Это усиливает производительность GPU.
Смотрите курс Работа с LOD на Unity Learn для получения дополнительных деталей.

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

Тесселяция делит формы на меньшие версии этой формы. Это может улучшить детали за счет увеличенной геометрии. Хотя есть примеры, когда тесселяция имеет смысл, например, для реалистичной коры деревьев, в общем, избегайте тесселяции на консолях. Они могут быть дорогими для GPU.
Как и шейдеры тесселяции, геометрические и вершинные шейдеры могут выполняться дважды за кадр на GPU – один раз во время предварительного прохода глубины и снова во время прохода теней.
Если вы хотите генерировать или изменять данные вершин на GPU, вычислительный шейдер часто является лучшим выбором, чем геометрический шейдер. Выполнение работы в вычислительном шейдере означает, что шейдер вершин, который фактически отображает геометрию, может быть сравнительно быстрым и простым.
Узнайте больше о основных концепциях шейдеров.
Когда вы отправляете вызов отрисовки на GPU, эта работа делится на множество волновых фронтов, которые Unity распределяет по доступным SIMD в GPU.
Каждый SIMD имеет максимальное количество волновых фронтов, которые могут работать одновременно. Заполнение волновых фронтов относится к тому, сколько волновых фронтов в настоящее время используется относительно максимума. Это измеряет, насколько хорошо вы используете потенциал GPU. Специфические для консоли инструменты анализа производительности показывают заполнение волновых фронтов в больших деталях.
В приведенном ниже примере волновые фронты шейдера вершин отображаются зеленым цветом. Волновые фронты шейдера пикселей отображаются синим цветом. На нижнем графике много волновых фронтов шейдера вершин появляются без значительной активности шейдера пикселей. Это показывает недоиспользование потенциала GPU.
Если вы выполняете много работы шейдера вершин, которая не приводит к пикселям, это может указывать на неэффективность. Хотя низкое заполнение волновых фронтов не обязательно плохо, это метрика, с которой стоит начать оптимизацию ваших шейдеров и проверку других узких мест. Например, если у вас есть задержка из-за операций с памятью или вычислениями, увеличение заполнения может помочь производительности. С другой стороны, слишком много волновых фронтов в полете может вызвать сбой кэша и уменьшить производительность.

Если у вас есть интервалы, когда вы недоиспользуете GPU, асинхронные вычисления позволяют вам перемещать полезную работу вычислительного шейдера параллельно с вашей графической очередью. Это лучше использует эти ресурсы GPU.
Например, во время генерации теневых карт GPU выполняет только рендеринг глубины. В этот момент происходит очень мало работы шейдера пикселей, и многие волновые фронты остаются незанятыми.
Если вы можете синхронизировать некоторую работу шейдера вычислений с рендерингом только глубины, это обеспечивает лучшее общее использование GPU. Неиспользуемые волновые фронты могут помочь с окклюзией в пространстве экрана или любой задачей, которая дополняет текущую работу.
Посмотрите эту сессию на Оптимизация производительности для высококлассных консолей от Unite.

GPU Resident Drawer (доступен как для URP, так и для HDRP) — это система рендеринга, управляемая GPU, предназначенная для оптимизации времени CPU, предлагающая значительные преимущества в производительности. Она поддерживает кроссплатформенный рендеринг и разработана для работы из коробки с существующими проектами.
Система может быть включена в активе Render Pipeline HDRP или URP. Выберите Инстансированный рендеринг, чтобы включить его. Вы также можете выбрать, хотите ли вы включить его только в режиме игры или в режиме редактирования тоже.
Когда вы включаете GPU Resident Drawer, игры, которые зависят от CPU из-за большого количества вызовов отрисовки, могут улучшить производительность, так как количество вызовов отрисовки уменьшается. Улучшения, которые вы увидите, зависят от масштаба ваших сцен и количества инстансирования, которое вы используете. Чем больше объектов, которые можно инстансировать, вы рендерите, тем больше преимуществ вы увидите.
При выборе опции Инстансированный рендеринг вы можете получить сообщение в интерфейсе, предупреждающее вас о том, что «Настройка BatchRenderGroup Variants должна быть 'Keep All'». Настройка этой опции в графических настройках завершает настройку для GPU Resident Drawer.
Чтобы узнать больше, ознакомьтесь с нашей дискуссионной темой здесь.

GPU occlusion culling, доступный как для URP, так и для HDRP, работает в тандеме с GPU Resident Drawer. Он значительно увеличивает производительность, уменьшая количество перерисовок для каждого кадра, что означает, что рендерер не тратит ресурсы на отрисовку невидимых объектов.
Чтобы активировать GPU occlusion culling, найдите актив рендер-пайплайна и переключите флажок GPU Occlusion.
Чтобы включить GPU Occlusion Culling в режиме отладки в Unity 6, перейдите в Window > Rendering > Occlusion Culling. Здесь вы можете визуализировать, как объекты отсекаются, переключая различные параметры визуализации.


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