Як ми вирішуємо великі вимоги до відеопам'яті у 2D грі?


40

Як ми вирішуємо великі вимоги до відеопам'яті у 2D грі?


Ми розробляємо 2D гру (Factorio) в алегро C / C ++, і ми зіткнулися з проблемою із збільшенням вимог до відеопам'яті, оскільки вміст гри збільшується.

Наразі ми збираємо всю інформацію про зображення, які будуть використані спочатку, обрізаємо всі ці зображення якомога більше і впорядковуємо їх у великі атласи якомога щільніше. Ці атласи зберігаються у відеопам'яті, розмір якої залежить від системних обмежень; В даний час це, як правило, 2 зображення розміром до 8192x8192, тому для них потрібно від 256 Мб до 512 Мб відеопам'яті.

Ця система працює для нас досить добре, так як за допомогою деяких спеціальних оптимізацій та розділення потоку візуалізації та оновлення ми можемо намалювати десятки тисяч зображень на екрані за 60 кадрів в секунду; у нас на екрані багато об'єктів, і дозволити велике зменшення масштабу - важлива вимога. Як ми хотіли б додати більше, виникають певні проблеми з вимогами до відеопам'яті, тому ця система, можливо, не може працювати.

Одна з речей, яку ми хотіли спробувати, - це мати один атлас з найпоширенішими зображеннями, а другий - кеш-пам'ять. Зображення будуть переміщені туди з растрового зображення пам'яті на вимогу. З цим підходом є дві проблеми:

  1. Малюнок з растрового зображення пам'яті на відео растрове зображення болісно повільний, в алегро.
  2. Не можна працювати з відео растровим зображенням, крім основного потоку, в алегро, тому він практично непридатний.

Ось деякі додаткові вимоги, які ми маємо:

  • Гра повинна бути детермінованою, тому питання про продуктивність та час завантаження ніколи не можуть змінити стан гри.
  • Гра в реальному часі, і незабаром також буде багатокористувацькою. Нам потрібно уникати навіть найменшого заїкання будь-якою ціною.
  • Більшість гри - це один безперервний відкритий світ.

Тест складався з малювання 10 000 спрайтів у партії розмірами від 1х1 до 300х300, кілька разів для кожної конфігурації. Я робив тести на Nvidia Geforce GTX 760.

  • Відео-растрове зображення для малювання растрового зображення відео займало 0,1 мс на спрайт, коли вихідний растровий файл не змінювався між окремими растровими зображеннями (варіант атласу); розмір не мав значення
  • Відео растрове зображення для графічного растрового відео, тоді як вихідне растрове зображення перемикалось між малюнками (не атласний варіант), займало 0,56 у.о. за спрайт; розмір не мав значення.
  • Растрова пам'ять для малювання растрових відео дійсно була підозрілою. Розміри від 1x1 до 200x200 займали 0,3us за растрову карту, так що не так жахливо повільно. Для більших розмірів час почав дуже різко збільшуватися - у 9us за 201x201 до 3116us за 291x291.

Використання атласу збільшує продуктивність на коефіцієнт, більший за 5. Якщо для рендерінгу у мене було 10 мс, то в атласі я обмежений 100 000 спрайтів на кадр, а без нього - обмеження в 20 000 спрайтів. Це було б проблематично.

Я також намагався знайти спосіб тестування растрової карти та формату біт-мапи 1bpp для тіней, але мені не вдалося знайти спосіб зробити це в allegro.


1
Великий шанувальник вашої гри, я підтримав кампанію Indiegogo. Я розпиваюся на ньому кожні кілька місяців. Приємної роботи поки! Я видалив питання, "які технології використовувати", які є поза темою для сайту. Решта питань все ще досить широкі, якщо у вас є щось більш конкретне, вам слід спробувати звузити сферу застосування.
MichaelHouse

