Ray Tracing? – Wprowadzenie do path tracing’u

Wprowadzenie do path tracing’u było prezentowane przeze mnie na uczelni na zajęciach z matematycznych pojęć grafiki komputerowej. Postanowiłem wkleić tę prezentację również na bloga.

Wprowadzenie

Tematem prezentacji początkowo miał być stricte ray tracing czy reversed ray tracing ale z racji, że zostało to już kilka razy powtórzone nawet na dzisiejszych zajęciach to slowem wstepu przedstawimy kilka koncepcji, które zahaczają o ray tracing ale w dalszej części wykładu skupimy się na technice zwanej path tracingiem.

Tutaj widzimy słowa Davida Kirka – utalentowanego informatyka oraz byłego chief scientist oraz wiceprezydenta architektury w firmie będącej jednym z głównym graczy (jak nie tym najważniejszym) na rynku kart graficznych czyli firmie NVIDIA. 

Mawiał on, że ray tracing jest technologią przyszłości i zawsze nią pozostanie. Mamy początek 2023 roku a kilka miesięcy temu miała miejsce premiera nowej generacji kart graficznych NVIDIA, które wspierają dla technologii Ray Tracingu akcelerowanego sprzętowo. Czyli nie miał racji ze nie uda nam się okiełznać tej technologii czy w pełni jej wykorzystać. 

Zaczniemy sobie teraz od małego wprowadzenia do terminologii. 

Promienie

Zdefiniujemy sobie na początek czym jest promień i jak go możemy określać. Nadamy mu atrybuty takie jak origin czyli początek promienia, który będzie jakimś punktem w układzie współrzędnych, w naszej prezentacji przyjmujemy przestrzeń trójwymiarową i punkt określimy skalarami X Y Z. Dodatkowo, żeby promień miał sens musi mieć jakiś kierunek, w którym zmierza. I to będzie po prostu wektor trójwymiarowy. 

Rzutowanie promieni

Następnie zdefiniujemy sobie Ray Casting czyli próba rzutowania/strzelania promieniem z jego początku w zdefiniowanym kierunku. Celem Ray Castingu jest sprawdzenie czy jakiś potencjalny obiekt zostanie tym promieniem trafiony. Tutaj można wspomnieć, że w zasadzie nie jest to algorytm renderowania ale raczej narzędzie, które można wykorzystać w dowolny sposób, zależnie od projektu. Przykładowo do sprawdzania fizycznych kolizji w grze komputerowej, strzelance, w której sprawdzamy czy wystrzelony pocisk trafi jakiś obiekt. 

Tutaj oczywiście wykorzystamy je do renderowania. Czyli jeszcze raz podsumowując – ray casting polega na “strzelaniu” promieniem i sprawdzaniu czy coś stanie na jego drodze 

Ray casting może zostać również wykorzystany pomiędzy dwoma punktami i w takim ustawieniu możemy sprawdzić czy jakiś obiekt znajduje się pomiędzy nimi. Jest to dobry sposób na sprawdzenie czy dany punkt i również przestrzeń znajduje się w cieniu obiektu. Czyli zakładamy jeden punkt jako nasze origin – początek promienia ustawionego w kierunku drugiego punktu i w ten sposób możemy ustalić czy coś przesłania ten drugi punkt. Jeśli tak to jest w jego cieniu.

Backwards ray tracing

Tyle ze wstępu, poznaliśmy fundamenty promieni, narzędzie ray castingu. Teraz przejdźmy do generowania jakiegoś podstawowego obrazu, czyli faktyczne i praktyczne wykorzystanie ray castingu. W zasadzie każdy renderowany obraz posiada kamerę – obiekt oka – z którego użytkownik / gracz widzi obraz. Tak więc po lewej stronie mamy kamerę. Następnie mamy obraz – Image – czyli ekran, przestrzeń dwuwymiarowa, która opisuje świat trójwymiarowy. Idąc dalej, każdy mały kwadracik w tym obrazie Image jest pikselem, tak należy go poprawnie interpretować. Ten piksel zawiera dane RGB, czyli kolejno Red Green Blue. Tak więc technologia ray tracingu próbuje odpowiedzieć na pytanie, w co promień przechodzący przez dany piksel uderza. Innymi słowami, iterujemy sobie po wszystkich pikselach na obrazie i rzutujemy wybraną ilość promieni przez ten piksel zbierając próbki. Promień wchodzi w środowisko sceny (w naszym przypadku trójwymiarowej), spotyka na swojej drodze obiekty, bądź nie oczywiście. I ten obiekt, który jest najbliżej, zostanie jako pierwszy uderzony, a tym samym to właśnie ten obiekt zostanie wyświetlony na ekranie.  

