artykuły

Variable Rate Shading – zgrubne cieniowanie w DirectX i nowych konsolach

31
16 kwietnia 2020, 14:01 Mateusz Brzostek

Zgrubne cieniowanie

Zgrubne cieniowanie (coarse rate shading) jest w pewnym sensie odwrotnością lub rozszerzeniem wygładzania krawędzi MSAA w przeciwnym kierunku. Zamiast próbkować geometrię częściej niż co jeden piksel, można próbkować kolor rzadziej niż co jeden piksel.

Rasteryzacja jest przeprowadzana z pełną rozdzielczością: jedna próbka pokrycia na jeden piksel ekranu. Odwzorowanie krawędzi i niewielkich obiektów jest tak samo dobre, jak w renderowaniu z natywną rozdzielczością. Jednak kolor jest obliczany rzadziej – na przykład tylko jeden raz dla czterech sąsiadujących pikseli:

Zgrubne cieniowanie 1 raz na 4 piksele

Próbki koloru są obliczane tylko raz na cztery piksele, a ich kolor rozprzestrzeniany na wszystkie piksele, w których próbka pokrycia „trafiła” w obiekt:

Zgrubne cieniowanie 1 raz na 4 piksele

Pokazana powyżej 1 próbka koloru na 4 piksele ekranu to tylko przykład. W nowoczesnych GPU i API przewidziano różne rozdzielczości cieniowania. Dla każdej możemy sobie wyobrazić „dokładne” piksele odpowiadające rozdzielczości ekranu oraz „zgrubne” piksele odpowiadające najmniejszej części ekranu, która może mieć unikalny kolor. Te „zgrubne” piksele mogą być 2 razy większe, 4 razy większe, 8 razy większe lub 16 razy większe:

Variable Rate Shading

Variable w nazwie tej techniki oznacza, że rozdzielczość cieniowania zmienia się w ramach jednej klatki. Można to zrobić na różne sposoby: za pomocą mapy ekranu lub osobno dla każdego polecenia rysowania (draw call).

W trybie mapy ekranu tworzy się teksturę-maskę, która służy do określenia, który segment ekranu ma być cieniowany z jaką rozdzielczością. Segmenty mogą mieć rozmiar 8×8, 16×16 lub 32×32 piksele. Wewnątrz takiego kwadratu wszystkie obiekty będą cieniowane z wybraną rozdzielczością. Te metodę wykorzystano w Wolfenstein II: The New Colossus (więcej informacji na następnej stronie).

Żeby najlepiej wykorzystać VRS w trybie mapy ekranu, trzeba dodać do tej techniki jakiś czynnik temporalny. Nie można ocenić, która część obecnej klatki jest ważna i pełna szczegółów, dopóki nie wygenerujemy jej go końca. Można za to założyć, że poprzednia klatka była dość podobna, i zaczerpnąć tę informację z poprzedniej klatki. Można też wykorzystać informacje o położeniu obiektów z poprzedniej klatki – te, które znacząco zmieniły pozycję szybko się poruszają, więc mogą być cieniowane ze zmniejszoną dokładnością. Informacje o ruchu są zwykle dostępne „za darmo”, bo mapa wektorów ruchu jest i tak obliczana na potrzeby efektu rozmycia (motion blur). 

Rozdzielczość cieniowania można też ustawić oddzielnie dla każdego polecenia rysowania. Draw call – polecenie rysowania – zwykle odpowiada jednej bryle geometrycznej pokrytej jedną teksturą. Jeden złożony model może wymagać wielu poleceń rysowania, ale proste bryły i efekty (a nawet kilka prostych, identycznych obiektów) mogą odpowiadać jednemu poleceniu.

Ustawianie zgrubnego cieniowania osobno dla każdej bryły lub draw call może być niezależne od jakichkolwiek dodatkowych informacji i nie wymaga podawania dalej czegokolwiek z poprzedniej klatki. Może też dawać znacznie lepszą jakość obrazu i większy zysk wydajności, ale wymaga dostosowania do konkretnej gry lub silnika graficznego. Jakość cieniowania można dostosować do:

  • treści obrazu – mało szczegółowe tekstury lub takie, które mają niewielki wkład w końcowy obraz (np. maski efektów postprodukcyjnych) można oznaczyć jako nadające się do zgrubnego cieniowania
  • efektów rozmycia, odbić, załamań – jeśli obraz jakiegoś obiektu będzie i tak mocno zniekształcony np. przez głębię ostrości, można go cieniować z niską rozdzielczością
  • istotności obiektu – jeśli reżyser pewnej sceny wie, że wzrok obserwatora będzie skierowany na pewne istotne elementy sceny, może mniej ważne elementy przygotować do cieniowania z niską rozdzielczością

To wymaga pewnej wiedzy i zaangażowania nie tylko od programistów, ale i od artystów, ale pozwala najlepiej uniknąć zbyt zgrubnego cieniowania istotnych, rzucających się w oczy elementów lub zbyt dokładnego cieniowania czegoś, co i tak pozostanie niezauważone. Pomagające w tym mechanizmy powinny być wbudowane w narzędzia do pracy z silnikiem graficznym. Na przykład Unreal Engine 4 umożliwia manipulowanie rozdzielczością cieniowania w zależności od nałożonej na obiekt tekstury.

3