Який сенс оновлення незалежного візуалізації в ігровому циклі?


74

Існує десятки статей, книг та дискусій про петлі гри. Однак я досить часто натрапляю на щось подібне:

while(running)
{
    processInput();
    while(isTimeForUpdate)
    {
        update();
    }
    render();
}

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


6
Особисто я знайшов gameprogrammingpatterns.com/game-loop.html корисним поясненням
Нільс

12
Не всі зміни у візуалізації відображаються в ігровому стані. І я підозрюю, що ви неправильно розумієте суть цього фрагмента коду - він дозволяє оновлювати кілька разів за візуалізацію, а не рендерівати кілька разів за оновлення.
Луань

13
Зверніть увагу, що код читає while (isTimeForUpdate), а не if (isTimeForUpdate). Основна мета полягає не в тому, render()коли цього не було update(), а в update()неодноразовому проміжку між render()s. Незважаючи на те, обидві ситуації мають дійсне використання. Перше було б дійсним, якщо стан може змінюватися поза вашою updateфункцією, наприклад, змінювати те, що відображається на основі неявного стану, такого як поточний час. Останнє дійсне, тому що надає вашому фізичному двигуну можливість робити багато невеликих, точних оновлень, що, наприклад, зменшує ймовірність «викривлення» через перешкоди.
Тьєррі

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

1
Як часто у вас є оновлення, яке нічого не робить? Навіть не оновлюючи фонову анімацію чи годинник на екрані?
pjc50

Відповіді:


113

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

1. Проблема: пристрої працюють із різною швидкістю

Коли-небудь намагаєтеся грати в стару гру DOS на сучасному ПК, і вона працює нечувано швидко - просто розмиття?

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

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

Зокрема, для ігор, які є конкурентоспроможними (або для багатокористувацьких, або за допомогою лідерів), ми не хочемо, щоб гравці, які працюють на певному пристрої, мали перевагу перед іншими, оскільки вони можуть бігти швидше або мати більше часу на реакцію.

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

2. Отже, чому б просто не зафіксувати частоту кадрів (наприклад, за допомогою VSync) і все-таки запустити оновлення стану гри та рендерінг у режимі блокування?

Це може спрацювати, але не завжди приємно для аудиторії. Існував довгий час, коли біг на солідних 30 кадрів в секунду вважався золотим стандартом для ігор. Зараз гравці звичайно очікують, що мінімум 60 кадрів в секунду, як мінімум, особливо в багатокористувацьких бойових іграх, а деякі старі заголовки зараз виглядають помітно похмурими, оскільки наші очікування змінилися. Зокрема, є також вокальна група гравців на ПК, які взагалі заперечують проти кадрування замків. Вони заплатили чимало за своє найсучасніше обладнання та хочуть використовувати цю обчислювальну мускулатуру для найгладшого та найвищого рівня, на який вона здатна.

Зокрема у VR, частота кадрів є королем, а стандарт продовжує повзати. На початку недавнього відродження VR ігри часто тривали близько 60 кадрів в секунду. Зараз 90 є більш стандартним, і таке програмне забезпечення, як PSVR, починає підтримувати 120. Це може продовжувати зростати. Отже, якщо VR-гра обмежує рамки до того, що можна зробити і прийнято сьогодні, вона може залишитися позаду, оскільки обладнання та очікування розвиватимуться далі.

(Як правило, будьте обережні, коли їм сказано, що "гравці не можуть сприймати нічого швидше, ніж XXX", оскільки це зазвичай засноване на певному типі "сприйняття", як розпізнавання кадру послідовно. Сприйняття безперервності руху, як правило, набагато набагато більше чутливий.)

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

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

3. Чи не має оновлення за фіксованим часовим кроком такі самі проблеми, як (2)?

Я думаю, що це суть початкового запитання: якщо ми розв'язуємо свої оновлення та інколи виводимо два кадри без оновлень стану гри між собою, то хіба це не те саме, що ретрансляція на нижньому кадрі, оскільки видимих ​​змін немає екран?

Насправді є кілька різних способів використання ігор для роз'єднання цих оновлень для хорошого ефекту:

a) Швидкість оновлення може бути швидшою, ніж виведений кадр

Як зазначає Тайкенн в іншій відповіді, зокрема, фізика часто наступає на більш високу частоту, ніж візуалізація, що допомагає мінімізувати помилки інтеграції та дати більш точні зіткнення. Отже, замість того, щоб оновлювати 0 або 1 оновлення між виведеними кадрами, у вас може бути 5 або 10 або 50.

Тепер рендерінг гравця зі 120 кадрів в секунду може отримати 2 оновлення на кадр, тоді як гравець на нижній специфікації апаратної рендеринга при 30 кадрів в секунду отримує 8 оновлень на кадр, і обидві їх ігри працюють з однаковою швидкістю гри-тики за реальну секунду. Краще апаратне забезпечення робить його більш гладким, але не радикально змінює, як працює ігровий процес.

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

