Port na OSG już grywalny 2015-06-13 - Vedyimyn

(Niniejszy tekst jest luźnym tłumaczeniem wypowiedzi scrawla. Z uwagi na trudności w przekładzie technicznego języka, niektóre fragmenty zostawiam po angielsku, a niektóre, drobne, pomijam. Proszę wybaczyć niektóre neologizmy, jeśli takowe powstały, starałem się jak mogłem 😉 )

Przez ostatnie trzy miesiące zespół OpenMW ciężko pracował, by przeportować kod z silnika Ogre3D na OpenScenGraph (w skrócie OSG). Można o tym poczytać w jednym z poprzednich postów (tutaj).

Mamy zaszczyt ogłosić, że nasze wysiłki wreszcie wydały owoce. Wszystkie funkcje istotne dla gameplayu zostały przeportowane, tak więc użytkownicy mogą cieszyć się pełnoprawnym Morrowindem z gałęzi rozwojowej OpenMW-osg.

Niektóre zaawansowane funkcje – shadery, odległy teren, cienie i refleksy na wodzie – nie zostały jeszcze przeniesione. Można już jednak powiedzieć, że przejście na nowy silnik było wielkim sukcesem, nawet większym, niż się spodziewaliśmy. Odnowiony OpenMW ładuje się szybciej, wyświetla więcej klatek na sekundę, wygląda bardziej jak oryginalna gra oraz naprawia wiele długowiecznych bugów, którymi trudno się było zająć, korzystając z poprzednich narzędzi.

Zaraz, zaraz… Więcej klatek? Przetestujmy…

Pierwszy benchmark

Sprzęt, na którym testowano:
GeForce GTX 560 Ti/PCIe/SSE2, procesor AMD Phenom(tm) II X4 955 × 4, Linux 3.13.0-24-generic x86_64
1680×1050, pełny ekran, bez AA, 16x AF, bez refleksów na wodzie, cieni i shaderów
Maksymalny zasięg widzenia, ustawiony za pomocą suwaka w ustawieniach.

osg_bench
Scena testowa: stara, dobra (zacinająca się) Balmora.

Wielkości średnie OpenMW OpenMW-osg
Klatek na sekundę 49 75
Czas ładowania 7s 3.4s
Zajęta pamięć 344.6mb 277.1mb

OSG wygrywa we wszystkich kategoriach, co nie jest zaskoczeniem. Poprawa liczby klatek na sekundę zadowala, ale nie jest to trzy-, czterokrotna poprawa, jaką widzieliśmy w poprzednich testach, na pojedynczym modelu. Nie jest to powód do zmartwienia, ale jednak trzeba patrzeć na te wyniki z przymrużeniem oka:

  1. To porównanie nie jest fair. Do gałęzi OSG dodano nowe funkcje, które przybliżają nas do kompatybilności z oryginalnym Morrowindem, ale też wpływają na wydajność. Na przykład bryły brzegowe są dynamicznie rozszerzane, zależnie od animacji, co naprawia niesławny Bug 455 objawiający się znikaniem skrzekaczy pod pewnymi kątami. Ta zmiana odbija się na liczbie klatek. Wyrzucono static geometry batching (statyczne przetwarzanie geometrii?), które poprawiało wydajność, ale niosło ze sobą wiele problemów, na przykład niepoprawne oświetlenie albo brak ruchu pewnych obiektów. Pomimo tych dodatkowych obciążeń, OSG jest wciąż szybszy!
  2. Po dodaniu brakujących funkcji, zysk wydajności będzie większy. Powyższe porównanie uczyniono przy minimalnych ustawieniach graficznych, z uwagi na obecny brak implementacji zaawansowanych funkcji (shaderów, refleksów wodnych, itd.) w OSG. Spodziewamy się, że gdy tylko te funkcje się pojawią, spowodują mniejszy spadek wydajności, niż na starym silniku. Wynika to z lepszego dopasowywania się OSG do obciążenia GPU. Rysowanie działa w innym wątku niż reszta programu, toteż wyświetlanie złożonej sceny nie koliduje z realizacją fizyki, skryptów i animacji.
  3. Prawdziwa optymalizacja jeszcze się nie zaczęła. Na razie nacisk położono na to, by gra wróciła do stanu grywalnego, co stało się zaledwie parę dni temu. Teraz pojawiło się wiele nowych możliwości optymalizacji. Nowy silnik daje nam większą kontrolę nad procesem rysowania sceny, oraz nad jej zmianami. Dopiero zaczynamy z tego korzystać. Planowane optymalizacji obejmują:
    1. Przeniesienie aktualizacji skinów (skinning updates) do wątku roboczego.
    2. Przeniesienie aktualizacji cząsteczek do wątku roboczego.
    3. Współdzielenie stanu między różnymi NIF-ami.
    4. Dodanie cullingu dla emiterów cząsteczek. (Enable culling for particle emitters/programs.) [culling – usuwanie obiektów zasłoniętych przez inne obiekty, przyp. tłum.].
    5. Integrate a model optimizer. Morrowind’s models unfortunately contain plenty of redundant nodes, redundant transforms, and redundant state, which impacts rendering performance. The original engine runs an „optimizer” pass over the models upon loading them into the engine. We should implement a similar optimizer pass. OpenSceneGraph dostarcza przydatne narzędzie: osgUtil::Optimizer that might prove useful for this very purpose.
    6. Create a more balanced scene graph, e.g. a quad tree, to reduce the performance impact of culling and scene queries.
  4. Rendering to nie jedyne wąskie gardło. Założenie, że N razy szybszy silnik da nam N razy szybsze działanie programu jest błędne. Wiele innych czynników przyczynia się do czasu generowania pojedynczej klatki. Teraz, kiedy mamy szybszy silnik, inne wąskie gardła stały się bardziej widoczne. Obecnie największymi łobuzami są systemy odpowiadające za fizykę i animację. Wprowadzono parę wstępnych poprawek, ale bez wątpienia można zrobić więcej.

