Korzystanie z wielu shaderów

53

Obecnie studiuję moduły cieniujące Opengl, ale nie mogę czegoś wymyślić: jak zastosować różne moduły cieniujące do obiektów, na przykład czajniczek renderowany za pomocą toon shadera i inny w tej samej scenie przy użyciu bardzo odbijającej powierzchni, a inne zniekształcone od funkcja szumu, jak w tym filmie

http://www.youtube.com/watch?v=1ogg4ZfdBqU

Kolejnym jest zastosowanie modułu cieniującego Bloom w scenie, a następnie modułu cieniowania rozmycia w ruchu. Jak osiągnąć te efekty, gdy można mieć tylko jeden moduł cieniujący wierzchołki i jeden moduł cieniujący fragmenty? Czy istnieje jakaś sztuczka, taka jak używanie więcej niż jednego programu do cieniowania?

ibrabeicker
źródło
Jeśli chodzi o dobre odpowiedzi Nathana i Davida, właśnie dlatego widzisz termin render pass lub shader pass ; do skomponowania ostatecznego obrazu / klatki potrzeba wielu przejść. Jednym z powodów, dla których przetwarzanie GPU stało się tak cholernie równoległe, a zatem tak szybkie, jest potrzeba wielu przejść na ramkę. Wróć do rendererów oprogramowania Quake II lub Half Life, aby przypomnieć sobie, jak wiele funkcji cieniowania miłości dodaje do całej grafiki 3D.
Inżynier

Odpowiedzi:

59

Prostą odpowiedzią jest to, że zmieniasz je między każdym losowaniem. Ustaw moduł cieniujący, narysuj czajnik, ustaw inny moduł cieniujący, narysuj kolejny czajnik.

W przypadku bardziej skomplikowanych rzeczy, w których musisz zastosować wiele modułów cieniujących tylko do jednego obiektu, takich jak rozmycie, poświata i tak dalej. Zasadniczo masz wszystko renderowane do tekstur. Następnie renderujesz quad na całym ekranie z zastosowaną teksturą, używając innego modułu cieniującego.

Na przykład, jeśli chcesz wyrenderować efekt blasku, najpierw musisz wyrenderować swoją zwykłą scenę bez jarzenia, a następnie wyrenderować tylko kolorową sylwetkę rzeczy, które chcesz rozjaśnić na teksturze, a następnie przełączyć na moduł cieniowania rozmycia i renderować quad z tą teksturą przyczepioną do twojej nie świecącej sceny.

Istnieje inna technika zwana Odroczonym cieniowaniem, w której renderujesz scenę bez oświetlenia i stosujesz ją później w przestrzeni ekranu. Podstawowym celem jest zmniejszenie kosztów oświetlenia na piksel.

Zwykle renderowany jest bufor kolorów, który jest wyświetlany na ekranie. Z odroczonym cieniowaniem zamiast tego renderujesz bufor kolorów, a także bufor normalny i bufor głębokości w jednym przejściu cieniowania (możesz przechowywać normalne wektory i głębokość w teksturze, tak jak w przypadku mapowania normalnego i wysokości).

Oznacza to, że dla każdego piksela znasz położenie najbliższego kawałka nieprzezroczystej geometrii (głębokość lub odległość od oka) kolor i normalny. Z tego powodu możesz zastosować oświetlenie do każdego piksela na ekranie zamiast do każdego widocznego piksela każdego renderowanego obiektu. Pamiętaj, że jakiś obiekt zostanie narysowany nad innymi obiektami, jeśli scena nie będzie idealnie renderowana w kolejności od początku do końca.

W przypadku cieni faktycznie renderujesz bufor głębokości z punktu widzenia światła, a następnie korzystasz z informacji o głębokości, aby ustalić, gdzie uderza światło. Nazywa się to mapowaniem cieni (istnieje również inne podejście zwane objętościami cieni, które opracowuje sylwetkę geometrii i wytłacza ją, ale nadal będziesz używać shaderów).

