Jak działają wielopasmowe moduły cieniujące w OpenGL?

13

W Direct3D wielozadaniowe moduły cieniujące są proste w użyciu, ponieważ można dosłownie zdefiniować przebiegi w programie. W OpenGL wydaje się to nieco bardziej skomplikowane, ponieważ możliwe jest nadanie programowi cieniującemu tyle cieniowania wierzchołków, geometrii i fragmentów, ile chcesz.

Popularnym przykładem shadera wielopasmowego jest shader toon. Jedno przejście powoduje rzeczywisty efekt cieniowania, a drugie tworzy kontur. Jeśli mam dwa moduły cieniujące wierzchołki, „cel.vert” i „zarys.vert”, oraz dwa moduły cieniujące fragmenty, „cel.frag” i „zarys.frag” (podobnie jak w HLSL), jak mogę to zrobić? połączyć je, aby stworzyć pełny shader toon?

Nie chcę, żebyś powiedział, że można do tego użyć modułu cieniującego geometrię, ponieważ chcę tylko poznać teorię kryjącą się za wielościennymi modułami cieniującymi GLSL;)

jmegaffin
źródło
„W Direct3D wielozadaniowe moduły cieniujące są łatwe w użyciu, ponieważ można dosłownie zdefiniować przebiegi w programie”. Nie, nie możesz. Możesz zdefiniować przejścia w pliku FX, ale to nie to samo co moduł cieniujący HLSL.
Nicol Bolas

Odpowiedzi:

11

Za wieloprzebiegową nie ma „teorii”. Nie ma „shaderów wielopasmowych”. Multipass jest bardzo prosty: rysujesz obiekt za pomocą jednego programu. Następnie rysujesz obiekt za pomocą innego programu.

Możesz użyć D3DX, takich jak pliki FX, aby ukryć te dodatkowe przejścia. Ale nadal działają w ten sposób. OpenGL po prostu nie ma dla niego kryjówki.

Nicol Bolas
źródło
1

Renderuj obiekt za pomocą modułu cieniującego komórki, a następnie ponownie renderuj go za pomocą modułu cieniującego kontur.

Adam
źródło
1
Więc powinienem stworzyć dwa różne programy do cieniowania? Dlaczego więc mogę dać programowi cieniującemu tak wiele shaderów wierzchołków / geometrii / fragmentów, ile chcę? Musi istnieć sposób, aby to zrobić za pomocą jednego programu.
jmegaffin
1
Nie dajesz mu wielu programów cieniujących wierzchołki (itp.). Jest tylko jedna główna funkcja, więc nie masz wielu punktów wejścia. Jest bardzo podobny do programu w C, ponieważ możesz mieć wiele plików połączonych ze sobą w celu utworzenia programu. Możesz udostępniać te pliki między różnymi programami, więc nie musisz powielać kodu, ale każdy plik niekoniecznie jest programem sam w sobie.
Chewy Gumball
1
Tak to już jest, renderuj raz za pomocą jednej pary modułów cieniujących (wierzchołek + fragment), a następnie renderuj ponownie za pomocą innej pary (lub użyj tego samego modułu cieniującego wierzchołków + innego modułu cieniującego fragmenty). Czasami renderujesz do bufora i używasz (jeszcze) innego modułu cieniującego, aby „wtopić” go w końcowy wynik.
Valmond
1

W OpenGL 4.0 istnieją jednolite podprogramy . Pozwalają one definiować funkcje, które można wymieniać w czasie wykonywania przy bardzo niewielkim obciążeniu. Możesz więc wykonać 1 funkcję dla każdego przejścia. Również 1 funkcja dla każdego typu modułu cieniującego.

Tutaj jest tutorial .

W starszych wersjach OpenGL najlepiej jest mieć kilka różnych shaderów i zamieniać się nimi. W przeciwnym razie możesz dodać wartości, które pomnożysz przez mundur o wartości 0,0 lub 1,0, aby włączyć lub wyłączyć. W przeciwnym razie warunkowe, jeśli można użyć instrukcji, ale OpenGL wykona wszystkie możliwe wyniki przy każdym wykonaniu / przejściu, więc upewnij się, że nie są zbyt ciężkie.

David C. Bishop
źródło
0

Są ludzie, którzy dużo wiedzą o GLSL, więc mam nadzieję, że wyprostowali rekord, ale na podstawie tego, co widziałem, powinieneś być w stanie w swoim shaderze fragmentów zrobić coś takiego (pseudokod, ja pozostawiam rzeczywisty GLSL osobom, które go znają):

out vec4 fragment_color
vec4 final_color
final_color = flat_color
If this fragment is in shadow
    final_color = shadow_color
If this fragment is an edge
    final_color = edge_color
If this fragment is a highlight
    final_color = highlight_color
fragment_color = final_color

Używając ifs w ten sposób, otrzymujesz coś w rodzaju wielokrotnych przejść. Czy to ma sens?

Edycja: Mam nadzieję, że to pytanie w SO pomoże rozwiać pewne nieporozumienia.

Społeczność
źródło
2
Ważne jest, aby pamiętać, że GLSL będzie wykonywać wszystkie instrukcje w gałęziach if za każdym razem, nawet jeśli nie są włączone. Najwyraźniej obliczanie wszystkiego i dodawanie wszystkich kolorów razem, ale pomnożenie wartości przez 1,0 lub 0,0, aby je włączyć lub wyłączyć, jest szybsze.
David C. Bishop
1
@ DavidC.Bishop: To nieprawda. Przynajmniej nie gwarantuje się prawdą. Kompilator zdecyduje, czy rzeczywista gałąź jest szybsza, czy podejście „oblicz wszystko i posortuj to później” jest szybsze.
Nicol Bolas
1
Nawiasem mówiąc, zachowanie, o którym wspomina @ DavidC.Bishop, nie jest specyficzne dla shaderów i GPU. Nowoczesne procesory wykonujące normalne programy wykonają spekulacyjnie co najmniej jedną gałąź, jeśli testowana wartość nie jest jeszcze dostępna. Jeśli okażą się błędne, wycofują się i ponawiają. To kończy się średnio dużym przyspieszeniem.
ipeet