Оптимізація текстурних атласів: де просідає кадр
Сцена мобільної гри зростає ітераціями: спочатку десяток об'єктів на рівні, потім сотня, і бюджет часу кадру непомітно перестає сходитися.
Просідання кадрів на слабких пристроях і довге завантаження рівня майже ніколи не пов'язані зі сценаріями чи логікою — у проєктах, які ми розбирали, причина частіше в тому, як зібрано текстурний атлас мобільної гри.
Типова помилка — один великий лист на всю категорію ресурсів: інтерфейс, оточення й ефекти лежать разом, і рушій піднімає в пам'ять увесь лист заради двох-трьох потрібних елементів.
Паралельно зростає обсяг збірки: частина листа не стискається, частина каналів залишається без втрат, а декодування великого зображення займає помітну частку часу старту рівня.
Окремо б'є неакуратний формат: елементи без відступу по краях, різні канали прозорості в одному листі, змішування ресурсів із різною потрібною деталізацією.
На слабких пристроях це дає рвані краї та повторне вивантаження-завантаження листа там, де вистачило б підвантаження одного фрагмента. Оптимізація текстурних атласів починається не з пакування, а з профілю: що і коли реально потрапляє на екран.
Ми знімаємо цей профіль на цільових пристроях, потім ріжемо листи за сценами й групами видимості, підбираємо формат стиснення під вміст листа й додаємо міп-рівні там, де об'єкт іде в глибину кадру.
Збірку збираємо в тому ж порядку, що й у вас, — пакувальник на кшталт TexturePacker підключається як крок автоматизації, щоб ручна правка листів не поверталася в проєкт. Розбираємо, як це закривається.
Що дає перепакування атласів мобільної сцени
Правильно зібраний атлас насамперед скорочує обсяг ресурсів збірки: повторювані елементи та дрібні зображення укладаються в спільні листи, дублікати й зайві поля по краях зникають.
З постачання зникає помітна частка вихідних даних, а разом із нею — час на їх розпакування та перевірку цілісності під час першого запуску.
Час завантаження сцени скорочується завдяки двом ефектам: менше файлів потрібно відкрити й прочитати, менше даних декодується під час переходів між екранами.
На середньому пристрої різниця помітна користувачеві — екран готовності не тримає його зайві секунди, а фонове підвантаження наступних сцен не конкурує з рендерингом поточної.
Витрати пам'яті на пристрої падають передбачувано: один великий лист замість десятків дрібних знижує накладні витрати на зберігання й перемикання, а єдиний формат зберігання прибирає постійні звільнення та повторні завантаження.
Це той запас, який залишається під графіку на бюджетних моделях і визначає, чи доживе сцена до кінця без примусового вивантаження.
Стабільність кадрів зростає напряму: чим менше перемикань матеріалів на кадр, тим рівніший час рендерингу й рідші просідання на піках. Відмови через нестачу пам'яті, які зазвичай спливають на довгих сесіях, зникають разом із дробленням ресурсів на безліч дрібних файлів.
Підсумок перевіряється за чотирма вимірюваними ознаками: вага збірки стала меншою, сцена вантажиться швидше, пам'ять витрачається ощадніше, кадри йдуть рівно без провалів.
Якщо хоч один пункт не зрушив, перепакування атласів варто перезібрати заново — за вимірами, а не за відчуттями.
Режими пакування та стиснення: порівняння підходів
Ресурси мобільної гри впираються в два обмеження: обсяг відеопам'яті та кількість перемикань матеріалів на кадр. Режим пакування й стиснення вибирають не «на смак», а під вміст атласу — градієнти, дрібні іконки інтерфейсу та повноекранні фони поводяться по-різному.
Стиснення без втрат зберігає кожен піксель, але в пам'яті така текстура все одно розгортається повністю — виграш залишається тільки в розмірі збірки.
Блокове стиснення з втратами (ASTC) тримає дані стиснутими прямо в пам'яті прискорювача: обсяг і пропускна здатність падають, але з'являються артефакти на тонких лініях і градієнтах.
| Варіант | Коли підходить | Обмеження |
|---|---|---|
| Без втрат | Інтерфейс, шрифти, маски, прев'ю | У пам'яті розгортається повністю, відеопам'ять не економить |
| Блокове з втратами | Великі фони, карти матеріалів | Артефакти на градієнтах, вимоги до кратності блоку |
| Розбиття на сторінки | Атлас не вміщається в ліміт пристрою | Більше перемикань матеріалів на кадр |
| Щільне пакування з ротацією | Різнорідні спрайти, чітка сітка | Ротація ламає дев'ятисегментні елементи та шейдери |
Щільність пакування конфліктує з розбиттям на сторінки. Чим щільніший атлас, тим менше сторінок і перемикань, але ротація спрайтів ламає дев'ятисегментні елементи та шейдери, залежні від координат. Розбиття, навпаки, спрощує підтримку артів, але додає перемикань на кадр.
Тому ми не фіксуємо один режим: інтерфейс і шрифти йдуть без втрат, великі фони — блоковим стисненням, переповнені атласи діляться за частотою спільного використання. Профіль закріплюється в скрипті збірки, і новий арт не ламає розкладку.
Порядок робіт: від вимірювання до передавання проєкту
Атлас перепаковуємо не «на око», а за результатами вимірювання: спочатку знімаємо профіль на цільових пристроях і знаходимо, що саме впирається — заповнення текстурного блоку, обсяг займаної відеопам'яті, кількість викликів рендерингу або час завантаження сцени.
Далі йде послідовність кроків, де кожне рішення спирається на дані попереднього, а не на звичку розробника.
- Вимірювання вузьких місць. Профілюємо проблемні сцени й меню на репрезентативній вибірці пристроїв — від слабких до топових. Фіксуємо базові метрики: час кадру, споживання пам'яті, тривалість завантаження, кількість перемикань матеріалу.
- Схема розбиття атласу. Групуємо спрайти за частотою спільної появи в кадрі та за спільним матеріалом, рахуємо бюджет площі й запас на технологічний відступ між елементами, щоб не ловити «протікання» країв на міп-рівнях.
- Перепакування та перезбирання. Збираємо атласи за затвердженою схемою, приводимо розміри до зручних для стиснення значень, оновлюємо прив'язки в ресурсах і перевіряємо, що збірка проходить без ручних правок.
- Перевірка на цільових пристроях. Прогоняємо ті самі сцени повторно та звіряємо метрики з базовими: дивимося, чи зникло вузьке місце і чи не з'явилося нове — наприклад, зростання часу завантаження через дроблення файлів.
- Стабілізація та регрес. Фіксуємо еталонні вимірювання й додаємо автоперевірку схеми пакування, щоб наступна порція графіки не зламала досягнутий результат.
- Передавання проєкту команді. Віддаємо схему розбиття, скрипти перепакування, регламент додавання нових ресурсів і коротку інструкцію для художників — далі команда замовника веде пакування сама, без нас.
Кожен етап закінчується артефактом: вимірювання, схема, оновлені атласи, звіт за пристроями, регламент. Так результат відтворюваний, а не тримається на одному інженері.
Артефакти: схеми розбиття, профілі пам'яті, регламенти
Після робіт у команди замовника залишається не звіт, а робочий комплект: за ним новий інженер відтворює збірку атласів і отримує той самий результат без звернення до нас.
Кожен документ прив'язаний до конкретного кроку конвеєра ресурсів, тому розбіжність між «як домовилися» і «як збирається» видно одразу — на етапі перевірки, а не на пристрої гравця.
- Схема розбиття ресурсів — які групи зображень зводяться в один атлас, за якою ознакою (частота одночасного показу, спільний матеріал, екран), які залишаються окремими файлами. Із зазначенням граничного розміру листа та правил добирання вільного місця.
- Профіль пам'яті застосунку — вимірювання споживання на цільових пристроях до і після правок, розбиті за сценами: завантаження, бій, інтерфейс, тривала сесія. Слугує еталоном для порівняння під час наступних релізів.
- Правила іменування ресурсів — єдиний шаблон для зображень, атласів і похідних файлів, щоб збирач автоматично знаходив залежності, а пошук потрібного листа не перетворювався на перебір директорій.
- Регламент ревізій графіки — хто і коли переглядає склад атласів, що вважається підставою для перезбирання (новий набір контенту, зростання споживання, скарги на підвантаження), як фіксується результат.
- Документація зі збирання ресурсів — порядок кроків, склад інструментів і точки контролю з перевірками: незаповнені області, дублі, ресурси поза схемою. Нова людина проходить шлях від вихідних файлів до готового набору без усних пояснень.
- Карта володіння — які файли й налаштування закріплені за конкретними ролями, що змінюється тільки через ревізію, а що можна правити локально.
Комплект передаємо у вигляді, придатному для правок: схеми й правила лежать поруч із проєктом і версіонуються разом із ним, а не в листуванні. Через кілька релізів команда повертається до документів, а не до нас — це і є критерій, що роботу виконано.
Кейс: прибрали просідання на слабких пристроях
Що було до робіт
До нас прийшов проєкт, де графіка зростала швидше, ніж її встигали приводити до ладу: кожен новий екран тягнув власний набір текстур, частина зображень дублювалася одразу в кількох атласах, а рідкісні асети лежали в спільному пулі й вантажилися завжди.
На нижній межі підтримуваних пристроїв це давало просідання в бою та на переходах між сценами — пам'ять упиралася в стелю, а підвантаження йшло саме в момент дії гравця.
Що змінили
Перезібрали атласи за фактичною спільною появою: ресурси одного екрана — в один набір, рідкісні винесли окремо з довантаженням на вимогу.
Дублікати замінили посиланнями на спільне джерело, кількість кадрів в анімаціях обмежили, формати стиснення підібрали під те, що пристрій декодує апаратно.
- прибрали перетини атласів між екранами;
- перевикористовувані елементи винесли в спільний пул замість копій;
- рідкісні сцени перевели на асинхронне довантаження з передзавантаженням у паузах;
- кеш прогріли на старті, щоб перший вхід у бій не збирав ресурси.
Як виміряли результат
Рахували за фактом, а не на око: проєкт на Unity віддає покадровий профіль, і ми спиралися на нього. Перевіряли не на топових моделях, а на нижній межі списку підтримки — тих пристроях, що реально приносять інсталяції.
Один і той самий набір сцен до і після: обсяг збірки зменшився приблизно на третину, завантаження рівня стало вдвічі швидшим, просідання на слабких пристроях зникли, пам'ять перестала впиратися в стелю.
Що робити, якщо застосунок уже випущено й оновлюється?
Випущений застосунок оновлюється у своєму ритмі, і зупиняти релізи заради перепакування графіки ніхто не буде. Оптимізація текстурних атласів вбудовується в поточний цикл: одна хвиля — один екран або локація. Кожен крок при цьому зобов'язаний бути відкатним, інакше ризик під час оновлення переважує виграш.
Ключова умова — зворотна сумісність ресурсів. Старі збірки на пристроях продовжують читати попередні листи, нові — уже перепаковані: імена слотів і ключі доступу до кадрів зберігаються, змінюється тільки розкладка.
Попередній набір залишається в дистрибутиві до моменту, коли частка гравців на застарілих версіях падає до знехтуваної.
Плавний перехід будується на вимірюваннях, а не на вірі у виграш. На кожній хвилі порівнюємо зайняту відеопам'ять, час завантаження рівня та частоту підвантажень під час гри. Якщо ефект не підтверджується на матриці пристроїв, хвиля в реліз не йде — правки чекають у гілці.
Ризики відомі й закриваються заздалегідь: артефакти на краях листів під час фільтрації та переходу між рівнями деталізації, втрачені посилання після видалення старих кадрів, зростання розміру збірки в перехідний період. Повернення до попередньої схеми робимо прапорцем конфігурації, без аварійного оновлення.
Так оптимізація йде паралельно випуску версій, а не замість нього: кожна хвиля дає вимірюваний зріз за пам'яттю та завантаженням, а узгоджений вигляд і поведінка гри для гравця залишаються незмінними.
Фільтрація, прозорість, пам'ять: часті питання
Такі питання зазвичай спливають уже на дзвінку, коли чорновий атлас зібрано й видно, де він просідає. Нижче — короткі відповіді на те, що найчастіше викликає сумніви в команди замовника.
Загальний принцип один: рішення щодо атласу ухвалюється за вимірюваннями — займана пам'ять, час підготовки сцени, кількість перемикань текстур за кадр. Без цих чисел суперечка про кайму чи якість стиснення залишається справою смаку.
По краях елементів з'являється кайма — це лікується?
Так, це найчастіший артефакт, і причина технічна: фільтрація захоплює пікселі сусіднього елемента. Закривається запасом у 2–4 пікселі по краю, куди дублюються крайні пікселі, і коректно зібраними зменшеними копіями листа — інакше кайма проявиться на далеких рівнях деталізації.
Чи можна тримати напівпрозорі елементи в спільному атласі?
Можна, але із застереженнями: критичні порядок змішування та спосіб зберігання прозорості. Якщо напівпрозорий елемент лежить в одному листі з непрозорими, він змішується з чужими пікселями й дає темний ореол — такі елементи виносимо в окремий лист або окремий шар рендерингу.
Чому після розбиття атласу пам'ять зросла?
Тому що кожен лист — окрема текстура зі своїм мінімальним розміром, запасом по краях і своїми зменшеними копіями. Дробимо не «за папками», а за форматом стиснення та частотою використання елементів: рідкісні елементи їдуть в окремий лист, який вантажиться на вимогу.
Як переконатися, що стиснення не вбило якість?
Порівнюємо стиснений лист з еталоном без стиснення, дивимося відхилення за каналами, а очима — на градієнтах, тонких лініях і дрібному тексті. Елементи, чутливі до втрати деталей, тримаємо на окремому листі з щаднішим режимом.
З чого починати, якщо застосунок просто «гальмує»?
З вимірювання. Знімаємо обсяг завантажуваних текстур, їхню кількість і час підготовки сцени, потім дивимося, що змінюється під час переходу між екранами. Найчастіше вузьке місце — не геометрія, а обсяг текстур і зайві перемикання матеріалів у кадрі.
Обговоримо задачу: вимірювання сцени, план робіт, оцінка
Оптимізація текстурних атласів починається не з правок, а з вимірювання сцени: без цифр будь-яка зміна перетворюється на вгадування. Щоб повернутися з оцінкою строків і робочим планом, а не із загальними рекомендаціями, нам потрібні стартові дані проєкту.
- поточна збірка гри або доступ до репозиторію — знімок реального стану, а не переказ;
- перелік сцен, де видно просідання: завантаження рівня, бій, екран магазину, інвентар;
- статистика за пам'яттю та часом рендерингу, якщо команда її вже збирає;
- список атласів із розмірами й правилами пакування: які набори спрайтів до якого екрана належать;
- обмеження щодо цільових пристроїв і мінімальної підтримуваної версії системи;
- дані аналітики падінь і відгуків — де частіше скаржаться на підгальмовування та нагрівання корпусу.
За цими даними ми збираємо план робіт з оптимізації: черговість атласів, що перепаковуємо, що дробимо за екранами, що вивантажуємо з пам'яті між сценами. До плану додаємо оцінку строків за етапами — так ви бачите, на якому кроці з'являється вимірюваний результат.
Порядок початку робіт: обговорюємо задачу, узгоджуємо обсяг першого етапу й точки контролю, після чого фіксуємо план і стартуємо. Опишіть задачу та надішліть те, що вже є, — повернемося з планом робіт і оцінкою.