Дякую за підтримку. То де ж де запитати, яку технологію тоді використовувати? Я не шукаю відповіді з конкретними рекомендаціями щодо двигунів, але мені не вдалося знайти поглиблене порівняння 2d двигунів, а інспектування їх вручну по одному, включаючи тести на продуктивність та зручність, зайняло б віки.
Марвін

Ознайомтесь із нижньою частиною цієї сторінки, де можна задати питання на кшталт "який технологій використовувати". У вас є абсолютно вагомим і обґрунтованим питанням, це просто не той тип питань, яким ми займаємося на цьому сайті. Незважаючи на те, що ви не шукаєте конкретного двигуна, це дійсно єдиний спосіб відповісти на питання "Чи є якась технологія, яка робить X?". Хтось міг просто відповісти «так» і не дати рекомендації щодо конкретного, але це не буде дуже корисно. Удачі вам!
MichaelHouse

2
Ви стискаєте свої текстури?
GuyRT

3
@Marwin, стислі текстури можуть працювати набагато краще, ніж нестиснені текстури, оскільки вони зменшують необхідну пропускну здатність пам'яті (це особливо стосується мобільних платформ, де пропускна здатність значно нижча). Ви можете заощадити величезну кількість пам’яті, просто стискаючи текстури. Дійсно, єдиний недолік - це неминуче представлені артефакти.
GuyRT

Відповіді:


17

У нас є аналогічний випадок з нашою RTS (KaM Remake). Усі одиниці та будинки - спрати. У нас є 18 000 спрайтів для одиниць, будинків і рельєфу, а також ще ~ 6 000 для командних кольорів (застосовується як маски). Довго розтягнуті ми також маємо близько 30 000 символів, що використовуються у шрифтах.

Отже, є кілька оптимізацій щодо атласів RGBA32, які ви використовуєте:

  • Спліт розділіть пул спрайтів на багато менших атласів і використовуйте їх на вимогу, як описано в інших відповідях. Це також дозволяє використовувати різні методи оптимізації для кожного атласу окремо . Я підозрюю, що у вас буде трохи менше витраченої оперативної пам’яті, оскільки при упакуванні таких величезних текстур зазвичай внизу є невикористані ділянки;

  • Спробуйте скористатися палітруючими текстурами . Якщо ви використовуєте шейдери, ви можете "застосувати" палітру в коді шейдерів;

  • Ви можете розглянути можливість додавання параметра RGB5_A1 замість RGBA8 (якщо, наприклад, тіні для шахів добре підходять для вашої гри). Уникайте 8-бітової Альфи, коли це можливо, і використовуйте RGB5_A1 або аналогічні формати з меншою точністю (так само, як RGBA4), вони займають половину місця;

  • Переконайтеся, що ви щільно упаковуєте спрайт в атласи (див. Алгоритми упаковки у сміттєві упаковки), обертайте спрайт, коли це необхідно, і дивіться, чи зможете ви перекривати прозорі куточки для спрайтів ромба;

  • Ви можете спробувати апаратні формати стиснення (DXT, S3TC тощо) - вони можуть значно зменшити використання оперативної пам'яті, але перевірити наявність артефактів стиснення - на деяких зображеннях різниця може бути непомітна (ви можете використовувати це вибірково, як описано в першій точці кулі), але на деяких - дуже вимовляють. Різні формати стиснення викликають різні артефакти, тому ви можете вибрати той, який найкраще підходить для вашого стилю мистецтва.

  • Подивіться на розбивання великих спрайтів (звичайно, не вручну, але у вашому текстовому атласному пакувальнику) на статичний спрайт та менші спрайти для анімованих деталей.


2
+1 за використання DXT, це дуже добре. Велике стиснення і використовується безпосередньо графічним процесором, тому накладні витрати мінімальні.

1
Я згоден з dxt. Ви також можете запитати про підтримку DXT7 (обладнання DX11 +), який має той самий розмір, що і DXT1, але (мабуть) більш високої якості. Однак вам або потрібно буде подвоїти текстури (один DXT7 і один DXT1), або стиснути / розпакувати під час завантаження.
Programmdude