Następnie możemy rzutować promienie między źródłem światła, a najbliższym widzianym obiektem w scenie / środowisku. Tym samym sprawdzimy, czy cokolwiek stoi na przeszkodzie światłu, tak żeby dotarło do wybranego miejsca i oświetlało je pełną swoją mocą. Jeśli cokolwiek będzie na drodze światła do punktu intersekcji View Ray, to to jest sygnał dla nas, że ten punkt znajduje się w cieniu. W przeciwnym wypadku jest oświetlony. To jest Shadow Ray widoczny na obrazku. 

To co tutaj zaprezentowaliśmy jest w zasadzie wykorzystaniem idei promieni i ray castingu, o których wspomnieliśmy wcześniej. Definiujemy sobie promienie, które wchodzą w świat i szukają kolizji. Następnie sprawdzamy czy między dwoma punktami (punktem intersekcji View Ray i źródłem światła) jest jakikolwiek obiekt.

Whitted’s Ray Tracing

To co opisaliśmy, jest algorytmem, którego geneza zaczyna się w 1980. Właśnie wtedy powstawały pierwsze algorytmy ray tracingu. Przykładem jest whitepaper napisany przez Turnera Whitted “An Improved Illumination Model for Shaded Display”. Ten dokument opisuje sporo ważnych algorytmów, które w zasadzie wykorzystywane są po dziś dzień, np. antyaliasing oraz bounding volume hierarchies (BVH). 

Mówiąc w skrócie, to był początek idei – w jaki sposób jesteśmy w stanie wyrenderować refleksje, refrakcję i cienie. Oraz czy w ogóle jesteśmy w stanie wyrenderować to w sposób rekursywny. 

Na bazie tego co zostało powiedziane wcześniej możemy wywnioskować czym jest ray tracing. Jest to algorytm. gdzie na każdy piksel ekranu rzutujemy promień w środowisko. Następnie z punktu intersekcji rzutujemy kolejny promień w kierunku każdego istniejącego źródła światła w scenie tak żeby dowiedzieć się gdzie są cienie. Natomiast na końcu z każdego materiału z wartości refleksji / refrakcji rzutujemy promienie, żeby wydobyć kolor dla tego materiału. 

Kajiya’s Path Tracing

My jednak bardziej chcielibyśmy skupić się na technologii path tracingu. Tak więc przechodząc dalej, w 1986 był spory skok teoretyczny jeśli chodzi o algorytmy śledzenia promieni. James T. Kajiya opisał to w swoim white paper The Rendering Equation. Co w przypadku gdy powiemy Sky is the Limit. Będziemy ponownie rzutować promienie z punktu kamery / oka i będziemy szukać każdego promienia, który w coś uderzy. Czyli znajomy będzie punkt intersekcji. I co w przypadku gdy nie będziemy wiedzieli w którą stronę idzie odbicie. Owszem, w przypadku lustra to jest jasne, jednak mówimy tutaj o powiedzmy ceramice. W tym przypadku totalnie nie mamy pojęcia z którego punktu, z której strony pochodzi światło. W zasadzie wiemy, jak to w prawdziwym życiu, światło pochodzi ze wszystkich możliwych kierunków. Tak więc rzutujemy promienie z tego punktu intersekcji w wielu kierunkach. O czym konkretnie mówię? Zobaczymy to.

Algorytm śledzenia ścieżek

Z punktu oka / kamery przez jeden wybrany piksel, w jednym jego wybranym miejscu, wpuszczamy jeden promień w środowisko. Ten promień uderza w tą skrzynkę. Z tego powodu, że uderzyliśmy w skrzynkę, poznaliśmy punkt intersekcji promienia ze światem gry. 

I następnie z tego punktu intersekcji rzutujemy kolejny promień, który może pójść w dowolnym kierunku. Tutaj na rzecz prezentacji wraca w kierunku nieba i zdobywa kolor zielony. Dlatego też został narysowany tutaj na zielono.

Później rzutujemy kolejny promień właśnie z tego punktu intersekcji, ponownie w dowolnym kierunku i ten promień zdobywa informacje dot. koloru. Widzimy, że odbija się dwa razy i potem sobie leci gdzieś dalej, na rzecz prezentacji taki poziom rekursywności powinien pozwolić zrozumieć zagadnienie.