Podsumowując, większa wydajność to nie wszystko, czego użytkownicy mogą się spodziewać.

Wstępna lista zmian:

Poprawki w renderingu:

  1. Wieloosiowe skalowanie NPC-ów (Bug 814):
    Niektórzy NPC-e są teraz skalowani wzdłuż osi X i Y, co nadaje im grubawy wygląd, jak w oryginalnym Morrowindzie. Poprzednie wersje OpenMW nie mogły tego osiągnąć z powodu ograniczeń Ogre3D.
  2. Zwiększenie precyzji renderingu: gdy gracz znajdował się daleko od początku świata (co dawało duże współrzędne jego położenia) działy się dziwne rzeczy. Filmik.
  3. Usunięto statyczne przetwarzanie grafiki (static geometry batching): naprawa Bugu 385 (niepoprawne oświetlenie), naprawa ruchu obiektów pod wpływem skryptów (Bug 602), poprawa czasu ładowania sceny.
  4. Przezroczystość wygląda teraz tak, jak w oryginale: poprzednie wersje OpenMW radziły sobie z przezroczystością inaczej, niż oryginalny Morrowind, co miało ułatwić implementację statycznego przetwarzanie grafiki (static geometry batching). Poprawiono to. Widać, że przezroczyste obiekty mają gładsze krawędzie.
  5. Dodanie cullingu małych rzeczy (small feature culling option): oprócz usuwania obiektów spoza ekranu, można także wykonać culling obiektów mniejszych od piksela po wyrenderowaniu. Wizualnie nie widać zmiany, więc ta opcja jest domyślnie włączona.
osg_scaling osg_transparency
Porównanie skalowania NPC Porównanie przezroczystości

Zmieniono loader NIF-ów:

  1. Wsparcie dla skalowania wieloosiowego w plikach NIF  (Bug 2052).
  2. Poprawiono ograniczenie liczby węzłów w plikach NIF (Bug 2187).
  3. Poprawiono „zamarzanie animacji” przy cullingu obiektu (Bug 2151).
  4. Poprawiono algorytm skinningu, dla zwiększenia wydajności renderingu.
  5. Dynamiczne rozszerzanie brył brzegowych zależnie od animacji. Załatwia to Bug 455 (znikanie niektórych istot pod pewnymi kątami).
  6. Współdzielenie stanu NIF-ów (scene graphs are now a shared resource); drastyczne skrócenie czasu ładowania.
  7. Klucze animacji są teraz zasobem współdzielonym.

Przepisanie fizyki:

  1. Przy kompilacji z użyciem Bullet 2.83 lub nowszym, można skorzystać z funkcji btScaledBvhTriangleMeshShape, co poprawia wydajność instancingu kształtu (shape instancing).
  2. Usunięcie „szczegółowego” ray castingu, na rzecz bezpośredniego ray castingu, co znacznie zmniejsza zużycie pamięci.
  3. Użycie btCollisionWorld w miejsce btDynamicsWorld, żeby uniknąć zbędnych aktualizacji funkcjonalności, której nie używamy.
  4. Mapowanie obiektów kolizji przez wskaźnik zamiast nazwy.

Nowy ray casting:

  1. Użycie osgUtil::IntersectionVisitor dla bezpośredniego raycastingu.
  2. Wsparcie dla ray castingu zamiast  animowanych siatek (meshy). Tak naprawiono Bug 827.
  3. Przepisano algorytm wyświetlania postaci w oknie ekwipunku (podgląd obecnego ubioru) tak, aby używał ray castingu zamiast bufora selekcji, co poprawia responsywność.

