Tak, ale potrzebujesz zmiany paradygmatu.
To, co jesteś przyzwyczajony, nazywa się renderingiem do przodu. Podajesz swoją geometrię, a następnie natychmiast przystępujesz do przejścia cieniowania. W podstawowym renderowaniu do przodu możesz albo zapętlić wnętrze modułu cieniującego dla każdego światła lub wykonać jedno przejście na światło i połączyć wynik razem (z mieszaniem dodatkowym).
Ale wiele się zmieniło. Wchodzi: odroczone renderowanie
Teraz, gdy jest tak wiele wariantów, które opisują je wszystkie w szczegółach, odpowiedź będzie znacznie bardziej niż możliwa do zaakceptowania. Więc tutaj opiszę sedno odroczonego cieniowania, istnieje wiele innych zasobów, które można łatwo znaleźć za pomocą Google, mam nadzieję, że po przeczytaniu tego będziesz mieć odpowiednie słowa kluczowe, aby znaleźć to, czego potrzebujesz.
Podstawową ideą jest odłożenie cieniowania na później. Masz dwa główne kroki:
- Renderuj swoją geometrię i wszystkie informacje potrzebne do cieniowania do wielu celów renderowania. Oznacza to, że zazwyczaj w podstawowej implementacji miałbyś bufor głębokości, bufor zawierający wartości normalne twojej geometrii i kolor albedo. Wkrótce przekonasz się, że potrzebujesz innych informacji o materiałach (np. Szorstkość, współczynnik „metaliczny” itp.).
Ten obraz z wikipedii pokazuje trzy bufory (kolor, głębokość i normalne)
Ponownie ilość, rodzaj i zawartość używanych buforów różni się bardzo w różnych projektach. Znajdziesz zestaw buforów o nazwie GBuffers.
- Następnie nadszedł czas na zastosowanie rzeczywistego oświetlenia. Podczas przejścia światła dla każdego światła chcesz narysować objętość światła, która zależy od rodzaju światła:
- Aby uzyskać światło kierunkowe, renderujesz czteroekranowy ekran.
- Dla światła punktowego renderujesz kulę, której promień jest oparty na tłumieniu światła punktowego.
- Dla światła punktowego renderujesz stożek, którego wymiary ponownie zależą od właściwości twojego światła.
W cieniowaniu pikseli tego przejścia przekazujesz swoje GBuffery i wykonujesz oświetlenie i cieniowanie z wykorzystaniem zawartych w nich informacji. W ten sposób przetwarzane są tylko piksele, na które wpływa każde ze świateł, z wyraźnym przyspieszeniem w porównaniu z klasycznym renderowaniem do przodu.
Ma także różne wady, w szczególności obsługę przezroczystych obiektów oraz większe zużycie przepustowości i pamięci wideo. Ale trudniej jest też obsługiwać różne modele materiałów.
Masz inne zalety dodatkowe (ponieważ masz dużo informacji gotowych do przetwarzania końcowego), a także jest dość łatwy do wdrożenia. Ale nie jest to już najfajniejsza rzecz dla wielu świateł.
Nowsze techniki to na przykład renderowanie sąsiadująco. Ich główną ideą jest podzielenie sceny w „kafelkach” przestrzeni ekranu i przypisanie do każdej płytki wpływających na nią świateł. Istnieje to zarówno w sposób odroczony, jak i terminowy. Techniki te prowadzą do pewnych problemów, gdy występują różne nieciągłości głębokości w kafelku, ale na ogół są szybsze niż klasyczne odroczone i rozwiązują różne problemy z tym związane. Na przykład, między zaletami, z odłożonym kafelkami odczytujesz GBuffers raz na oświetlony fragment i piksele na tym samym kafelku spójnie przetwarzają te same światła.
Dalszą ewolucją po tej stronie jest cieniowanie klastrowe, które jest koncepcyjnie podobne do podejścia opartego na kafelkach, mając zamiast kafelków przestrzeni ekranu klastry w zakresie 3D. Ta metoda lepiej radzi sobie z problemem nieciągłości głębokości i generalnie działa lepiej niż metody sąsiadująco.
WAŻNA UWAGA: Opisałem podstawy odroczonego cieniowania. Istnieje wiele odmian, optymalizacji i ulepszeń, więc zachęcam do eksperymentowania z prostą wersją, a następnie do zbadania innych technik, takich jak wspomniana powyżej.