Tak więc kontynuujemy rzutowanie promieni, śledzenie ich ścieżek, tym samym zdobywając coraz to więcej informacji na temat koloru. Warto tu wspomnieć, że to nie musi polegać na tym, że Shadow Ray, czyli te promienie z punktu intersekcji rzutujemy bezpośrednio w kierunku światła. Nie, Tutaj zależy nam na zdobyciu informacji skąd światło jest najbardziej intensywne, ponieważ światło samo w sobie pochodzi ze wszystkich kierunków. 

Tak więc mamy ścieżki, promienie zdobywają informacje o podłożu, gruncie, informacje o niebie, o innych obiektach znajdujących się w pobliżu itp. Tak więc całkiem sporo wydobytych kolorów z środowiska gry. Jak to wygląda pod względem próbek? Przejdźmy dalej.

Próbki naszego piksela są zebrane i w takiej graficznej / obrazkowej reprezentacji przedstawiają się następująco, widoczne tutaj po lewej stronie. 

Dzięki takiemu rozwiązaniu, otrzymujemy antyaliasing w zasadzie kompletnie za darmo co jest znaczącym benefitem. Takie próbkowanie pozwala nam otrzymać wszystkie kolory, które wchodzą w skład wybranego piksela, w jednym wykładzie to ujęli jako “the whole pixel box”. W standardowym podejściu rzutowalibyśmy promienie tylko z środka tego piksela. Teraz wystarczy te próbki zsumować i w zasadzie otrzymujemy gotowy kolor dla wybranego piksela. 

Tutaj oczywiście zdecydowaliśmy zaprezentować się jedynie kilka promieni, tak żeby pokazać ogólny zarys algorytmu. Biorąc pod lupę sobie powiedzmy branżę filmową, możemy się dowiedzieć, że tam na każdy piksel filmowcy rzutują po 1000, czy nawet 3000 promieni. To jest przeogromna ilość promieni i ścieżek do wyliczenia, z aktualnym hardware niemożliwa do wyliczenia w standardzie 60 klatek na sekundę. 

Tak więc path tracing jest w zasadzie prostym wynalazkiem, wystarczy rzutować promienie i zdobywać kolory, które opisują dany piksel.

The Rendering Equation

Wytłumaczyliśmy sobie czym jest path tracing. Teraz postarajmy się zrozumieć jakie równanie opisuje to zjawisko. Ono dokładnie przedstawia, w jaki sposób światło dostaje się do naszych oczu. Wygląda to skomplikowanie jednak jest to jedno z najwspanialszych równań jakie widziała grafika komputerowa. Jeśli mamy tutaj jakiegoś fanatyka grafiki, to jest to równanie, które możemy sobie wytatuować bądź wydrukować nad łóżkiem.

