Оптимізація Draw Calls мобільної гри
Draw Call — це команда CPU до GPU: «нарисуй вот цей меш з цим матеріалом». На мобільних GPU з тайловою архітектурою (Mali, Adreno, Apple GPU) зайві Draw Calls дорожче, ніж на десктопе. На Adreno 618 переход від 300 до 150 Draw Calls у кадрі може дати прирост з 45 до 60 FPS без єдиної зміни у шейдерах.
Звідки беруться зайві вислови
Три головні джерела.
Різні матеріали на подібних об'єктах. Кожен унікальний матеріал = мінімум один окремий Draw Call. Часто бачу проекти, де у монет, врагів та бонусів — різні текстури (PNG різних розмірів), упаковані у різні атласи, з різними матеріалами. Batch для них неможливий.
Dynamic batching ломається незабачено. Unity батчит меші лише якщо вони менше 900 вершин, використовують один матеріал та не мають статичного флага. Додавання тені (Shadow Casting = On) до динамічного об'єкта автоматично виключає його з батча — це не очевидно з документації.
Skinned mesh без GPU instancing. Анімовані персонажі з SkinnedMeshRenderer не беруть участь ні в static batching, ні в dynamic batching. Якщо на екрані 20 врагів з одним і тим же мешем, але без GPU Instancing — 20 окремих Draw Calls.
Інструменти діагностики
Unity Frame Debugger (Window → Analysis → Frame Debugger) — перший крок. Показує кожен Draw Call у кадрі з поясненням, чому батчинг не відбувся (Why This Draw Call Can't Be Batched).
Snapdragon Profiler (для Android на Adreno) та Xcode GPU Frame Capture (iOS) дають більш детальну картину на реальному залізі, включаючи час per draw call.
RenderDoc — для глибокого аналізу, якщо Frame Debugger не дає відповіді.
Що робимо
Sprite Atlas для 2D
Для 2D-ігор — SpriteAtlas (не застарілий Sprite Packer). Всі спрайти одного ігрового шару — в один атлас, один матеріал, один Draw Call для всього шару. Важливо: атлас повинен бути Include in Build, інакше у рантаймі підгружаються окремі текстури.
Максимальний розмір атласу на мобільних — 2048×2048 для більшості пристроїв, 4096×4096 допускається для Android API 26+ та iOS 12+. Використовуємо ASTC 6×6 для обох: хороша компресія без помітних артефактів на ігрових спрайтах.
GPU Instancing для 3D
Для повторюючихся об'єктів (враги, дерева, кулі) — Enable Instancing на матеріалі + переконатися, що шейдер підтримує #pragma multi_compile_instancing. З Unity 2022+ можна використовувати BatchRendererGroup для повного контролю.
GPU Instancing не працює з анімацією на CPU. Для анімованих врагів — або GPU skinning через AnimationInstancing (asset), або вертексні шейдери з запечуваними анімаціями у текстурі (Texture-based animation).
Static Batching
Статичні об'єкти (платформи, стіни, декорації) — позначаємо як Static, включаємо Static Batching у Player Settings. Unity об'єднає меші при сборці. Overhead: збільшення розміру пам'яті (меші дублюються), тому не позначаємо статикою все підряд.
Видаляємо зайві Shadow Casters
Тені — дорого. На мобільних часто виключають real-time тіні повністю та замінюють blob shadow (простий dark circle спрайт під об'єктом). Якщо тіні потрібні — обмежуємо дистанцію та переходимо на одну каскадну карту тіней замість чотирьох.
Цільові метрики
| Пристрій | Рекомендований максимум Draw Calls |
|---|---|
| Low-end Android (Adreno 505) | 80–120 |
| Mid-range Android (Adreno 618) | 150–200 |
| iPhone 12 / A14 | 200–300 |
| iPhone 15 / A17 | 300–400 |
Ці цифри — для 60 FPS. Якщо таргет 30 FPS, бюджет вдвоє м'якший.
Процес роботи
Аудит поточного Frame Debugger → категоризація Draw Calls по причинах → пріоритизація по вкладу в GPU time → реалізація атласів/instancing/batching → валідація на Low-end пристрої.
Терміни залежать від масштабу гри: простий 2D-аркада — два-три дні, 3D з анімованими персонажами — тиждень і більше.