б) Інтерполяція (або екстраполяція) ігрового стану між оновленнями

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

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

в) Додавання гладкості до змін неігрового стану

Навіть не маючи інтерполяції ігрового стану, ми все одно можемо отримати певні виграші.

Чисто візуальні зміни, такі як анімація персонажів, системи частинок або VFX, а також елементи інтерфейсу користувача, такі як HUD, часто оновлюються окремо від встановленого часового кроку стану гри. Це означає, що якщо ми відбиваємо свій ігровий стан кілька разів за кадр, ми не сплачуємо їх вартість кожним галочкою - лише за остаточний пропуск рендеру. Натомість ми масштабуємо швидкість відтворення цих ефектів відповідно до довжини кадру, щоб вони грали так само плавно, як дозволяє кадр візуалізації, не впливаючи на швидкість гри або справедливість, як обговорювалося в (1).

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

4. Чому б просто не використовувати цей (c) стиль для всього? Якщо це працює для анімації та інтерфейсу користувача, чи не можемо ми просто змінити масштаби оновлень стану геймплея, щоб вони відповідали поточному кадрам?

Так * це можливо, але ні це не просто.

Ця відповідь вже трохи довга, тому я не буду вникати в усі деталі, лише короткий підсумок:

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

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

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

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

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

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

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


2
У випадках, коли все буде використовувати однакову частоту кадрів, синхронізація всього може мінімізувати затримку між тим, коли контролер дискретизується, і коли реагує ігровий стан. Для багатьох ігор на деяких старих машинах час у найгіршому випадку буде менше 17 мс (елементи керування читаються на початку вертикальної порожньої, потім застосовуються зміни стану гри, а наступний кадр відображається, коли промінь рухається вниз по екрану) . Розв'язка речей часто призводить до значного збільшення найгіршого часу.
supercat

3
Хоча це правда, що більш складні трубопроводи для оновлення полегшують ненавмисне введення затримки, але це не є необхідним наслідком розв'язаного підходу при правильній реалізації. Насправді ми можемо навіть зменшити затримку. Давайте візьмемо гру, яка відображається зі швидкістю 60 кадрів в секунду. За допомогою read-update-renderблокувального кроку наша найгірша затримка - 17 мс (ігнорування графіки та затримка відображення на даний момент). З нерозв'язним (read-update)x(n>1)-renderциклом в одному кадрі, наша найгірша затримка може бути однаковою або кращою, тому що ми перевіряємо та діємо на введення так часто або більше. :)
DMGregory

3
З цікавої сторони, що стосується старих ігор, що не враховують реального часу, оригінальна аркада Space Invaders мала проблеми, спричинені передачею сили, коли гравець знищив ворожі кораблі, рендерінг, і, таким чином, оновлення гри, прискориться, в результаті чого, випадково , в знаковій кривій складності гри.
Оскуро

1
@DMGregory: Якщо все буде виконано асинхронно, то зміни керування можуть відбутися відразу після того, як цикл ігор опитує елементи керування, цикл подій гри після поточного завершиться після того, як цикл візуалізації захопить ігровий стан, і щоб цикл візуалізації після поточного закінчувався одразу після того, як система вихідного відеозахоплення захопить буфер поточного кадру, тому найгірший час закінчується просто сором’язливим двома ігровими циклами плюс два рази візуалізації плюс два періоди кадру. Правильна синхронізація речей може розрізати їх навпіл.
supercat

1
@Oskuro: Це не було проблемою. Швидкість циклу оновлення залишається незмінною незалежно від кількості окупантів на екрані, але гра не малює всіх окупантів у кожному циклі оновлення.
supercat

8

Інші відповіді хороші і говорять про те, чому цикл гри існує і повинен бути відокремлений від циклу візуалізації. Однак, що стосується конкретного прикладу "Чому відображати кадр, коли не було змін?" Це дійсно просто зводиться до обладнання та складності.

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

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

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


5
Тут слід розрізняти візуалізацію (усе) лише тоді, коли щось змінилося (про що запитує питання) і відображенням лише тих частин , які змінилися (що описує ваша відповідь).
DMGregory

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

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

@StevenStadnicki Це правда, що для рендерингу кожного кадру не існує великих витрат часу (оскільки для цього потрібно мати час у своєму бюджеті, коли одразу змінюється багато штатів). Але для таких портативних пристроїв, як ноутбуки, планшети, телефони або портативні ігрові системи, може бути обережним уникнути зайвого візуалізації, щоб ефективно використовувати акумулятор плеєра . В основному це стосується важких ігор інтерфейсу, де великі частини екрану можуть залишатися незмінними для кадрів між діями гравця, і не завжди можуть бути практичними для реалізації, залежно від архітектури гри.
DMGregory