Ruszamy zatem w kierunku zrozumienia tego równania. Tak więc zacznijmy od tego co równanie potrzebuje na wejściu. Jest to punkt w scenie X, na który aktualnie patrzy kamera / oko. Jest też outgoing direction, czyli omega o. To jest w zasadzie kierunek do kamery / oka. Oprócz tego mamy też incoming direction. To znajduje się po samej prawej stronie jako omega i. Ta zmienna opisuje światło przychodzące z innych stron do tego punktu X. I obok omega i, mamy wektor normalny (czyli wektor prostopadły do płaszczyzny. Czyli gdy mamy po prostu płaską płaszczyznę, wektor normalny będzie bezpośrednio ukierunkowany ku górze, No i mamy też wyrażenie S do kwadratu. S do kwadratu mówi nam, że będziemy ewaluować tą całkę po wszystkich kierunkach z których pochodzi światło.

Jeśli chodzi o wyrażenia po kolei znajdujące się w tym równaniu. 

Outgoing light po samej lewej, odpowiada na pytanie jakie światło widzimy / obserwujemy, z danym punktem i wyjściowym kierunkiem. Innymi słowami, patrzymy w wybranym kierunku na punkt, jakie światło obserwujemy z tego punktu. 

Idąc dalej, mamy emitted light. Ta funkcja w zasadzie polega na tym samym co outgoing light, z tą różnicą, że ta funkcja ma odpowiedzieć jakie światło pochodzi dokładnie z tego punktu. Więc jeśli w tym punkcie jest źródło światła, które w zasadzie świeci bezpośrednio w nasze oko, to wtedy nie zobaczymy żadnego innego koloru, będzie to po prostu światło pochodzące tylko z tego punktu. Nie musimy wtedy rozwiązywać reszty tego równania.

Natomiast w całce widzimy trzy wyrażenia, są to kolejno incoming light, material i lambert. Tak więc incoming light odpowiada nam jakie światło widzi dany punkt z kierunku omega i. To już jest inny kierunek niż ten w kierunku oka, co warto zaznaczyć, to jest omega i, a nie omega o. 

Funkcja materiału z danymi na wejściu omega i, czyli kierunkiem światła nadchodzącego, i omega o, kierunkiem światła odchodzącego, odpowiada na pytanie, które nadchodzące światła odbijają się w kierunku światła odchodzącego. Tak więc w przypadku lustra, kierunki nadchodzącego i odchodzącego będą bardzo ze sobą powiązane. Natomiast inne materiały już mogą zachowywać się odrobinę inaczej. 

No i finalnie mamy ostatnie wyrażenie, lambert. W skrócie to iloczyn światła nadchodzącego i wektora normalnego. Przejdźmy dalej, żeby łatwiej pokazać.

Lambert’s Cosine Law

Lambert’s cosine law jest już całkiem starą ideą, która nawet intuicyjnie jest prawdziwa. Jeśli światło jest bezpośrednio nad powierzchnią, będzie miało największy wpływ na kolor tej powierzchni. Ale jeśli źródło światła zostanie przesunięte w innym kierunku, czyli światło padające na powierzchnię będzie pochodziło  z boku, będzie miało znacznie mniejszy wpływ na kolor tej powierzchni. Tak więc patrząc na te obrazki od lewej do prawej. możemy zobaczyć jak światło rozprzestrzenia się po powierzchni, gdy zmieniamy kierunek jego pochodzenia. 

Materiały

Dodatkowo parę słów o materiale. W przypadku path tracingu, jeśli chodzi o lustra to mamy bezpośrednie odbicie naszego rzutowanego promienia. Tak więc w przypadku lustra wystarczy jeden promień, który idealnie się odbija. 

W przypadku błyszczącego materiału będziemy potrzebowali prześledzić ścieżki serii promieni i możemy dobrać dowolnie kierunki. Następnie ich zsumowanie powinno zwrócić satysfakcjonujący rezultat. 

I na końcu mamy już wspomnianą ceramikę, czyli materiał, który rozprasza światło, gdzie właśnie najczęściej stosujemy wcześniej wspomniane prawo Lamberta.

Szybki przykład każdego materiałów wziętych z prawdziwego życia, czyli bombki świąteczne, kulka styropianowa oraz kulka drewniana. 

Podsumowanie

Tak więc w zasadzie wytłumaczyliśmy sobie najważniejsze równanie stojące za ideą path tracingu. Sumujemy wszystkie światła pochodzące ze wszystkich kierunków i to światło przekazujemy do kamery / oka jak to zostało przedstawione w wizualizacji.

Na końcu chcielibyśmy pokazać porównanie wyrenderowanych scen z różną ilością próbek z algorytmami właśnie path tracingu. Po lewej widnieje obraz wyrenderowany z 5 próbkami per pixel, natomiast po lewej już zostało wykorzystane 500 próbek, tym samym obraz jest dużo bardziej przejrzysty, posiada śladową ilość szumów. Takie drobne szumy możemy zaobserwować właśnie w grach, gdzie bardziej interesuje nas utrzymanie stabilnego renderowania 60 klatek na sekundę celem zachowania płynności gry. Natomiast w branży filmowej starają się wygenerować fotorealistyczne obrazy, tym samym mogą sobie pozwolić na wykorzystanie zdecydowanie większej ilości próbek.

Oraz ostatnie porównanie, gdzie mamy są obrazy wyrenderowane z algorytmami path tracingu, ray tracingu oraz standardowej rasteryzacji. Widzimy, że path tracing najbardziej oddaje świat rzeczywisty, fantastycznie reprezentuje odbicia. Fotorealizm w najwyższej krasie.

Bibliografia

Turner Whitted, An Improved Illumination Model for Shaded Display, 1980​

NVIDIA, OptiX: A General Purpose Ray Tracing Engine​

James T. Kajiya, The Rendering Equation, 1986​

NVIDIA, Ray Tracing Essentials, 2021​

Rendering: Path Tracing Basics lecture by Bernhard Kerbl in TU Wien, Austria​

Barbara Putz, GRAFIKA KOMPUTEROWA 3D, OKNO Politechnika Warszawska 2018​

https://blogs.nvidia.com/blog/2022/03/23/what-is-path-tracing/