Оптимизация графики под мобильные платформы
На Android mid-range устройстве 2023 года GPU Profiler показывает 18 мс на кадр при целевых 16.6 мс — игра не держит 60 FPS. Причина, как правило, не одна: 340 draw calls, несколько overdraw-тяжёлых эффектов, непожатые текстуры 2048×2048 на объектах, которые занимают 64×64 пикселя на экране. Каждый из этих пунктов в отдельности некритичен. Вместе — катастрофа.
Draw Calls: где они берутся и как их считать
Draw Call — это команда CPU отрисовать группу треугольников с определёнными настройками. Каждый draw call требует синхронизации CPU-GPU и передачи данных. На мобильных устройствах с tile-based GPU (PowerVR, Mali, Adreno) это дороже, чем на десктопных immediate mode GPU.
Инструменты: Unity Profiler (GPU Usage), Frame Debugger, и — для детального анализа — RenderDoc на Android или Xcode Instruments на iOS. GPU Profiler прямо в редакторе показывает количество batch'ей и SetPass calls. Хорошая цель для мобильного проекта — до 100 draw calls на кадр, реалистичная для mid-core — 150–200.
Основные источники лишних draw calls:
Материалы без батчинга. Static Batching объединяет статические объекты с одинаковым материалом в один mesh при старте сцены. Условие: объекты должны быть помечены Static в Inspector и использовать одинаковый Material. Один ассет материала, не одинаковые настройки — именно одинаковый объект в памяти. Если у двух объектов Material с идентичными параметрами, но это разные Material Instance — батчинг не работает.
Dynamic Batching для мелких объектов (до 900 вертексов) работает автоматически, если объекты используют одинаковый материал. Но на практике Dynamic Batching часто отключают ради GPU Instancing — инстансинг масштабируется лучше при большом количестве копий одного объекта (деревья, камни, враги одного типа).
Canvas Overlay режим в uGUI. Canvas в Screen Space - Overlay рендерится поверх всего, и каждое изменение в любом UI-элементе (даже мигание курсора в текстовом поле) помечает весь Canvas Dirty, пересчитывает mesh и делает отдельный draw call. Для UI с анимированными элементами обязательно разносить статичные и динамические элементы по разным Canvas'ам.
Текстуры: самый недооценённый источник проблем с памятью
Мобильные устройства используют Unified Memory Architecture: GPU и CPU делят одну память. 512 MB RAM — не редкость для бюджетных Android-устройств в 2023–2024. Некомпрессированная RGBA32 текстура 2048×2048 = 16 MB. 10 таких текстур на уровне = 160 MB только на текстурах.
Форматы сжатия с аппаратной поддержкой:
- Android: ETC2 (без альфы — 4 bpp, с альфой — 8 bpp), ASTC 4×4 (8 bpp) или ASTC 6×6 (3.5 bpp)
- iOS: ASTC 4×4 – ASTC 8×8 в зависимости от требований к качеству
- PC: DXT5 (BC3) для RGBA, BC7 для высококачественных текстур
ASTC — лучший вариант для iOS и современных Android (Adreno 400+ серии, Mali G7x и выше). На старых Android устройствах с OpenGL ES 2.0 ASTC не поддерживается — нужен ETC2 fallback. Unity позволяет задать разные форматы для разных платформ через Texture Importer.
Мипмапы — обязательны для 3D-объектов, не нужны для UI. Мипмап добавляет 33% к размеру текстуры в памяти, но для UI-элементов, которые всегда рендерятся в нативном разрешении, это бесполезный расход. Проверяем через Texture Importer → Generate Mipmaps → отключить для всех UI-спрайтов.
Кейс: снижение памяти с 380 до 140 MB
На проекте — мобильная 3D стратегия — при запуске кампании игра падала с OOM (Out of Memory) на устройствах с 512 MB RAM. Memory Profiler показал 380 MB только на текстурах.
Аудит: 60% текстурного бюджета занимали текстуры terrain и environment в формате RGBA32 без сжатия — разработчик отключил сжатие на этапе прототипирования «для скорости», и забыл вернуть. Ещё 15% — UI-текстуры с включёнными мипмапами.
Решение: перевод всех terrain/environment текстур в ASTC 6×6 (основная целевая платформа — iOS, Android 7.0+ как минимальный требуемый), UI-текстуры в ASTC 8×8 без мипмапов. Для эффектов с альфой (партиклы, VFX) — ASTC 4×4. Итог: 142 MB. OOM-крэши прекратились, освободилось 240 MB для игровой логики и звука.
Шейдеры и Overdraw
Overdraw — это рендеринг одного пикселя несколько раз. Полупрозрачные партикулы, сложные постпроцессинговые эффекты, перекрывающиеся UI-элементы — всё это overdraw. На tile-based мобильных GPU overdraw особенно дорог: каждый раз, когда тайл памяти читается и записывается повторно, это дополнительная работа.
Визуализировать overdraw в Unity: Scene View → Render Mode → Overdraw. Белые пятна = проблема. Особенно следим за particle systems — партиклы часто рендерят десятки полупрозрачных квадов поверх друг друга в одной точке.
Для партикульных систем: ограничивать Max Particles, использовать непрозрачные или cutout шейдеры где это визуально допустимо (cutout дороже прозрачного по fill rate, но дешевле по overdraw в глубину), сортировать партиклы по Sorting Layer чтобы минимизировать пересечение с геометрией.
Для шейдеров: простые Unlit шейдеры в 3–5 раз дешевле Lit на мобильных устройствах. Для декораций дальнего плана, теней на земле, billboard-объектов Unlit достаточен. Lit шейдер с per-pixel lighting только для ближнего плана и ключевых объектов.
Профилирование: инструменты в порядке использования
Начинаем с Unity Profiler подключённым к устройству через USB (Build → Development Build + Autoconnect Profiler). GPU Usage Profiler показывает время рендера по категориям. Frame Debugger — детальный разбор draw calls. Memory Profiler — снимок памяти с разбивкой по категориям.
Для Android дополнительно: Android GPU Inspector (AGI) для устройств с Adreno, Mali Performance Counters для Mali GPU. Они показывают fill rate utilization, texture bandwidth и cache hit rate — метрики, недоступные в Unity Profiler.
| Задача | Сроки |
|---|---|
| Аудит производительности + отчёт с рекомендациями | 2–5 дней |
| Оптимизация текстур и материалов (одна сцена) | 3–7 дней |
| Комплексная оптимизация графики (весь проект) | 2–6 недель |
| Оптимизация под конкретное минимальное устройство | 1–3 недели |
Стоимость определяется после аудита проекта и анализа текущих метрик производительности.