5

Перш за все, вам потрібно використовувати більше, менші атласи текстури. Чим менше текстур у вас буде складніше і жорсткіше управління пам’яттю. Я б запропонував розмір атласу 1024, і в цьому випадку у вас буде 128 текстур замість 2, або 2048, у цьому випадку у вас буде 32 текстури, які ви можете завантажувати та вивантажувати за потребою.

Більшість ігор займаються цим управлінням ресурсами, маючи межі рівня, тоді як на екрані завантаження відображаються всі ресурси, які більше не потрібні на наступному рівні, завантажуються, а необхідні ресурси завантажуються.

Інший варіант - завантаження за запитом, яке стає необхідним, якщо межі рівня небажані або навіть один рівень занадто великий, щоб вписатися в пам'ять. У цьому випадку гра намагатиметься передбачити, що гравець побачить у майбутньому, і завантажить це на задньому плані. (Наприклад: речі, які на даний момент знаходяться на відстані 2 екранів від програвача.) У той же час речі, які більше не використовувались довше, будуть завантажені.

Однак є одне питання: що відбувається, коли трапилось щось несподіване, що гра не змогла передбачити?

  • Панікування та відображення екрана завантаження, поки не завантажуються всі необхідні речі. Це може відчувати себе руйнівним для досвіду.
  • Майте спрайти з низькою роздільною здатністю для всього попередньо завантаженого, продовжуючи гру та замінюючи їх, як тільки спрацьовані з високою роздільною здатністю закінчуються завантаженням. Це може виглядати дешево для гравця.
  • Зробіть це впливом на геймплей і затримуйте подію на стільки, скільки потрібно. Наприклад, не породжуйте ворога, поки не буде завантажена графіка. Не відкривайте скриньку зі скарбами, перш ніж буде завантажена вся графіка для цього лута тощо.

Я додав деякі вимоги, які я пропустив. Екран завантаження або будь-який тип завантаження неможливий. Все потрібно робити у фоновому режимі або між окремими кліщами (менше 15 мс на кожен), хоча більшість часу зазвичай вже використовується для підготовки візуалізації та оновлення гри. У будь-якому випадку, розщеплення на більш дрібні частини може додати деяку гнучкість у перемиканні, це було б швидше точно. Питання полягає в тому, наскільки це шкодить продуктивності при візуалізації, оскільки перемикання вихідної растрової карти під час малювання уповільнює візуалізацію. Я повинен був би зробити точне вимірювання, щоб сказати, скільки.
Марвін

@ Так, ефективність продуктивності Марвіна, так, але, оскільки ви маєте справу з 2D, вам слід все-таки бути далеко від цього. Якщо в даний час візуалізація займає 1 мс на кадр, а через використання менших текстур вона раптом займає 2 мс, то це все-таки більш ніж швидко, щоб досягти постійних 60 кадрів в секунду. (16 мс)
API-Beast

@Marwin Multiplayer - це хитра діловість, завжди була, завжди буде. Вам, швидше за все, доведеться йти на компроміси. У вас з’являться заїкання, просто тому, що вам доведеться передавати дані через Інтернет, пакети будуть втрачені, пінг може раптом сплеск і т. Д. Заїкання неминуче, тому ви, що важливіше, зробите саму мережеву модель стійкою до заїкання. Знання, коли чекати та як чекати інших гравців.
API-Beast

Привіт, заїкання майже не можна уникнути в мультиплеєрі, ми працюємо над цим напрямком зараз, і я вважаю, що у нас хороший план. Я навіть міг би опублікувати та відповісти на власне запитання, описуючи те, що ми детально дослідили пізніше :) Це може бути несподівано, але час відтворення насправді є проблемою. Ми зробили багато оптимізацій, щоб зробити візуалізацію швидшою. Основний візуалізація тепер виконана окремою ниткою та іншими невеликими настройками. Не забувайте, що при максимальному збільшенні гравець може одночасно бачити десятки тисяч спрайтів. І ми навіть хотіли б пізніше дозволити ще більш високі масштаби.
Marwin

