Jak narysować kontury wokół modeli 3D? Mam na myśli coś takiego jak efekty z ostatniej gry Pokemon, które wydają się mieć wokół siebie zarys jednego piksela:
3d
shaders
graphics
graphics-programming
mistyczny portal
źródło
źródło
Odpowiedzi:
Nie sądzę, że żadna z pozostałych odpowiedzi tutaj osiągnie efekt w Pokémon X / Y. Nie wiem dokładnie, jak to się robi, ale wymyśliłem sposób, który wydaje się prawie tym, co robią w grze.
W Pokémon X / Y kontury są rysowane zarówno wokół krawędzi sylwetki, jak i na innych nie-sylwetkowych krawędziach (tak jak tam, gdzie uszy Raichu spotykają się z głową na poniższym zrzucie ekranu).
Patrząc na siatkę Raichu w Blenderze, widać, że ucho (zaznaczone na pomarańczowo powyżej) jest tylko oddzielnym, odłączonym przedmiotem, który przecina głowę, powodując nagłą zmianę normalnych powierzchni.
Na tej podstawie próbowałem wygenerować kontur w oparciu o normalne, co wymaga renderowania w dwóch przebiegach:
Pierwsze przejście : Renderuj model (teksturowany i cieniowany) bez konturów i wyrenderuj normalne przestrzenie kamery na drugi cel renderowania.
Drugie przejście : Wykonaj pełnoekranowy filtr wykrywający krawędzie normalnych od pierwszego przejścia.
Pierwsze dwa obrazy poniżej pokazują wyniki pierwszego przejścia. Trzeci to sam zarys, a ostatni to końcowy łączny wynik.
Oto moduł cieniujący fragmenty OpenGL, którego użyłem do wykrywania krawędzi w drugim przejściu. To najlepsze, co mogłem wymyślić, ale może być lepszy sposób. Prawdopodobnie też nie jest zbyt dobrze zoptymalizowany.
A przed renderowaniem pierwszego przejścia oczyszczam cel renderowania normalnych do wektora odwróconego od kamery:
Czytałem gdzieś (umieszczę link w komentarzach), że Nintendo 3DS używa potoku o stałej funkcji zamiast shaderów, więc myślę, że nie może tak być dokładnie tak, jak dzieje się w grze, ale na razie „ Jestem przekonany, że moja metoda jest wystarczająco bliska.
źródło
Ten efekt jest szczególnie powszechny w grach wykorzystujących efekty cieniowania cel, ale w rzeczywistości jest czymś, co można zastosować niezależnie od stylu cieniowania cel.
To, co opisujesz, nazywa się „renderingiem krawędzi obiektu” i ogólnie polega na podkreśleniu różnych konturów i konturów modelu. Dostępnych jest wiele technik i wiele artykułów na ten temat.
Prostą techniką jest renderowanie tylko krawędzi sylwetki, najbardziej zewnętrznego konturu. Można to zrobić tak samo, jak renderowanie oryginalnego modelu za pomocą szablonu, a następnie renderowanie go ponownie w trybie grubej siatki, tylko w przypadku braku wartości szablonu. Zobacz tutaj przykładową implementację.
To jednak nie podświetli wewnętrznego konturu ani fałdowania krawędzi (jak pokazano na zdjęciach). Zasadniczo, aby to zrobić skutecznie, musisz wyodrębnić informacje o krawędziach siatki (na podstawie nieciągłości w normalnych ścianach po obu stronach krawędzi i zbudować strukturę danych reprezentującą każdą krawędź.
Następnie możesz pisać moduły cieniujące, aby wyciągać lub w inny sposób renderować te krawędzie, gdy regularna geometria zachodzi na model podstawowy (lub w połączeniu z nim). Położenie krawędzi i normalne sąsiadujących ścian w stosunku do wektora widoku służą do ustalenia, czy można narysować konkretną krawędź.
W Internecie można znaleźć dalsze dyskusje, szczegóły i dokumenty z różnymi przykładami. Na przykład:
źródło
dz/dx
dz/dy
Najprostszym sposobem na zrobienie tego, powszechnym na starszym sprzęcie przed modułami cieniującymi piksele / fragmenty i nadal używanym na urządzeniach mobilnych, jest powielenie modelu, odwrócenie kolejności nawijania wierzchołków, aby model wyświetlał się na lewą stronę (lub jeśli chcesz, możesz zrób to w narzędziu do tworzenia zasobów 3D, powiedzmy Blender, odwracając normalne powierzchni - to samo), a następnie lekko rozwiń cały duplikat wokół jego środka, a na koniec kolor / teksturę tego duplikatu całkowicie czarny. Daje to kontury wokół oryginalnego modelu, jeśli jest to prosty model, taki jak sześcian. W przypadku bardziej złożonych modeli z wklęsłymi formami (takich jak ten na poniższym obrazku) konieczne jest ręczne zmodyfikowanie duplikatu modelu, aby był nieco „grubszy” niż jego pierwotny odpowiednik, na przykład suma Minkowskiegow 3D. Możesz zacząć od wypchnięcia każdego wierzchołka nieco wzdłuż jego normalnej pozycji, aby utworzyć siatkę konturu, podobnie jak transformacja Zmniejszanie / Tuczenie Blendera.
Ekran podejścia przestrzeń / pixel shader wydają się być wolniejsze i trudniejsze do wdrożenia dobrze , ale OTOH nie podwoić liczbę wierzchołków w swoim świecie. Więc jeśli wykonujesz pracę w wielu polach, najlepiej wybierz to podejście. Biorąc pod uwagę nowoczesną konsolę i pojemność pulpitu do przetwarzania geometrii, nie chcesz martwić się o współczynnik 2 w ogóle . Styl kreskówkowy = na pewno niski poli, dlatego kopiowanie geometrii jest najłatwiejsze.
Możesz sam przetestować efekt np. W Blenderze bez dotykania żadnego kodu. Kontury powinny wyglądać jak na poniższym obrazku, zwróć uwagę, jak niektóre są wewnętrzne, np. Pod pachą. Więcej szczegółów tutaj .
.
źródło
W przypadku gładkich modeli (bardzo ważne) efekt ten jest dość prosty. W cieniowaniu fragmentów / pikseli potrzebujesz normalnej wartości cieniowanego fragmentu. Jeśli jest on bardzo zbliżony do prostopadłego (
dot(surface_normal,view_vector) <= .01
może być konieczne granie z tym progiem), następnie pokoloruj fragment na czarny zamiast zwykłego koloru.Takie podejście „zużywa” trochę modelu do wykonania szkicu. To może, ale nie musi być to, czego chcesz. Bardzo trudno jest stwierdzić na podstawie obrazu Pokemona, czy tak właśnie się dzieje. Zależy to od tego, czy spodziewasz się, że kontur zostanie zawarty w jakiejkolwiek sylwetce postaci, czy też wolisz, aby kontur otaczał sylwetkę (co wymaga innej techniki).
Punktem kulminacyjnym będzie dowolna część powierzchni, na której będzie przechodzić od przodu do tyłu, w tym „wewnętrzne krawędzie” (jak nogi na zielonym pokemonie lub jego głowie - niektóre inne techniki nie dodałyby do nich żadnego konturu ).
Przy takim podejściu obiekty, które mają twarde, nieładne krawędzie (jak sześcian), nie zostaną wyróżnione w pożądanych lokalizacjach. Oznacza to, że takie podejście w ogóle nie jest opcją; Nie mam pojęcia, czy wszystkie modele Pokemonów są płynne, czy nie.
źródło
Najczęstszym sposobem, w jaki to widziałem, jest powtórzenie renderowania w twoim modelu. Zasadniczo powiel go i odwróć normalne, i wepchnij to w moduł cieniujący wierzchołek. W module cieniującym przeskaluj każdy wierzchołek wzdłuż jego normalnej. W module cieniującym piksele / fragmenty narysuj kolor czarny. To da ci zarówno zarysy zewnętrzne, jak i wewnętrzne, takie jak wokół ust, oczu itp. Jest to w rzeczywistości dość tani call remis, jeśli nic innego nie jest ogólnie tańszy niż post przetwarzanie linii, w zależności od liczby modeli i ich złożoności. Guilty Gear Xrd używa tej metody, ponieważ łatwo jest kontrolować grubość linii za pomocą koloru wierzchołka.
Drugi sposób wykonywania linii wewnętrznych nauczyłem się z tej samej gry. Na mapie UV wyrównaj teksturę wzdłuż osi u lub v, szczególnie w obszarach, w których chcesz uzyskać linię wewnętrzną. Narysuj czarną linię wzdłuż każdej osi i przesuń współrzędne UV do lub z tej linii, aby utworzyć linię wewnętrzną.
Zobacz wideo z GDC dla lepszego wyjaśnienia: https://www.youtube.com/watch?v=yhGjCzxJV3E
źródło
Jednym ze sposobów na wykonanie konspektu jest użycie naszych modeli normalnych wektorów. Wektory normalne to wektory, które są prostopadłe do ich powierzchni (skierowane od powierzchni). Sztuczka polega na podzieleniu modelu postaci na dwie części. Wierzchołki skierowane w stronę aparatu i wierzchołki skierowane w stronę przeciwną do aparatu. Nazwiemy je odpowiednio PRZÓD i POWRÓT.
Na potrzeby konspektu bierzemy nasze ZWROTY wierzchołki i nieznacznie przesuwamy je w kierunku ich normalnych wektorów. Pomyśl o tym, jakby część naszej postaci odwrócona od aparatu była nieco grubsza. Kiedy to zrobimy, przydzielamy im wybrany przez nas kolor i mamy ładny kontur.
Linia 41: Ustawienie „Cull Front” mówi modułowi cieniującemu, aby wykonał ubój na wierzchołkach skierowanych do przodu. Oznacza to, że w tym przejściu zignorujemy wszystkie wierzchołki skierowane do przodu. Pozostaje nam strona WSTECZ, którą chcemy nieco zmodyfikować.
Linie 51–53: Matematyka ruchów wierzchołków wzdłuż ich normalnych wektorów.
Linia 54: Ustawienie koloru wierzchołka na wybrany przez nas kolor zdefiniowany we właściwościach modułu cieniującego.
Przydatny link: http://wiki.unity3d.com/index.php/Silhouette-Outlined_Diffuse
Aktualizacja
inny przykład
źródło
Jednym ze wspaniałych sposobów na to jest renderowanie sceny na teksturze Framebuffer , a następnie renderowanie tej tekstury podczas filtrowania Sobela na każdym pikselu, co jest łatwą techniką wykrywania krawędzi. W ten sposób możesz nie tylko stworzyć piksele sceny (ustawienie niskiej rozdzielczości tekstury Framebuffer), ale także mieć dostęp do wszystkich wartości pikseli, aby Sobel działał.
źródło