Istnieją dwie metody radzenia sobie z tym. Obecnie nazywane są renderowaniem do przodu i renderowaniem odroczonym. Istnieje jedna odmiana tych dwóch, które omówię poniżej.
Renderowanie do przodu
Renderuj każdy obiekt raz dla każdego światła, które na niego wpływa. Obejmuje to światło otoczenia. Korzystasz z addytywnego trybu mieszania ( glBlendFunc(GL_ONE, GL_ONE)
), więc wkład każdego światła jest dodawany do siebie. Ponieważ udział różnych świateł jest addytywny, bufor ramki ostatecznie otrzymuje wartość
Możesz uzyskać HDR, renderując do bufora zmiennoprzecinkowego. Następnie wykonujesz ostatni ruch nad sceną, aby zmniejszyć wartości oświetlenia HDR do widocznego zakresu; będzie to również miejsce, w którym wdrażasz rozkwit i inne efekty końcowe.
Powszechnym ulepszeniem wydajności dla tej techniki (jeśli scena zawiera wiele obiektów) jest użycie „wstępnego przejścia”, w którym renderowane są wszystkie obiekty bez rysowania czegokolwiek w buforze ramki kolorów (użyj, glColorMask
aby wyłączyć zapisywanie kolorów). To po prostu wypełnia bufor głębokości. W ten sposób, jeśli renderujesz obiekt znajdujący się za innym, GPU może szybko pominąć te fragmenty. Nadal musi uruchamiać moduł cieniujący wierzchołki, ale może pomijać zwykle droższe obliczenia modułu cieniującego fragmenty.
Jest to prostsze do kodowania i łatwiejsze do wizualizacji. A w przypadku niektórych urządzeń (głównie mobilnych i wbudowanych układów GPU) może być bardziej wydajny niż alternatywa. Ale w sprzęcie wyższej klasy alternatywa zazwyczaj wygrywa w scenach z dużą ilością świateł.
Odroczone renderowanie
Odroczone renderowanie jest nieco bardziej skomplikowane.
Równanie oświetlenia używane do obliczania światła dla punktu na powierzchni wykorzystuje następujące parametry powierzchni:
- Pozycja na powierzchni
- Normalne powierzchni
- Rozproszony kolor powierzchni
- Kolor lustrzany powierzchni
- Błyszczący połysk powierzchni
- Możliwe inne parametry powierzchni (w zależności od złożoności równania oświetlenia)
W renderowaniu do przodu parametry te trafiają do funkcji oświetlenia modułu cieniującego fragmenty albo poprzez przekazanie bezpośrednio z modułu cieniującego wierzchołki, albo wyciągnięcie z tekstur (zwykle przez współrzędne tekstury przekazane z modułu cieniującego wierzchołek), lub wygenerowanie z całej tkaniny w module cieniującym fragmenty na podstawie inne parametry. Kolor rozproszenia można obliczyć, łącząc kolor na wierzchołek z teksturą, łącząc wiele tekstur, cokolwiek.
W renderowaniu odroczonym robimy to wszystko jawnie. W pierwszym przejściu renderujemy wszystkie obiekty. Ale nie renderujemy kolorów . Zamiast tego renderujemy parametry powierzchni . Dlatego każdy piksel na ekranie ma zestaw parametrów powierzchni. Odbywa się to poprzez renderowanie tekstur poza ekranem. Jedna tekstura przechowałaby rozproszony kolor jako RGB, a być może lśniący połysk jako alfa. Inna tekstura przechowałaby lustrzany kolor. Trzecia przechowa normalność. I tak dalej.
Pozycja zwykle nie jest przechowywana. Zamiast tego jest odtwarzany w drugim przejściu przez matematykę, która jest zbyt skomplikowana, aby się tu dostać. Wystarczy powiedzieć, że używamy bufora głębokości i pozycji fragmentu przestrzeni ekranu jako danych wejściowych, aby obliczyć pozycję punktu na powierzchni kamery w przestrzeni.
Teraz, gdy te tekstury przechowują zasadniczo wszystkie informacje o powierzchni dla każdego widocznego piksela w scenie, zaczynamy renderować quady pełnoekranowe. Każde światło otrzymuje pełnoekranowy render quad. Próbkujemy z tekstur parametrów powierzchni (i odtwarzamy pozycję), a następnie wykorzystujemy je do obliczenia udziału tego światła. To jest dodawane (ponownie glBlendFunc(GL_ONE, GL_ONE)
) do obrazu. Robimy to, dopóki nie zabraknie świateł.
HDR ponownie jest etapem postprocesowym.
Największym minusem odroczonego renderowania jest antyaliasing. Prawidłowe wykonanie antyialii wymaga nieco więcej pracy.
Największą zaletą, jeśli twój GPU ma dużą przepustowość pamięci, jest wydajność. Rzeczywistą geometrię renderujemy tylko raz (lub 1 + 1 na światło, które ma cienie, jeśli wykonujemy mapowanie cienia). Nigdy nie spędzamy czasu na ukrytych pikselach lub geometrii, które nie są widoczne po tym. Cały czas spędzany na oświetleniu jest spędzany na rzeczach, które są rzeczywiście widoczne.
Jeśli twój GPU nie ma dużej przepustowości pamięci, wtedy przejście światła naprawdę może zacząć boleć. Ciągnięcie od 3-5 tekstur na piksel ekranu nie jest zabawne.
Light Pre-Pass
Jest to swego rodzaju odmiana renderowania odroczonego, która ma interesujące kompromisy.
Podobnie jak w przypadku renderowania odroczonego, renderujesz parametry powierzchni do zestawu buforów. Masz jednak skrócone dane powierzchni; jedynymi danymi powierzchniowymi, na których Ci zależy, są wartości bufora głębokości (do rekonstrukcji pozycji), normalne i połysk.
Następnie dla każdego światła obliczasz tylko wyniki oświetlenia. Bez mnożenia z kolorami powierzchni, nic. Tylko kropka (N, L) i określenie lustrzane, całkowicie bez kolorów powierzchni. Określenia zwierciadlane i rozproszone powinny być przechowywane w osobnych buforach. Terminy zwierciadlane i rozproszone dla każdego światła są sumowane w dwóch buforach.
Następnie ponownie renderujesz geometrię, korzystając z obliczeń całkowitego światła rozproszonego i rozproszonego, aby uzyskać ostateczną kombinację z kolorem powierzchni, a tym samym generować całkowity współczynnik odbicia.
Zaletą jest to, że otrzymujesz z powrotem multisampling (przynajmniej łatwiej niż przy odroczeniu). Renderujesz mniej na obiekt niż renderowanie do przodu. Ale najważniejsze, że odroczenie tego zapewnia, to łatwiejszy czas na uzyskanie różnych równań oświetlenia dla różnych powierzchni.
Dzięki opóźnionemu renderowaniu generujesz całą scenę przy użyciu tego samego modułu cieniującego na światło. Dlatego każdy obiekt musi używać tych samych parametrów materiałowych. Dzięki wstępnemu przejściu światła możesz nadać każdemu obiektowi inny moduł cieniujący, aby sam mógł wykonać ostatni krok oświetlenia.
Nie zapewnia to tyle swobody, co przypadek renderowania do przodu. Ale jest jeszcze szybszy, jeśli masz wolne pasmo tekstur.