Widzę kilka ogólnych podejść do robienia cieniowania cel:
- Powielanie i powiększanie modelu za pomocą odwróconych normalnych (dla mnie nie jest to opcja)
- Filtr Sobela / moduł cieniujący fragmenty zbliża się do wykrywania krawędzi
- Bufor matryc zbliża się do wykrywania krawędzi
- Metody cieniowania geometrii (lub wierzchołków) obliczające normalne ściany i krawędzie
Czy mam rację, zakładając, że podejście zorientowane na geometrię daje największą kontrolę nad oświetleniem i grubością linii, a także np. dla terenu, gdzie możesz zobaczyć linię sylwetki wzgórza łączącą się stopniowo w równinę?
Co jeśli nie potrzebuję oświetlenia pikselowego na moich powierzchniach? (I prawdopodobnie nie będę, ponieważ planuję używać opartego na komórkach oświetlenia / cieniowania opartego na wierzchołkach lub mapach tekstur.) Czy lepiej byłbym wtedy trzymać się podejścia opartego na geometrii, czy zamiast tego przejść na podejście do przestrzeni / fragmentów ekranu uprościć sprawę? Jeśli tak, to w jaki sposób mógłbym uzyskać „odbarwienie” wzgórz w obrębie sylwetki siatki, a nie tylko kontur całej siatki (bez szczegółów „atramentu” w tym zarysie? ( Sugestywne kontury , zagniecenia ).
Wreszcie, czy można tanio emulować podejście z odwróconą normą, używając modułu cieniującego geometrię? Martwię się tym, że z pewnością mógłbym powielić każdy wierzchołek i odpowiednio go skalować, ale jak podejść do odwracania normalnych i wyraźnego kolorowania w module cieniującym fragmenty?
To, czego chcę - różna grubość linii z natrętnymi liniami wewnątrz sylwetki ...
Czego nie chcę ...
EDYCJA: Dalsze badania wykazały, że ...
Ponieważ mam ogromną liczbę wierzchołków w terenie, nawet biorąc pod uwagę LoD oparte na odległości, ani odwrócone normalne, ani podejście oparte na shaderze geometrii (nawet z ubijaniem frustum) nie byłoby rozsądną opcją ze względu na złożoność obliczeniową związaną z duplikacją i skalowaniem wszystkich przesłane wierzchołki.
Biorąc pod uwagę, że nie potrzebuję oświetlenia na piksel w postaci cieniowania tonów stałych na powierzchniach terenu, rozważniejsze jest podejście oparte na normalnej twarzy - w przeciwnym razie wymóg prawidłowego oświetlenia powierzchni - są naturalnie dość drogie do obliczenia. Prawdą jest jednak, że dają one najwyższy stopień kontroli; na przykład możliwość cieniowania krawędzi za pomocą „artystycznych” pociągnięć: Piękna, ale nie bardzo przydatna w przypadku bardzo złożonego środowiska gry.
Bufory szablonów są czymś, czego wolałbym unikać, ponieważ wolałbym wykonywać całą pracę w shaderach. (Powyższy przykład z czerwonym konturem wykonano za pomocą bufora szablonów - stara szkoła).
Pozostawia to podejście cieniowania fragmentów obrazu. Złożoność obliczeniowa jest zredukowana do liczby fragmentów, a nie do liczby wierzchołków (w moim przypadku jest to 10–100 razy mniej operacji niż w przypadku modułu cieniującego geometrię). Wymaga to więcej niż jednego przejścia renderowania w celu wygenerowania bufora g (składającego się również z bufora normalnego i opcjonalnie również bufora głębokości), do którego możemy zastosować filtry nieciągłości (np. Operator Sobela). Nieciągłość głębokości umożliwia sugestywne kontury i fałdy. Moim jedynym sporem z tym podejściem jest niemożność zapewnienia dokładniejszej kontroli nad atramentowymi szerokościami krawędzi, chociaż przy odpowiednim algorytmie w module cieniującym fragmenty jestem pewien, że byłoby to możliwe.
Pytanie staje się teraz bardziej szczegółowe: jak dokładnie miałbym uzyskać otrzymywanie zmiennych szerokości krawędzi, szczególnie na zewnętrznej sylwetce, w shaderze fragmentów?
źródło
Odpowiedzi:
Zdecydowałem się zastosować metodę cieniowania fragmentów poprzez filtrowanie nieciągłości bufora głębokości. Przyczyny tego są:
Po przetestowaniu powiedziałbym, że ze względu na złożoność w przyszłych projektach wybrałbym podejście oparte na geometrii. Powodem jest to, że (jak sugerują inni w komentarzach) podejście modułu cieniującego fragmenty do wykrywania krawędzi może być intensywne obliczeniowo, szczególnie w przypadku implementacji DoF, w których okrąg promienia pomieszania, a tym samym liczba próbek na fragment, może być dość wysoka. Na szczęście jest to mniej ważne dla shaderów konturu.
źródło
W rzeczywistości istnieje bardzo łatwe ogólne rozwiązanie, jeśli można zastosować efekt końcowy. Świetną rzeczą jest to, że nie ma znaczenia, jak wysoka jest twoja liczba. Renderuj mapę głębokości jako skalę szarości, a następnie utwórz kropkę w żądanym kolorze linii, gdy kontrast między dwoma sąsiadującymi pikselami jest większy niż wartość progowa. Możesz powiększyć kropkę zgodnie z kontrastem i / lub poziomem światła renderowanego obrazu.
Wynalazłem algorytm toonShader w 2000/2001, jeszcze przed tym francuskim kolesiem, który stworzył to rozwiązanie. Mój był oparty na faktycznej geometrii materiałów. Istnieją w zasadzie dwa sposoby na zrobienie tego: 1. spójrz na normalne, jeśli normalne dwie płaszczyzny połączone z linią są odwrócone i skierowane w stronę kamery, renderuj tę linię, a następnie możesz użyć głębokości, oświetlenia itp. Jako wskazówek dla głębokości linii. 2. Spójrz na renderowaną geomerty (więc po transformacji perspektywy) Weź każdy odcinek linii, jeśli wierzchołki płaszczyzn łączących znajdują się po tej samej stronie tego odcinka linii, renderujesz linię. Możesz wtedy zrobić to samo dla grubości linii jak w metoda 1. 3. Mógłbyś tworzyć kombinacje tych trzech technik, ale wspomniałem o pierwszej, ponieważ wskazałeś ogromną liczbę.
źródło