У VR кадр потрібно рендерити двічі — для лівого та правого ока. На Quest 2 це 72 fps × 2 = 144 Draw Call-пачки в секунду. Якщо ваш проект не пройшов через Single Pass Instanced Rendering і у вас більше 100 batches на кадр, стереоскопічна сцена просто не вкладеться в тайм-слот GPU. Головний біль і нудота у користувачів — прямий наслідок dropped frames. Ми на практиці знаємо, як це виправити: за плечима десятки оптимізованих XR-проектів під різні платформи. Наша спеціалізація — оптимізація графіки під VR/AR пристрої.
AR-проекти на ARCore/ARKit додають поверх цього захват з камери, обробку площин та occlusion mesh. Пристрій вже завантажений CPU-завданнями трекінгу до того, як ваш шейдер зробив перший виклик. Ми допомагаємо вкластися в FPS-бюджет навіть на бюджетних пристроях. Замовте аудит — ми оцінимо ваш проект за 2 дні та надамо план оптимізації з конкретними метриками.
Як оптимізація графіки під VR/AR пристрої вирішує проблему dropped frames?
Ключові техніки — Single Pass Instanced Rendering, Fixed Foveated Rendering, GPU Instancing та оптимізація шейдерів. Single Pass Instanced дозволяє рендерити обидва ока за один прохід, знижуючи кількість Draw Calls вдвічі. Fixed Foveated Rendering зменшує навантаження на GPU на 15–30% без помітного погіршення картинки. GPU Instancing групує однакові об'єкти в один Draw Call. Разом ці методи забезпечують стабільні 72 fps навіть на мобільних XR-пристроях.
Чому стандартні методи оптимізації графіки не працюють в VR/AR?
Зниження полігонажу — це останнє, що ми робимо. Спочатку дивимось на те, що реально вбиває продуктивність на XR-пристроях.
Overdraw в мобільному VR
На Adreno та Mali GPU overdraw коштує непропорційно дорого — тайловий рендер не любить велику кількість напівпрозорих об'єктів. Стандартні партикл-системи з Additive-блендингом на фоні HDR-скайбокса — типовий вбивця frame rate на Quest. Frame Debugger в Unity покаже це миттєво: шукаємо червоні зони в overdraw view.
Неправильне налаштування Fixed Foveated Rendering
Fixed Foveated Rendering на Meta XR SDK знижує навантаження на GPU на 15-30% — але тільки якщо правильно обрано рівень (Low/Medium/High) під конкретний контент. В динамічних сценах зі швидким рухом камери High-рівень дає артефакти на периферії. Рекомендуємо Medium для більшості проектів: він дає до 20% приросту продуктивності без помітних артефактів.
Single Pass Instanced не працює з кастомними шейдерами
Якщо в проекті є хоча б один шейдер без UNITY_VERTEX_INPUT_INSTANCE_ID та UNITY_SETUP_INSTANCE_ID, весь рендер автоматично fallback'ається в Multi Pass. Це подвоює навантаження. Знаходимо через XR Plug-in Management → Rendering Stats. Ми гарантуємо, що після аудиту всі шейдери будуть коректно підтримувати Single Pass Instanced.
Як ми працюємо з XR-проектами
Починаємо з профілювання на цільовому залізі — не в Editor, а на пристрої. RenderDoc для Android, Xcode Instruments для iOS/visionOS, OVR Metrics Tool (частина Meta XR Best Practices Guide). Емулятор не покаже реальних затримок пам'яті та bandwidth.
З нашої практики: кейс клієнта
Проект під Quest 3 — архітектурна візуалізація, 8 кімнат, PBR-матеріали. Перший білд: 45 fps в центрі сцени, 28 fps при погляді у бік вікна. Аналіз через OVR Metrics Tool показав 340 Draw Calls та 4 overdraw-шари на віконних стеклах. Рішення: GPU Instancing для повторюваних меблів (стільці × 24 → 1 Draw Call), заміна стекол з Standard Transparent на кастомний шейдер з Surface Type Opaque + альфа в кліпі, включення Fixed Foveated Rendering рівня Medium. Результат: 72 fps стабільні, thermal throttling зник. Наші клієнти економлять до 30% часу на профілювання завдяки автоматизованим інструментам.
Для AR-проектів окремо опрацьовуємо occlusion — AR Foundation Environment Depth вимагає коректного налаштування глибини в шейдерах, інакше віртуальні об'єкти «просвічують» крізь реальні поверхні.
Інструменти, які ми використовуємо
- Unity Profiler + Frame Debugger (GPU Usage module)
- RenderDoc (Android Vulkan/OpenGL ES)
- Meta Quest Developer Hub + OVR Metrics Tool
- XR Interaction Toolkit Profiling Guidelines
- ARM Mobile Studio (Streamline) для Adreno/Mali deep-dive
Shader Graph оптимізуємо вручну — дивимось на instruction count в Preview вікні, прибираємо зайві sample операції, переносимо обчислення з Fragment в Vertex там, де допустима інтерполяція.
Етапи роботи над оптимізацією XR-графіки
Спочатку збираємо білд в Release-конфігурації та знімаємо baseline-метрики: fps, GPU time per frame, Draw Calls, memory footprint. Без baseline неможливо оцінити результат.
Потім — аудит сцени: ієрархія об'єктів, кількість унікальних матеріалів, налаштування освітлення (статичне/динамічне), наявність real-time тіней (на мобільному VR вони майже завжди під забороною), LOD-групи.
Після аудиту готуємо план оптимізації з пріоритетами за impact/effort. Реалізація йде ітераціями з проміжними вимірами — важливо не втратити baseline та розуміти, що саме дало приріст.
Фінальний етап — теплове тестування на пристрої 20-30 хвилин в умовах нагріву. Thermal throttling на мобільних чипах (Snapdragon XR2) починається раніше, ніж здається.
| Масштаб завдання |
Орієнтовні терміни |
| Аудит + звіт без правок |
2–4 дні |
| Оптимізація однієї сцени (до 500 об'єктів) |
1–2 тижні |
| Повний проект (5–15 сцен, кастомні шейдери) |
3–6 тижнів |
| Портіювання PC VR → standalone Quest |
4–8 тижнів |
Вартість розраховується індивідуально після аудиту проекту та цільової платформи.
Порівняння методів оптимізації
| Метод |
Impact (приріст FPS) |
Effort |
| Fixed Foveated Rendering |
15-30% |
Низький — включення в SDK |
| Single Pass Instanced |
40-50% |
Помірний — правка шейдерів |
| GPU Instancing |
20-60% |
Низький — групування об'єктів |
| Оптимізація текстур (mipmap, стиснення) |
10-20% |
Низький — налаштування імпорту |
Що входить в роботу
- Аудит продуктивності на цільовому пристрої з baseline-метриками
- Оптимізація шейдерів та налаштування рендерингу (Single Pass Instanced, Foveated Rendering)
- Зниження Draw Calls через batching, Instancing, LOD
- Налаштування освітлення та тіней (baked lighting, blob shadows)
- Теплове тестування та фінальний звіт
- Документація щодо використаних технік та рекомендації щодо подальшого розвитку
Часті помилки при підготовці XR-графіки
- Real-time тіні на мобільному VR. Cascaded Shadow Maps з 4 каскадами на Quest — це гарантовані dropped frames. Замінюємо на запечені в Lightmap або Blob Shadow (простий проектор).
- Не вимкнений MSAA вище 4x. На тайлових GPU (Adreno) MSAA 8x ламає продуктивність. В XR Project Settings ставимо 4x максимум, у складних сценах — 2x.
- Текстури без Mipmap. В VR об'єкти можуть бути на різних відстанях від камери одночасно. Без Mipmap GPU бере повну роздільну здатність для далеких об'єктів — bandwidth зростає без причини.
- Physics Colliders складніші за необхідне. Mesh Collider на об'єктах інтер'єру там, де достатньо Box/Capsule. В VR physics tick теж впливає на frame time.
Замовте аудит вашого XR-проекту — ми оцінимо його за 2 дні та надамо план оптимізації з конкретними метриками. Single Pass Instanced ефективніший за Multi Pass вдвічі на однаковій сцені, а оптимізація може скоротити витрати на хмарні інстанси до 2 разів. Отримайте консультацію, щоб дізнатися, як наші рішення підходять вашому проекту.
Типові проблеми продуктивності ігор
Проект запускається на топових девайсах розробника без питань. На mid-range Android п'ятирічної давності — 20 fps і перегрів через 5 хвилин. На iPhone 11 — стабільні 60, але на iPhone XR — просідання у важких сценах. Ми стикаємося з цим кожен день. Оптимізація — не «потім», а архітектурне рішення з першого коміту. За 8 років роботи ми провели оптимізацію більш ніж для 50 ігор — від гіперказуалки до AAA на консолях. Гарантуємо: після нашого аудиту ви отримаєте не просто список проблем, а конкретний план з вимірними цілями та термінами. Замовте аудит продуктивності — оцінимо ваш проект за 3 дні і покажемо, як знизити draw calls на 40% без втрати якості.
Як профілювати продуктивність ігор?
Перш ніж оптимізувати — виміряти. Оптимізація без профілювання — вгадування.
| Інструмент |
Призначення |
| Unity Profiler |
CPU/GPU час по системах, GC allocations, audio |
| Frame Debugger |
Інспекція кожного draw call у кадрі |
| Memory Profiler |
Знімок пам'яті, граф залежностей асетів |
| RenderDoc |
Глибокий аналіз GPU-стану, актуальний для PC/Console |
| Android GPU Inspector |
Профілювання GPU на реальному Android-пристрої |
| Xcode Instruments |
GPU + memory на iOS (Metal Performance HUD) |
| Snapdragon Profiler |
Qualcomm GPU — детальна статистика шейдерів |
Профілюйте на цільовому залізі, а не в редакторі. Editor додає оверхед — цифри з Play Mode не репрезентативні. Розділяйте GPU та CPU bottleneck: на CPU багато draw calls або важка логіка, на GPU — складні шейдери або overdraw. Документація Unity: профілювання на пристрої — обов’язковий крок для мобільних ігор. Типовий час профілювання одного сценарію — 5–8 годин, включаючи збір метрик на 3–5 пристроях різних поколінь. Аналізуємо 10–15 ключових ігрових сценаріїв за 3 робочих дні.
Як зменшити кількість draw calls?
Draw call — команда CPU до GPU «намалюй це». Кожен виклик має overhead незалежно від складності геометрії. На мобільних 200–300 draw calls за кадр — межа. Мета: мінімізувати їх кількість, об’єднуючи геометрію з однаковим матеріалом.
Static Batching об’єднує нерухомі меші при збірці. Вимога: прапорець Static на об’єкті та однаковий матеріал. Ефективний для статичного оточення, але збільшує споживання пам’яті — об’єднаний меш зберігається окремо. Static Batching може знизити draw calls в 3 рази, але збільшує пам’ять на 20% порівняно з іншими методами. У сценах з тисячами статичних об’єктів слідкуйте за пам’яттю через Memory Profiler.
Dynamic Batching об’єднує меші в рантаймі з жорсткими обмеженнями: менше 900 вертексних атрибутів на меш, однаковий матеріал та масштаб. На практиці ефективний лише для дрібних об’єктів (партикли, UI). В URP за замовчуванням вимкнений — його витіснив SRP Batcher.
SRP Batcher — не класичний батчінг, а оптимізація CPU-overhead при підготовці draw calls. Замість того щоб кожен кадр заново завантажувати uniform-дані шейдера, SRP Batcher кешує їх у GPU-пам’яті та оновлює лише ті, що змінилися. Draw calls залишаються колишніми за кількістю, але кожен займає менше часу CPU — SRP Batcher дає приріст в 2–3 рази по CPU-часу рендеру. Вимога: шейдер має бути сумісний з SRP Batcher (декларувати per-object властивості в UnityPerDraw CBUFFER). Стандартні URP Lit/Unlit шейдери сумісні. Кастомні — перевіряємо в Inspector матеріалу: SRP Batcher compatible: Yes/No. Для ввімкнення переконайтеся, що в URP Asset опція SRP Batcher активна, а для кастомних шейдерів використовуйте макрос UNITY_INSTANCING_BUFFER і декларуйте per-object властивості в блоці CBUFFER_START(UnityPerDraw). Після ввімкнення в Profiler має знизитися час RenderLoop.Draw на CPU.
GPU Instancing — для множини копій одного меша з одним матеріалом (дерева, трава, NPC). Відправляє один draw call з масивом per-instance даних. Вмикається на матеріалі: Enable GPU Instancing. Обмеження: всі інстанси в одному batch повинні мати однаковий матеріал і меш. Graphics.DrawMeshInstanced / Graphics.DrawMeshInstancedIndirect — для процедурного рендерингу без GameObject overhead.
Вибір методу залежить від сценарію: Static Batching підходить для статичного оточення, SRP Batcher виграє в проектах з множиною унікальних матеріалів, GPU Instancing незамінний для масових об’єктів (ліс, натовп), Dynamic Batching — лише для дрібних та рідкісних випадків. На практиці ми комбінуємо все, починаючи з профілювання.
| Метод |
Тип об'єктів |
Вплив на CPU |
Вплив на GPU |
Споживання RAM |
| Static Batching |
Статичні |
Помірне зниження |
Без змін |
Збільшується |
| Dynamic Batching |
Дрібні (≤900 вертексів) |
Зниження |
Без змін |
Без змін |
| SRP Batcher |
Будь-які (сумісні шейдери) |
Значне зниження |
Без змін |
Без змін |
| GPU Instancing |
Копії одного меша |
Мінімальне |
Значне зниження |
Незначно |
Детальніше про технологію — на Wikipedia.
Чому оптимізація пам'яті критична для мобільних ігор?
Мобільні платформи — жорсткі обмеження по RAM. iOS вбиває додаток при перевищенні пам’яті без попередження (memory pressure kill). Android — аналогічно, але з onLowMemory callback. Цільові бюджети: iOS — <1 GB для сучасних пристроїв, <512 MB для підтримки iPhone 8/X; Android — <800 MB для широкої сумісності (ОС займає 400–600 MB). Типова економія після нашої оптимізації — 30–50% оперативної пам’яті при збереженні якості. Середня економія бюджету на етапі оптимізації — від $3,000 до $8,000 залежно від складності проекту, що підтверджується нашими кейсами.
Addressables та Asset Bundles: як не перевищити бюджет
Завантажувати все одразу при старті — неприйнятно для великих проектів. Addressables (надбудова над Asset Bundles) — система адресованого асинхронного завантаження асетів. Явне вивантаження: Addressables.ReleaseInstance / Addressables.Release. Addressables не вивантажують асети автоматично при знищенні об’єкта. Типова помилка: Addressables.InstantiateAsync у циклі без Release — пам’ять росте до крашу. Reference counting: асет вивантажується тільки коли всі його handles звільнені. Архітектурний патерн: сервіс/менеджер тримає handle завантаженого асета, звільняє при переході між сценами.
Groups та Bundle Strategy: групуємо асети за логікою завантаження. Наприклад, всі асети одного рівня — в один bundle, шарені (UI, шрифти) — в окрему групу з Prevent Updates. Така стратегія економить до 30% пам’яті.
Texture Memory: звідки береться 70% займаного об'єму
Текстури — основний споживач пам’яті. Аналіз через Memory Profiler: вкладка All Of Memory → Texture2D — одразу видно список найважчих текстур. На практиці ми знаходимо текстури з завищеним Max Size (4096 для мобільної іконки — типова помилка). Заходи: Mipmap для 3D-текстур (ввімкнути), для UI (вимкнути); Streaming Mipmaps для open world — завантажує mip-рівні по мірі наближення камери. Красовська проблема: текстури, на які посилаються невикористовувані Materials, залишаються в пам’яті — Memory Profiler покаже reference chain. Видаляйте зайві матеріали. Після заміни всіх текстур формату RGBA32 на ASTC 6×6 на Android економія досягає 60% без втрати якості.
GC Allocations: як усунути фризи в Hot Path
C# garbage collector в Unity — stop-the-world. Якщо за кадр алоційовано багато heap-пам’яті, GC-пауза викликає видимий фриз. Ціль: нульові алокації в hot path (Update, FixedUpdate, рендер). Типові джерела: string конкатенація в Update (замінюємо на StringBuilder), LINQ в hot path (ручні цикли з предалоційованими списками), GetComponent<T>() кожен кадр (кешуємо в Awake/Start), boxing value types при передачі в object параметри. Після профілювання за допомогою Unity Profiler ми знижуємо алокації в hot path на 95% — фризи зникають.
Як відсікти зайві 40% draw calls? LOD та Culling
LOD Group — перемикання на спрощену геометрію при віддаленні об’єкта від камери. Стандарт для 3D оточення: LOD0 (100%), LOD1 (30–50% трикутників), LOD2 (10–15%), Culled. Для мобільних поріг Culled ставимо агресивніше — менше малюємо за кадр. LOD знижує draw calls на 40–60% залежно від кількості об’єктів.
Occlusion Culling — Unity не рендерить об’єкти за стінами. Вимагає запечені occlusion дані. Для indoor сцен знижує draw calls на 20–40%.
Frustum Culling працює автоматично — об’єкти поза FOV камери не рендеряться. Але draw call на перевірку все одно відбувається. Для сцен з тисячами об’єктів — кастомний spatial partitioning (Quadtree, Octree). В одному з проектів впровадження оклюзійного калінгу та LOD знизило загальну кількість draw calls з 2800 до 450 на Android.
Оптимізація VR: як утримати 72 FPS на Quest 3
VR — окремий клас задач. Фреймрейт 72/90 Hz не можна порушувати, інакше motion sickness. Додатково до стандартних методів: Single Pass Instanced Rendering — рендер для обох очей за один прохід (знижує draw calls в 2 рази); Fixed Foveated Rendering (Quest) — зниження роздільної здатності на периферії; Late Latching (Quest 3) — оновлення позиції контролера максимально пізно перед рендером; Dynamic Resolution в URP/HDRP — автоматичне зниження роздільної здатності рендера при просадці fps. Для Quest профілюємо через OVR Metrics Tool — показує CPU/GPU time прямо в гарнітурі. Після застосування цих методів частота кадрів на Quest 2 стабілізується на 72 FPS навіть у сценах з 1.5 млн полігонів.
Які етапи оптимізації та терміни?
Ми пропонуємо комплексну послугу «під ключ»:
-
Профілювання на цільових пристроях — збір метрик (FPS, draw calls, пам’ять, GC). Аналізуємо 10–15 ключових сценаріїв за 3–5 робочих днів.
-
Звіт з пріоритетами — які проблеми критичні, які можна відкласти. Пріоритети виставляємо на основі впливу на ігровий досвід.
-
Впровадження оптимізацій — батчінг, LOD, Addressables, шейдери, occlusion culling. Середній цикл впровадження — 2–4 тижні.
-
Повторне профілювання — замір покращень. Типовий приріст FPS — 30–60% на мобільних пристроях.
-
Документація — рекомендації по підтримці та подальшій розробці.
-
Навчання команди — як не допустити регресу. Проводимо воркшопи з профілювання та оптимізації.
Завдяки запобіганню переробок на пізніх етапах замовник отримує значну економію. Отримайте консультацію — ми безкоштовно оцінимо ваш проект і покажемо потенціал оптимізації. Звертайтеся, щоб дізнатися точні терміни та вартість для вашого стеку.