@Marwin Гм, об'єкти 10k зазвичай не становлять жодних проблем для ПК або сучасного ноутбука, якщо ви використовуєте належну пакетну доробку, чи профілювали ви код візуалізації?
API-Beast

2

Нічого собі, це величезна кількість анімаційних спрайтів, створених із 3D-моделей, які я припускаю?

Ви справді не повинні робити цю гру в сирому 2D. Коли ви зафіксували перспективу, відбувається щось смішне, ви можете безперешкодно змішувати заздалегідь викладені спрайти та фони з 3D-моделями, відтвореними в реальному часі, які активно використовуються в деяких іграх. Якщо ви хочете такої вишуканої анімації, яка здається найбільш природним способом це зробити. Отримайте 3D-двигун, налаштуйте його на використання ізометричної точки зору та візуалізуйте об'єкти, для яких ви продовжуєте використовувати спрайти як прості плоскі поверхні із зображенням на них. І ви можете використовувати стиснення текстури за допомогою 3D-двигуна, що одне - це великий крок вперед.

Я не думаю, що завантаження та розвантаження зробить багато для вас, оскільки ви можете мати майже все на екрані одночасно.


2

По-перше, знайдіть найефективніший формат текстури, який ви можете, будучи ще задоволеним візуальними ознаками гри, чи це RGBA4444, чи стиснення DXT тощо. Якщо ви не задоволені артефактами, сформованими у DXT-стисненому зображенні DXT, це було б життєздатним щоб зробити зображення непрозорими за допомогою стиснення DXT1 для кольору в поєднанні з 4 або 8 бітною сірою шкалою текстури для альфа? Я думаю, ви залишилися б на RGBA8888 для GUI.

Я виступаю за розбиття речей на менші текстури, використовуючи той формат, який ви вирішили. Визначте елементи, які завжди є на екрані і тому завжди завантажені, це може бути атласи місцевості та графічного інтерфейсу. Тоді я би розбив решту елементів, які зазвичай надаються разом якомога більше. Я не уявляю, що ви втратите занадто велику продуктивність, навіть збираючись до 50-100 розіграшів на ПК, але виправте мене, якщо я помиляюся.

Наступним кроком буде генерування mipmap-версій цих текстур, як хтось вказав вище. Я б не зберігав їх в одному файлі, а окремо. Отже, ви отримаєте версії кожного файлу 1024x1024, 512x512, 256x256 і т.д., і я би робив це до тих пір, поки не досягну найнижчого рівня деталізації, який я коли-небудь хотів би відобразити.

Тепер, коли у вас є окремі текстури, ви можете побудувати систему рівня деталізації (LOD), яка завантажує текстури для поточного рівня масштабування, і вивантажує текстури, якщо вони не використовуються. Текстура не використовується, якщо виведений елемент не відображається на екрані або не потрібен поточний рівень збільшення. Спробуйте завантажити текстури в оперативну пам’ять відео в потоці, окремому для потоків оновлення / візуалізації. Ви можете відображати найнижчу текстуру LOD, поки не буде завантажена потрібна. Іноді це може призвести до видимого перемикання текстури з низькою деталізацією / високою деталізацією, але я думаю, що це буде лише тоді, коли ви виконуєте надзвичайно швидке збільшення та зменшення масштабу під час руху по карті. Ви можете зробити систему інтелектуальною, спробувавши попередньо завантажити там, де ви думаєте, що людина переміститься або збільшить масштаб і завантажить якнайбільше в межах поточних обмежень пам'яті.

Це та річ, яку я перевірив би, чи допоможе це. Я думаю, що для отримання надзвичайних масштабів вам неминуче потрібна система LOD.


