Historia tego, jak doszliśmy do tej wspólnej konwencji, jest długa, a po drodze mnóstwo fascynujących wyzwań, dlatego postaram się ją motywować etapami:
1. Problem: Urządzenia działają z różnymi prędkościami
Próbowałeś kiedyś zagrać w starą grę DOS na nowoczesnym komputerze i działa ona niemożliwie szybko - tylko rozmycie?
Wiele starych gier miało bardzo naiwną pętlę aktualizacji - zbierali dane wejściowe, aktualizowali stan gry i renderowali tak szybko, jak pozwalał na to sprzęt, bez uwzględnienia czasu, jaki upłynął. Co oznacza, że gdy tylko zmienia się sprzęt, zmienia się rozgrywka.
Zasadniczo chcemy, aby nasi gracze mieli spójne wrażenia i wrażenia z gry na szeregu urządzeń (o ile spełniają pewne minimalne wymagania), niezależnie od tego, czy używają zeszłorocznego telefonu, czy najnowszego modelu, najwyższej klasy pulpitu do gier czy laptop średniej klasy.
W szczególności w przypadku gier konkurencyjnych (dla wielu graczy lub poprzez tabele wyników) nie chcemy, aby gracze korzystający z określonego urządzenia mieli przewagę nad innymi, ponieważ mogą działać szybciej lub mieć więcej czasu na reakcję.
Pewnym rozwiązaniem tutaj jest zablokowanie tempa, z jakim przeprowadzamy aktualizacje stanu gry. W ten sposób możemy zagwarantować, że wyniki będą zawsze takie same.
2. Dlaczego więc nie zablokować klatek na sekundę (np. Przy użyciu VSync) i nadal uruchamiać aktualizacje i renderowanie stanu gry w trybie blokowania?
Może to działać, ale nie zawsze jest smaczne dla publiczności. Minęło dużo czasu, gdy praca przy stałym 30 fps była uważana za złoty standard gier. Teraz gracze rutynowo oczekują 60 fps jako minimalnego paska, szczególnie w grach akcji dla wielu graczy, a niektóre starsze tytuły wyglądają teraz wyraźnie niepewnie, gdy nasze oczekiwania się zmieniły. Istnieje także grupa wokalistów, którzy w szczególności sprzeciwiają się blokowaniu klatek na sekundę. Zapłacili dużo za swój najnowocześniejszy sprzęt i chcą móc korzystać z tego komputera, aby uzyskać jak najbardziej płynny i wierny rendering.
Zwłaszcza w VR framerate jest królem, a standard ciągle rośnie. Na początku niedawnego odrodzenia VR gry często działały z prędkością około 60 klatek na sekundę. Teraz 90 jest bardziej standardowe, a harware, takie jak PSVR, zaczyna obsługiwać 120. To może jeszcze wzrosnąć. Tak więc, jeśli gra VR ogranicza liczbę klatek na sekundę do tego, co jest wykonalne i zaakceptowane dzisiaj, może pozostać w tyle, gdy sprzęt i oczekiwania będą się dalej rozwijać.
(Z reguły należy zachować ostrożność, gdy mówi się, że „gracze nie potrafią dostrzec niczego szybciej niż XXX”, ponieważ zwykle opiera się on na określonym typie „percepcji”, na przykład rozpoznawaniu klatki w sekwencji. Postrzeganie ciągłości ruchu jest zasadniczo o wiele bardziej wrażliwy).
Ostatni problem polega na tym, że gra wykorzystująca zablokowaną szybkość klatek również musi być konserwatywna - jeśli kiedykolwiek trafisz na chwilę w grze, w której aktualizujesz i wyświetlasz niezwykle dużą liczbę obiektów, nie chcesz przegapić swojej klatki termin i spowodować zauważalne jąkanie lub zaczep. Musisz więc ustawić budżety na zawartość na niskim poziomie, aby pozostawić nadmiar, lub zainwestować w bardziej skomplikowane funkcje dynamicznej regulacji jakości, aby uniknąć uzależnienia całej gry od najgorszego działania na sprzęcie o minimalnej specyfikacji.
Może to być szczególnie problematyczne, jeśli problemy z wydajnością pojawiają się na późnym etapie rozwoju, gdy wszystkie istniejące systemy są budowane i dostrajane przy założeniu błyskawicznego renderowania klatek na sekundę, którego teraz nie zawsze możesz trafić. Odsprzężenie aktualizacji i szybkości renderowania daje większą elastyczność w radzeniu sobie ze zmiennością wydajności.
3. Czy aktualizowanie w określonym czasie nie powoduje takich samych problemów jak (2)?
Myślę, że to jest sedno pierwotnego pytania: jeśli odsprzęgniemy nasze aktualizacje i czasami renderujemy dwie ramki bez aktualizacji stanu gry pomiędzy nimi, to czy nie jest to to samo, co renderowanie w trybie blokowania przy niższej prędkości klatek, ponieważ nie ma widocznej zmiany na ekran?
W rzeczywistości istnieje kilka różnych sposobów, w jakie gry wykorzystują odsprzęganie tych aktualizacji, aby uzyskać dobry efekt:
a) Szybkość aktualizacji może być większa niż renderowana liczba klatek na sekundę
Jak zauważa tyjkenn w innej odpowiedzi, w szczególności fizyka jest często przyspieszana z większą częstotliwością niż rendering, co pomaga zminimalizować błędy integracji i dać dokładniejsze kolizje. Tak więc zamiast aktualizować 0 lub 1 między renderowanymi ramkami, możesz mieć 5 lub 10 lub 50.
Teraz odtwarzacz renderujący z prędkością 120 klatek na sekundę może uzyskać 2 aktualizacje na klatkę, podczas gdy gracz przy renderowaniu sprzętowym o niższej specyfikacji przy 30 klatkach na sekundę dostaje 8 aktualizacji na klatkę, a obie gry działają z tą samą szybkością tyknięcia na sekundę w czasie rzeczywistym. Lepszy sprzęt sprawia, że wygląda płynniej, ale nie zmienia radykalnie sposobu działania gry.
Istnieje ryzyko, że jeśli częstotliwość aktualizacji będzie niezgodna z liczbą klatek na sekundę, można uzyskać „częstotliwość uderzeń” między nimi . Na przykład. w większości klatek mamy wystarczająco dużo czasu na 4 aktualizacje stanu gry i trochę resztek, wtedy co jakiś czas mamy dość zapisanych, aby zrobić 5 aktualizacji w ramce, wykonując mały skok lub zacinanie się w ruchu. Można temu zaradzić ...
b) Interpolacja (lub ekstrapolacja) stanu gry między aktualizacjami
Tutaj często pozwalamy, aby stan gry przeszedł jeden ustalony czas w przyszłości i przechowywał wystarczającą ilość informacji z 2 ostatnich stanów, abyśmy mogli wykonać dowolny punkt między nimi. Następnie, gdy jesteśmy gotowi pokazać nową ramkę na ekranie, łączymy się z odpowiednim momentem tylko w celu wyświetlania (tj. Nie modyfikujemy tutaj podstawowego stanu gry)
Po prawidłowym wykonaniu ruch wydaje się gładki, a nawet pomaga ukryć wahania prędkości klatek, o ile nie spadniemy zbyt nisko.
c) Dodanie płynności do zmian stanów nie związanych z rozgrywką
Nawet bez interpolacji stanu gry nadal możemy uzyskać wygrane z wygładzeniem.
Czysto wizualne zmiany, takie jak animacja postaci, układy cząstek lub efekty wizualne, oraz elementy interfejsu użytkownika, takie jak HUD, często aktualizują się osobno od ustalonego czasu trwania stanu gry. Oznacza to, że jeśli tykamy nasz stan gry wiele razy na klatkę, nie płacimy ich kosztem za każdym tyknięciem - tylko przy ostatnim podaniu renderowania. Zamiast tego skalujemy szybkość odtwarzania tych efektów, aby dopasować je do długości ramki, dzięki czemu grają one tak płynnie, jak pozwala na to liczba klatek na sekundę renderowania, bez wpływu na szybkość lub uczciwość gry, jak opisano w (1).
Może to zrobić również ruch kamery - szczególnie w VR, czasami wyświetlamy tę samą klatkę więcej niż raz, ale zmieniamy ją ponownie, aby uwzględnić ruch głowy gracza między nimi , dzięki czemu możemy poprawić postrzegane opóźnienie i komfort, nawet jeśli możemy natywnie renderują wszystko tak szybko. Niektóre systemy przesyłania strumieniowego gier (gdzie gra działa na serwerze, a gracz działa tylko na cienkim kliencie) również używają tej wersji.
4. Dlaczego po prostu nie używać tego (c) stylu do wszystkiego? Jeśli działa w przypadku animacji i interfejsu użytkownika, czy nie możemy po prostu przeskalować naszych aktualizacji stanu gry, aby pasowały do bieżącej liczby klatek na sekundę?
Tak * jest to możliwe, ale nie, nie jest to proste.
Ta odpowiedź jest już trochę długa, więc nie będę wchodził w wszystkie krwawe szczegóły, tylko krótkie podsumowanie:
Mnożenie przez deltaTime
prace w celu dostosowania do aktualizacji o zmiennej długości w celu zmiany liniowej (np. Ruch ze stałą prędkością, odliczanie timera lub postęp wzdłuż osi czasu animacji)
Niestety wiele aspektów gier jest nieliniowych . Nawet coś tak prostego, jak grawitacja, wymaga bardziej wyrafinowanych technik integracji lub etapów o wyższej rozdzielczości, aby uniknąć rozbieżności wyników przy różnych prędkościach klatek. Wejście i kontrola odtwarzacza sama w sobie stanowi ogromne źródło nieliniowości.
W szczególności wyniki wykrywania i rozwiązywania dyskretnych kolizji zależą od częstotliwości aktualizacji, co prowadzi do błędów tunelowania i drgań, jeśli ramki stają się zbyt długie. Tak więc zmienna liczba klatek na sekundę zmusza nas do stosowania bardziej złożonych / kosztownych metod ciągłego wykrywania kolizji w większej ilości treści lub tolerowania zmienności w naszej fizyce. Nawet ciągłe wykrywanie kolizji napotyka trudności, gdy obiekty poruszają się w łukach, co wymaga krótszych czasów ...
Tak więc, w ogólnym przypadku gry o średniej złożoności, utrzymanie spójnego zachowania i uczciwości całkowicie poprzez deltaTime
skalowanie jest gdzieś pomiędzy bardzo trudnym a intensywnym utrzymaniem do wręcz niemożliwym.
Standaryzacja częstotliwości aktualizacji pozwala nam zagwarantować bardziej spójne zachowanie w różnych warunkach , często z prostszym kodem.
Utrzymanie prędkości aktualizacji oddzielonej od renderowania daje nam elastyczność w kontrolowaniu płynności i wydajności wrażeń bez zmiany logiki rozgrywki .
Nawet wtedy nigdy nie uzyskujemy prawdziwie „idealnej” niezależności klatek, ale podobnie jak w przypadku wielu podejść w grach, daje nam to kontrolowaną metodę wybierania „wystarczająco dobrego” na potrzeby danej gry. Dlatego jest powszechnie nauczany jako przydatny punkt wyjścia.