6

Візуалізація, як правило, найповільніший процес в ігровому циклі. Люди не так просто помічають різницю частоти кадрів швидше 60, тому часто менш важливо витрачати час на візуалізацію швидше. Однак є й інші процеси, які скористаються більшою швидкістю. Фізика - це одне. Занадто велика зміна однієї петлі може призвести до того, що предмети будуть провалюватися прямо біля стін. Можливо, існують способи подолати прості помилки зіткнення з більшими кроками, але для безлічі складних фізичних взаємодій ви просто не збираєтесь отримувати однакову точність. Якщо цикл фізики запускається частіше, шанси виникнення глюків є меншими, оскільки об'єкти можна переміщувати меншими кроками, не виводячись щоразу. Більше ресурсів йде на чутливий двигун фізики і менше витрачається на те, щоб намалювати більше кадрів, які користувач не може бачити.

Це особливо важливо в більш граматичних іграх. Якщо для кожного циклу гри було одне візуалізація, а у гравця не було найпотужнішої машини, у грі можуть бути пункти, коли кадр в секунду падає до 30 або 40. Хоча це все ще буде не зовсім жахливою частотою кадрів, гра почала би ставати досить повільною, якби ми намагалися тримати кожну зміну фізики досить малою, щоб уникнути неприємностей. Гравця буде роздратовано, що його персонаж ходить лише вдвічі від звичайної швидкості. Якщо швидкість візуалізації не залежала від решти циклу, однак гравець міг би залишитися з фіксованою швидкістю ходу, незважаючи на падіння частоти кадрів.


1
Або, наприклад, виміряти час між кліщами та обчислити, як далеко повинен пройти персонаж у той час? Часи фіксованих спрайт-анімацій давно минули!
Грем

2
Люди не можуть сприймати речі швидше 60 кадрів в секунду без тимчасового згладжування, але частота кадрів, необхідна для досягнення плавного руху за відсутності розмитості руху, може бути набагато вищою за це. Крім певної швидкості, прядильне колесо повинно виглядати як розмиття, але якщо програмне забезпечення не застосовує розмиття руху, а колесо обертається більш ніж на половину спиці на кадр, колесо може виглядати погано, навіть якщо частота кадрів була 1000 кадрів в секунду.
суперкат

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

1
Людина зазвичай не може сприймати швидше, ніж 60 кадрів в секунду, тому марно витрачати ресурси на рендерінг швидше, ніж це. Я сприймаю це твердження. VR HMD відображаються на 90 Гц, і він збільшується. Повірте, коли я скажу вам, що ви можете НАДІЙНО сприймати різницю між 90 Гц і 60 ГГц на гарнітурі. Крім того, останнім часом я бачив стільки ігор, які пов'язані з процесором, як і GPU. Казати, що "візуалізація - це, як правило, найповільніший процес", не обов'язково відповідає дійсності.
3Dave

@DavidLively, так "безглуздо", можливо, було занадто великим перебільшенням. Я мав на увазі те, що візуалізація, як правило, є вузьким місцем, і більшість ігор чудово виглядають зі швидкістю 60 кадрів в секунду. Безумовно, є ефекти, важливі в таких видах ігор, як VR, які ви можете отримати тільки при більш швидкій частоті кадрів, але вони здаються швидше винятком, ніж нормою. Якби я працював на грі на більш повільній машині, я швидше міг би мати робочу фізику, ніж ледь помітний швидкий кадр.
tyjkenn

4

Така конструкція, як ваша у запитанні, може мати сенс, якщо підсистема візуалізації має певне поняття "минув час з моменту останнього візуалізації" .

Розглянемо, наприклад, підхід, при якому положення об'єкта в ігровому світі представлено за допомогою фіксованих (x,y,z)координат із підходом, який додатково зберігає поточний вектор руху (dx,dy,dz). Тепер ви можете записати цикл гри, щоб змінити позицію в updateметоді, але ви також можете спроектувати його так, щоб зміни руху мали відбуватися протягом update. При останньому підході, навіть якщо ваш ігровий стан насправді не зміниться до наступного update, arender-функція, яка викликається на більш високій частоті, вже може намалювати об'єкт у дещо оновленому положенні. Хоча це технічно призводить до розбіжності між поглядом і тим, що представлено внутрішньо, різниця досить мала, щоб не мати значення для більшості практичних аспектів, але дозволяє анімації виглядати набагато плавніше.

Прогнозувати "майбутнє" вашого ігрового стану (незважаючи на ризик помилитися), може стати хорошою ідеєю, якщо взяти до уваги, наприклад, затримки мережевого введення даних.


4

Окрім інших відповідей ...

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

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

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