Jak poprawnie wdrożyć mieszanie alfa w złożonej scenie 3D?

11

Wiem, że odpowiedź na to pytanie może wydawać się łatwa, ale doprowadza mnie to do szału. Istnieje zbyt wiele możliwych sytuacji, z którymi powinien sobie poradzić dobry mechanizm mieszania alfa, a dla każdego algorytmu mogę coś wymyślić.

Oto metody, o których myślałem do tej pory:

  • Najpierw pomyślałem o sortowaniu obiektów według głębokości, ten po prostu zawodzi, ponieważ Obiekty nie są prostymi kształtami, mogą mieć krzywe i mogą zapętlić się między sobą. Więc nie zawsze mogę powiedzieć, który z nich jest bliżej aparatu.

  • Potem pomyślałem o sortowaniu trójkątów, ale ten też może się nie powieść, ale nie jestem pewien, jak to zaimplementować, jest rzadki przypadek, który może ponownie spowodować problem, w którym dwa trójkąty przechodzą przez siebie. Znów nikt nie może powiedzieć, który jest bliżej.

  • Następną rzeczą było użycie bufora głębokości, przynajmniej głównym powodem, dla którego mamy bufor głębokości, są problemy z sortowaniem, o których wspomniałem, ale teraz pojawia się inny problem. Ponieważ obiekty mogą być przezroczyste, w jednym pikselu może być widoczny więcej niż jeden obiekt. Więc dla którego obiektu należy przechowywać głębokość pikseli?

  • Pomyślałem wtedy, że może mogę zapisać tylko największą głębokość obiektu z przodu, i używając tego określam, jak mam mieszać kolejne wywołania rysowania przy tym pikselu. Ale znowu był problem, pomyśl o dwóch półprzezroczystych płaszczyznach z jednolitą płaszczyzną pośrodku. Na końcu miałem wyrenderować płaszczyznę bryłową, widać najodleglejszą płaszczyznę. Zauważ, że zamierzałem scalać co dwie płaszczyzny, dopóki nie pozostanie tylko jeden kolor dla tego piksela. Oczywiście mogę również stosować metody sortowania z tych samych powodów, które wyjaśniłem powyżej.

  • Wreszcie jedyną rzeczą, jaką wyobrażam sobie jako zdolną do pracy, jest renderowanie wszystkich obiektów w różne cele renderowania, a następnie sortowanie tych warstw i wyświetlanie ostatecznego wyniku. Ale tym razem nie wiem, jak mogę zaimplementować ten algorytm.

Ali1S232
źródło

Odpowiedzi:

11

Krótka odpowiedź

Spójrz w głęboki peeling . Z moich badań wydaje się, że jest to najlepsza alternatywa, choć kosztowna obliczeniowo, ponieważ wymaga wielu przejść renderowania. Oto kolejna nowsza i szybsza implementacja , również firmy NVIDIA.

Długa odpowiedź

To trudne pytanie. Większość książek, które czytałem, przegląda ten temat i pozostawia go na:

Zacznij od renderowania wszystkich nieprzezroczystych obiektów, a następnie mieszaj przezroczyste obiekty na wierzchu w kolejności od początku do końca.

Łatwiej powiedzieć niż zrobić, ponieważ oczywiste podejście do sortowania obiektów według ich centroidów nie gwarantuje prawidłowej kolejności sortowania.

To dokładnie ten sam problem, dlaczego algorytm malarza nie działa w ogólnym przypadku i potrzebny jest bufor głębokości .

Powiedziawszy to, w jednej z książek, o których wspomniałem, jest kilka rozwiązań:

  • Depth Peeling - rozwiązanie wieloprzebiegowe, które pokonuje ograniczenie bufora głębokości, dając nam n-ty najbliższy fragment, a nie tylko najbliższy. Największą zaletą jest to, że możesz renderować przezroczyste obiekty w dowolnej kolejności i nie trzeba sortować. Może to być kosztowne z powodu wielu przejść, ale link, który podałem u góry, wydaje się poprawiać wydajność.

  • Bufor K ze wzorcowanym routingiem - Użyj routingu szablonowego do przechwytywania wielu warstw fragmentów na piksel na przebieg. Główną wadą jest to, że fragmenty muszą być sortowane w przebiegu przetwarzania końcowego.