1

Я вважаю, що найкращий підхід - це розділити текстуру на багато файлів і завантажити їх на вимогу. Можливо, ваша проблема полягає в тому, що ви намагаєтеся завантажити більші текстури, які вам знадобляться для повноцінного 3D-сцени, і ви використовуєте Allegro для цього.

Для великого зменшення масштабу, який ви хочете застосувати, ви повинні використовувати mipmaps. Mipmaps - це версії текстур нижчої роздільної здатності, які використовуються, коли об'єкти знаходяться досить далеко від камери. Це означає, що ви можете зберегти свої 8192x8192 як 4096x4096, а потім ще 2048x2048 і так далі, і ви переключитесь на нижчі роздільні здатності, чим менше ви бачите спрайт на екрані. Ви можете як зберегти їх як окремі текстури, так і змінити їх розмір під час завантаження (але генерування міпових карт під час виконання збільшить час завантаження вашої гри).

Належна система управління завантажуватиме потрібні файли на вимогу та звільнятиме ресурси, коли їх ніхто не використовує, а також інші речі. Управління ресурсами - важлива тема в розробці ігор, і ви зводите своє управління до простого координатного відображення до єдиної текстури, що майже не має управління.


1
Розбившись на файли, ви маєте на увазі файли на жорсткому диску? Я припускаю, що я міг би зберігати всі зображення на оперативній пам’яті для початківців, і навіть копіювання з пам'яті-растрової карти на відео-растрову карту наразі занадто повільне, тому завантаження з жорсткого диска було б, звичайно, ще повільнішим. Наявність mimpaps не допоможе мені, оскільки у мене все ще буде найбільша роздільна здатність в vram.
Марвін

Так, не потрібно все завантажувати, ви повинні завантажувати лише те, що використовуєте. Щоразу, коли ви хочете змінити піксель на текстурі, завантаженій в VRAM, система повинна перенести ЦІЛЬКИЙ ТЕКСТУР в RAM, тільки для того, щоб змінити один піксель, поверніть його назад до VRAM. Якщо у вас все в одній текстурі, це передбачає переміщення 256 Мб в оперативну пам'ять, потім знову до VRAM, що блокує весь комп'ютер. Розділити його в різних файлах і текстурах - це правильний спосіб зробити це.
Пабло Аріель

Модифікація текстури, яка запускає копіювання в пам'ять і назад в рамку, застосовується лише для стійких растрових зображень, кеш, ймовірно, не буде встановлений стійким, єдиним недоліком буде необхідність оновити її, коли дисплей втрачений / знайдений. Але в allegro навіть проста копія зображення 640X480 з vram в біт-карту пам'яті (збереження попереднього перегляду гри) займає досить тривалий час.
Марвін

1
Мені потрібно мати все в одній великій текстурі, щоб оптимізувати сам малюнок, без нього ефект переключення контексту між окремими спрайтами занадто сильно сповільнює візуалізацію, щонайменше, в алегро. Не зрозумійте мене неправильно, але ви тут очевидний капітан, оскільки ви смутно пропонуєте мені зробити щось, про що я прошу у цьому питанні.
Марвін

1
Маючи ці текстуровані карти з різними файлами в різних файлах, це змусить мене перезавантажити весь атлас, коли програвач збільшує масштаб. Оскільки у двигуна є максимум кілька одиниць мс для цього, мабуть, я не бачу способу зробити це.
Марвін

0

Я рекомендую створити більше атласних файлів, які можна стиснути за допомогою zlib та витікати з компресії для кожного атласу, а, маючи більше атласних файлів та файлів меншого розміру, ви можете обмежити кількість даних про активне зображення у відеопам'яті. Крім того, застосуйте механізм потрійного буфера так, щоб ви швидше готували кожен кадр малювання і мали можливість швидше виконати, щоб заїкання не з’являлися на екрані.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.