W bardziej nowoczesnym OpenGL (3.0+) używasz obiektu Framebuffer z dołączonymi obiektami Renderbuffers. Ponieważ bufory renderujące można traktować jak teksturę. Możesz robić rzeczy, takie jak renderowanie 1 modułu cieniującego do wielu różnych buforów renderowania (więc nie musisz renderować tekstury, a następnie normalnych, a następnie składników blasku), ale podstawowa praktyka pozostaje taka sama.

Pożądane jest również zminimalizowanie jak największej liczby przełączników shaderów, aby zaoszczędzić na kosztach ogólnych. Dlatego niektóre silniki grupują wszystko razem z tym samym materiałem, aby można było wszystkie rysować jednocześnie.

David C. Bishop
źródło
16

Po prostu wiążesz jeden moduł cieniujący, renderujesz wszystkie obiekty za pomocą tego modułu cieniującego, a następnie wiążesz następny moduł cieniujący, renderujesz obiekty za pomocą tego modułu itp.

Możesz mieć tyle obiektów shaderów (shaderów załadowanych do pamięci i skompilowanych), jak chcesz; jednocześnie tylko jeden może być związany (aktywny).

Nathan Reed
źródło
5
Jeśli chodzi o implementację, w każdej ramce używam glUseProgram (1) i glUseProgram (2) do zmiany shaderów? Ile to kosztuje?
ibrabeicker
4
Jest to nietrywialny koszt (choć w przypadku najnowszych układów GPU jest mniejszy niż we wcześniejszych). Dlatego większość ludzi sortuje swoje obiekty według materiału, renderując razem wszystkie obiekty z tego samego materiału. Ale na pewno możesz sobie pozwolić na zmianę programów dziesiątki do setek razy na klatkę, jeśli nie więcej.
Nathan Reed,
9

Używanie więcej niż jednego modułu cieniującego w scenie jest dość proste; zmień moduł cieniujący, ustaw dla niego wartości, a następnie renderuj obiekt.

Pamiętaj jednak, że przełączanie shaderów może być kosztowne, dlatego przełączanie shaderów powinno być ograniczone do minimum. Istnieje kilka sposobów zmniejszenia tego wpływu przy jednoczesnym uzyskaniu wszystkich pożądanych efektów.

Pierwszą metodą, zazwyczaj najbardziej pożądaną, jest dodanie funkcjonalności wszystkich technik modułu cieniującego do tylko jednego modułu cieniującego i użycie warunków określonych dla renderowania każdego obiektu w inny sposób za pomocą tego samego modułu cieniującego. Nie wiem o modułach cieniujących OpenGL i GLSL, ale z modułami cieniującymi HLSL i DirectX można je zgrupować jako „technikę” i można ustawić tę technikę zamiast zmieniać moduł cieniujący. Dzięki temu możesz mieć kilka różnych programów cieniujących piksele i wierzchołki w tym samym pliku.

Drugim sposobem na zmniejszenie wpływu na wydajność jest ustawienie modułu cieniującego, renderowanie każdego obiektu, który go używa, a następnie powtórzenie. Innymi słowy, grupowanie renderowania.

Jeśli chcesz zastosować dwa różne efekty do tego samego obiektu (tj. Zastosować np. Shader toon, a następnie oświetlenie), możesz to zrobić na dwa różne sposoby. Pierwszym jest napisanie modułu cieniującego, który stosuje wiele efektów w tej samej funkcji. Drugim sposobem jest renderowanie modelu jeden raz dla każdego modułu cieniującego i mieszanie wyników poprzez ustawienie różnych opcji mieszania. Jest to jednak dużo więcej pracy i nie do osiągnięcia w każdych okolicznościach. Dlatego najlepszą opcją jest połączenie wszystkich efektów w jeden moduł cieniujący.

OriginalDaemon
źródło
7

Innym sposobem, który odkryłem, jest coś o nazwie podprogramy glsl, w których każdy typ modułu cieniującego jest zdefiniowany w jednej funkcji, aw aplikacji OpenGL możemy zdefiniować bieżący podprogram, narysować wierzchołek bufora, zmienić podprogram i renderowanie innego bufora

ibrabeicker
źródło
4
Wymaga to sprzętu obsługującego GL 4.x, który jest sprzętem klasy DX11.
Nicol Bolas,