Wspomina również o sprzętowym rozwiązaniu problemu, ale nie sądzę, aby było faktycznie dostępne:

  • Bufor F - Bufor FIFO na zamówienie rasteryzacji do renderowania wieloprzebiegowego. Niemniej jednak dobra lektura i wprowadzenie mówi również trochę o problemie z porządkiem sortowania według przejrzystości i obecnych rozwiązaniach.

Inne obejścia, które nie zapewniają doskonałych wyników, ale są lepsze niż nic:

  • Po renderingu wszystkie nieprzezroczyste przedmioty, trzymać za pomocą Z-buffer testowania dla obiektów przezroczystych ale wyłączyć piśmie Z-bufora . Możesz uzyskać niektóre artefakty z nieprawidłowego sortowania, ale przynajmniej wszystkie przezroczyste obiekty będą widoczne.

I cytując białą księgę bufora F powyżej:

Najprostszym rozwiązaniem jest renderowanie każdego częściowo przezroczystego wielokąta całkowicie niezależnie (tj. Renderowanie wszystkich jego przejść przed przejściem do następnego wielokąta). To rozwiązanie jest zwykle zbyt drogie ze względu na poniesione koszty zmiany stanu. Alternatywnie aplikacja lub biblioteka cieniowania mogą grupować wielokąty, aby zapewnić, że tylko nienakładające się wielokąty są renderowane razem. W większości przypadków to rozwiązanie również nie jest atrakcyjne, ponieważ wymaga oprogramowania do wykonania analizy wielokątów na ekranie.

David Gouveia
źródło
11

Prawidłowa odpowiedź to nr 1: posortuj wszystkie swoje rzeczy według głębokości i wyrenderuj je (oczywiście wyłącz zapisywanie głębokości, ale nie testuj). Co to jest „rzecz”?

Każda „rzecz” musi być obiektem wypukłym; nie może się pokrywać. Jeśli masz wklęsły przedmiot, musisz go zatem rozbić na wypukłe kawałki.

To standardowy sposób renderowania przejrzystą scenę. Czy rozwiązuje przenikające się przypadki? Nie. Czy rozwiązuje to przypadki, w których masz 3 obiekty, w których nie można ustalić kolejności głębokości? Nie. Czy rozwiązuje to przypadki, w których masz długi obiekt pokrywający się z małym, który znajduje się bliżej jego środkowej głębokości? Nie.

Ale działa wystarczająco dobrze . Gry nie używają peelingu głębinowego. Nie używają buforowanych k-buforów. Nie używają buforów F. Czemu? Ponieważ te rzeczy są niezwykle powolne.

Możesz zdobyć artefakty standardową metodą. Ale przynajmniej twoja gra działa dość szybko.

Jeśli chcesz ograniczyć się do DX11 lub lepszego sprzętu, istnieją sposoby na wdrożenie mieszania z odpowiednim sortowaniem. Są wolniejsze, ale nie tak wolne jak poprzednie techniki. I w przeciwieństwie do peelingu głębokiego, który może wprowadzać artefakty, ten jest dokładny dla próbki. Dodatkowo, wydajność algorytmu jest generalnie dla każdego fragmentu (i do pewnego stopnia nakładania się w obrębie każdego fragmentu). Więc jeśli nie narysowałeś zbyt wielu przezroczystych rzeczy, wydajność jest minimalna.

Nie wiem, czy technika ma dziwną nazwę, ale tutaj można znaleźć jedną implementację dla wersji wcześniejszej niż GL4.2. Wersja D3D11 można znaleźć tutaj (Powerpoint, ppsx, Libre kompatybilne).

Nicol Bolas
źródło
Dobre punkty tej odpowiedzi. Osobiście też zadowoliłbym się wystarczająco dobrym (co opisałem w odpowiedzi, jako obejście), ponieważ większość wymienionych przeze mnie technik jest prawdopodobnie większym problemem niż jest warta. Poza tym, interesująca technika na końcu, nie sądzę, żeby była wymieniona w Renderingu w Czasie Rzeczywistym, na który badałem moją odpowiedź. Jestem całkowitym noobem, jeśli chodzi o funkcje na poziomie DX11.
David Gouveia,
„jedno wdrożenie dla wersji wcześniejszej niż GL4.2 można znaleźć tutaj” 404
Jeroen van Langen