Jak obliczane są poziomy mipmap w metalu?

14

Moje pytanie dotyczy konkretnie Metalu, ponieważ nie wiem, czy odpowiedź zmieni się dla innego API.

Do tej pory rozumiem, że:

  • Tekstura zmapowana ma wstępnie obliczone „poziomy szczegółowości”, w których niższe poziomy szczegółowości są tworzone przez próbkowanie w dół oryginalnej tekstury w jakiś znaczący sposób.

  • Poziomy mipmap są określane w malejącym poziomie szczegółowości, gdzie poziom 0jest oryginalną teksturą, a wyższe poziomy są potęgą dwóch jego redukcji.

  • Większość procesorów graficznych implementuje filtrowanie trójliniowe, które wybiera dwa sąsiednie poziomy mipmapy dla każdej próbki, próbki z każdego poziomu za pomocą filtrowania dwuliniowego, a następnie liniowo miesza te próbki.

Nie do końca rozumiem, jak wybierane są te poziomy mipmap. W dokumentacji standardowej biblioteki Metal widzę, że można pobierać próbki z określeniem instancji lod_optionstypu lub bez niego . Zakładam, że ten argument zmienia sposób wyboru poziomów mipmap i istnieją najwyraźniej trzy rodzaje lod_optionstekstur 2D:

  • bias(float value)
  • level(float lod)
  • gradient2d(float2 dPdx, float2 dPdy)

Niestety dokumentacja nie przeszkadza w wyjaśnieniu, co robi dowolna z tych opcji. Mogę zgadywać, że bias()wpływa to na pewien automatycznie wybrany poziom szczegółowości, ale co to valueznaczy błąd? Na jakiej skali działa? Podobnie jak jest lodw level()języku dyskretnych poziomów mipmapa? I, działając przy założeniu, że gradient2d()wykorzystuje gradient współrzędnej tekstury, w jaki sposób używa tego gradientu, aby wybrać poziom mipmapy?

Co ważniejsze, jeśli pominie się lod_options, w jaki sposób wybierane są poziomy mipmap? Czy różni się to w zależności od rodzaju wykonywanej funkcji?

A jeśli domyślną operacją sample()funkcji nieokreśloną w opcjach jest wykonanie czegoś takiego gradient2D()(przynajmniej w module cieniującym fragmenty), czy wykorzystuje ona proste pochodne przestrzeni ekranu, czy też działa bezpośrednio z rasterizerem i interpolowanymi współrzędnymi tekstury obliczyć dokładny gradient?

I w końcu, jak spójne jest to zachowanie w zależności od urządzenia? Stary artykuł (stary jak w DirectX 9), który przeczytałem, dotyczył złożonego wyboru mipmap specyficznych dla urządzenia, ale nie wiem, czy wybór mipmap jest lepiej zdefiniowany w nowszych architekturach.

lcmylin
źródło

Odpowiedzi:

17

Wybór MIP jest obecnie dość dobrze ustandaryzowany na różnych urządzeniach - z wyjątkiem niektórych drobiazgowych szczegółów filtrowania anizotropowego, które wciąż są określane przez poszczególnych producentów GPU (a jego dokładne szczegóły na ogół nie są publicznie udokumentowane).

Dobrym miejscem do zapoznania się ze szczegółami wyboru mip jest specyfikacja OpenGL, sekcja 8.14, „Minimalizacja tekstury” . Zakładam, że działa tak samo w Metalu. (Apple mógł coś zmienić, biorąc pod uwagę, że produkują zarówno sprzęt, jak i interfejs API ... ale wątpię, że tak.) Podsumuję to tutaj.

Domyślny wybór mip (bez użycia żadnego z lod_optionsmodyfikatorów) wykorzystuje gradienty przestrzeni ekranowej współrzędnych tekstury do wybierania poziomów mip. Zasadniczo próbuje wybrać poziomy mip, które dają możliwie najbliższe odwzorowanie 1: 1 tekstur na piksele. Na przykład, jeśli gradienty mają długość 4 teksli na piksel, wybrałby poziom mip 2 (co stanowi 1/4 wielkości poziomu 0 i dlatego daje 1 mippowany texel na piksel).

Dzięki filtrowaniu trójliniowemu, ponieważ zwykle nie lądujesz na dokładnym odwzorowaniu 1: 1, wybiera dwa najbliższe poziomy i liniowo interpoluje między nimi, dzięki czemu masz płynne przejście między poziomami mip podczas ruchu kamery lub obiektów w scenie na około.

λλλλ=2.8

λlog2)(1/4)=-2)

Teraz, jeśli chodzi o opcje modyfikatora:

  • biasλ
  • levelλλlod
  • gradient2dpozwala wstawiać własne wektory gradientowe, które zastępują niejawne gradienty przestrzeni ekranowej współrzędnych tekstury. Reszta procesu selekcji i próbkowania mip przebiega normalnie, ale ze zmienionymi gradientami. Umożliwia to dostosowanie filtrowania anizotropowego.

W innych typach shaderów oprócz shaderów fragmentów nie ma pojęcia „gradienty w przestrzeni ekranu”, więc dwie ostatnie operacje są zwykle jedynymi dozwolonymi - każda operacja, która próbuje użyć niejawnych gradientów, dałaby błąd kompilacji. Nie jestem pewien, czy tak właśnie działa Metal, ale tego oczekiwałbym po pracy z innymi interfejsami API.

Nathan Reed
źródło