Wpis z mikrobloga

Kilka osób pytało, czy #symulatorlotoworbitalnych potrafi renderować światy większe niż tylko okolice planety.
tl;dr: tak, potrafi.

Ten post jest próbą poszerzonej odpowiedzi na to pytanie.
Załączam krótki filmik (około 2 min), który pokazuje tryb prezentacji lotu "z kamerą na Księżyc" - bez obaw, z rozsądną prędkością ;)
Po osiągnięciu apogeum lotu balistycznego uruchomiany jest ten tryb - wcześniej włączyłem kompresję czasu w symulatorze, aby lot do apogeum nie trwał zbyt długo.

A teraz postaram się wyjaśnić dlaczego renderowanie świata o takich rozmiarach, jak na tym filmiku, to jest dość duże wyzwanie.
Przeszkodą jest arytmetyka zmiennoprzecinkowa pojedynczej precyzji (liczby float o długości 32 bit).
Na 32 bitach można zapisać tylko ponad 4 miliardy różnych wartości. Jak łatwo policzyć, jeśli za największą możliwą do zapisania liczbę weźmiemy 384 400 000 (odległość Ziemi od Księżyca w metrach), to największa możliwa "rozdzielczość" takiego świata będzie miała niecałe 10 cm. Przy rozmiarach rakiety rzędu kilkunastu metrów oznacza to całkowicie niestabilny obraz i symulację. Problem oczywiście potęguje się przy jeszcze większych odległościach.
Cóż to za problem? Można zapytać. Wystarczy użyć liczb double (64 bit).
Otóż nie tak szybko... Rzecz w tym, że współczesne popularne procesory graficzne GPU nie obsługują operacji na liczbach double (wyjątkiem są może procesory do zadań profesjonalnych, jak NVIDIA Quadro)
W normalnym potoku przetwarzania, to GPU bierze na siebie operacje przekształcania geometrii obiektów z przestrzeni lokalnej (modelu) na przestrzeń świata, na przestrzeń widoku i na przestrzeń ekranu (odsyłam do bardzo dobrego artykułu na ten temat: https://learnopengl.com/Getting-started/Coordinate-Systems)
W praktyce oznacza to po prostu kolejne przemnażanie przez siebie macierzy reprezentujących odpowiednie przekształcenia (jesteśmy w świecie przestrzeni wektorowych, przekształcenia reprezentowane są przez macierze - zajmuje się tym Algebra Liniowa). Rzecz w tym, że przy tych rozmiarach świata w tych macierzach (na etapie przekształcenia do przestrzeni świata) mogą pojawić się bardzo małe i bardzo duże liczby - później już nie, bo ostatecznie w przestrzeni ekranu otrzymujemy już wartości, które rzeczywiście mieszczą się na ekranie.

Jak z tego wybrnąć? Jest wiele sposobów (co ciekawe, z tego co wiem, żaden współczesny silnik: ani Unreal Engine ani Unity nie udostępnia ich out-of-the box, trzeba "hackować" silnik, jak zrobili to np. autorzy Kerbal Space Program).
Jednym z nich jest po prostu przeniesienie operacji mnożenia macierzy z GPU do CPU już z wykorzystaniem współczesnych możliwości jednostek FPU (MMX, SIMD, AVX) szybkiego mnożenia wektorów z liczbami 64 bit.
Tą metodę właśnie zastosowałem w symulatorze. Szybkie mnożenie macierzy udostępnia np. biblioteka GLM. Powstaje taki pół-software'owy renderer (pół, bo w dalszym ciągu, oświetlenie, wektory normalne, teksturowanie, itp, itd. liczone jest w shaderach wykonywanych na GPU)
I to tyle :)
gacek_w - Kilka osób pytało, czy #symulatorlotoworbitalnych potrafi renderować światy...