Poprawiono ekran ładowania:

  1. Ekran ładowania jest renderowany w osobnym wątku, nie blokując w ten sposób procedury ładowania.
  2. Zwiększono liczbę klatek na sekundę w oknie łądowania, co upłynnia ruch paska ładowania.
  3. Wczytywanie obiektów OpenGL w osobnym wątku, w tle, w czasie ładowania obszaru, używając osgUtil::IncrementalCompileOperation.

Poprawa wsparcia dla SDL2

SDL2, wieloplatformowa biblioteka używana do obsługi wejścia i do tworzenia okien, została bardziej zintegrowana z systemem renderingu. Praktyczne korzyści obejmują:

  1. Opcja antyaliasingu wreszcie działa na Linuksie (Bug 2014).
  2. SDL2 odpowiada teraz za kontekst graficzny, co oznacza, że nowe API wyświetlania, takie jak Wayland i Mir na Linuksie, będą automatycznie wspierane bez przeróbek kodu.

osg_antialiasing
Antyaliasing 8x w akcji

Dynamiczna analiza programu

Miłym efektem ubocznym używania OSG jest możliwość korzystania z wysokiej klasy narzędzi do dynamicznej analizy programu. Klawisz F3 uruchamia nam podgląd, dający świetne informacje na temat programu.

osg_profiling
Dynamiczna analiza programu (Profiling overlay) – kolorowe paski obazują wątki wewnęrzne OSG, biały logikę OpenMW

Poprawki pasywne

OpenMW używa ujednoliconego silnika OpenGL na wszystkich platformach. Direct3D nie jest już wspierany, co ułatwia utrzymanie kodu i odciąża zespół.

Mówiąc praktycznie, w ten sposób naprawiono Bug 2186 (piksele-śmieci na minimapie na Windowsie) i Bug 1647 (wysypywanie się przy przełączeniu na pracę w oknie, na Windowsie).

Różne zmiany

Jest parę zmian nie związanych z przejściem na OSG, ale powstały w tej gałęzi kodu, dla redukcji liczby problemów przy łączeniu z resztą kodu:

  1. Zmieniono zasięg aktywacji dla świateł (Bug 1813).
  2. Poprawiono siłę NiGravity (Bug 2147).
  3. Dodano tryby ekstrapolacji kontrolera (Bug 1871).
  4. Dodano procesor cząsteczek NiPlanarCollider (Bug 2149).
  5. Dodano skalowanie interfejsu użytkownika:
osg_ui_scale_1 osg_ui_scale_2
Normalna skala Skala 2x, ta sama rozdzielczość

Utrzymanie kodu/restrukturyzacja/oczyszczanie

Baza kodu znacząco straciła na wadzie, co jest interesujące dla developerów, niekoniecznie dla użytkowników.

  1. Kod fizyki przeniesiono do nowego subsystemu: „mwphysics”.
  2. Usunięte nazwy węzłów scen, np. identyfikator RefData::getHandle.
  3. Usunięto OpenEngine.
  4. Usunięto „platform wrapper”.
  5. Usunięto „shiny”.

W sumie usunięto około 23 000 linijek kodu:

git diff upstream/master --shortstat
689 files changed, 24051 insertions(+), 47695 deletions(-)

Co dalej?

Lista poprawek jest spora, więc naszym priorytetem będzie wcielenie portu to głównej gałęzi, doprowadzenie nocnych buildów z powrotem do stanu używalności, wypuszczenie nowej wersji.

A mówiąc o dalszej przyszłości: daleko nam do uwolnienia pełnego potencjału naszego nowego silnika. Następne kroki zostaną skierowane ku poprawie wydajności, potem przywróceniu shaderów, odległego terenu, refleksów na wodzie i cieni. Nowy loader NIF-ów pozwala na implementację wczytywania komórek w tle, co początkowo planowano jako poprawkę po wydaniu wersji 1.0. Obecnie jest to trywialne, więc pewnie zobaczymy tę funkcję jeszcze przed wydaniem 1.0.

W międzyczasie jednak, pod względem graficznym, nic nas nie powstrzymuje przed wydaniem długo oczekiwanego OpenMW 1.0, więc pewnie najpierw skupimy się na usunięciu ostatnich blokad, wydaniu wersji 1.0, dodaniu dodatkowych funkcji graficznych w wersji 1.1. Jaka będzie kolejność – wyjdzie w praniu. W szczególności, odbicia na wodzie powinny być łatwiejsze do dodania niż cienie, które i tak nie działały zbyt dobrze na Ogre.

Jeśli chcesz się podzielić swoją opinią, nie krępuj się. Niezależnie od przyjętych priorytetów, czekają nas ekscytujące chwile!

Miejsce na komentarze.
Fork me on GitHub

Comments are closed.