Udostępnij za pośrednictwem


Kaskadowe mapy cieni

Kaskadowe mapy cieni (CSM) to najlepszy sposób zwalczania jednego z najbardziej rozpowszechnionych błędów z cieniowaniem: aliasowanie perspektywy. Ten artykuł techniczny, który zakłada, że czytelnik jest zaznajomiony z mapowaniem w tle, zajmuje się tematem CSMs. W szczególności:

  • wyjaśnia złożoność csm;
  • zawiera szczegółowe informacje o możliwych odmianach algorytmów CSM;
  • opisuje dwie najbardziej typowe techniki filtrowania — procentowe filtrowanie bliżej (PCF) i filtrowanie za pomocą map wariancji w tle (VSM);
  • identyfikuje i rozwiązuje niektóre typowe pułapki związane z dodawaniem filtrowania do CSMs; i
  • Pokazuje, jak mapować CSM na sprzęt Direct3D 10 do Direct3D 11.

Kod używany w tym artykule można znaleźć w zestawie SDK (DirectX Software Development Kit) w przykładach CascadedShadowMaps11 i VarianceShadows11. Ten artykuł okaże się najbardziej przydatny po zaimplementowaniu technik opisanych w artykule technicznym, typowe techniki ulepszania map głębokości cienia, są implementowane.

Kaskadowe mapy cieni i aliasy perspektyw

Alias perspektywy na mapie w tle jest jednym z najtrudniejszych problemów do pokonania. W artykule technicznym opisano typowe techniki ulepszania map głębokości w tle, aliasy perspektyw i zidentyfikowano niektóre podejścia do rozwiązania problemu. W praktyce csms wydają się być najlepszym rozwiązaniem i są powszechnie stosowane w nowoczesnych grach.

Podstawowa koncepcja CSMs jest łatwa do zrozumienia. Różne obszary frustum aparatu wymagają map cieni z różnymi rozdzielczościami. Obiekty najbliższe oko wymagają wyższej rozdzielczości niż zrobić bardziej odległe obiekty. W rzeczywistości, gdy oko porusza się bardzo blisko geometrii, piksele najbliższe oko może wymagać tak dużej rozdzielczości, że nawet mapa 4096 × 4096 cieni jest niewystarczająca.

Podstawową ideą CSM jest partycjonowanie frustum na wiele frusta. Mapa w tle jest renderowana dla każdego podfrustu; cieniowanie pikseli następnie próbki z mapy, która najlepiej pasuje do wymaganej rozdzielczości (Rysunek 2).

Rysunek 1. Pokrycie mapy w tle

pokrycie mapy w tle

Na rysunku 1 jest wyświetlana jakość (od lewej do prawej) od najwyższego do najniższego. Seria siatek reprezentujących mapy cieni z widokiem frustum (odwrócony stożek na czerwono) pokazuje wpływ pokrycia pikseli na różne mapy cieni rozdzielczości. Cienie są najwyższej jakości (białe piksele), gdy na mapie cieni znajduje się 1:1 pikseli mapowania proporcji. Aliasowanie perspektywy występuje w postaci dużych map tekstur blokowych (obraz po lewej stronie), gdy zbyt wiele pikseli jest mapowane na ten sam texel cienia. Gdy mapa w tle jest zbyt duża, jest w próbce. W takim przypadku texels są pomijane, pojawiają się błyszczące artefakty i ma to wpływ na wydajność.

Rysunek 2. Jakość w tle CSM

jakości w tle csm

Rysunek 2 przedstawia wycinki z najwyższej jakości sekcji na każdej mapie w tle na rysunku 1. Mapa cienia z najbardziej umieszczonymi pikselami (u wierzchołka) jest najbliżej oka. Technicznie są to mapy o tym samym rozmiarze, z białymi i szarymi używanymi do osiągnięcia sukcesu kaskadowej mapy cieni. Biały jest idealny, ponieważ pokazuje dobre pokrycie — stosunek 1:1 dla pikseli przestrzeni oczu i texels mapy cienia.

CsMs wymagają następujących kroków na ramkę.

  1. Podziel frustum na podfrusta.

  2. Oblicz projekcję ortograficzną dla każdego podfrustu.

  3. Renderuj mapę w tle dla każdego podfrustu.

  4. Renderowanie sceny.

    1. Powiąż mapy w tle i renderuj.

    2. Cieniowania wierzchołków wykonuje następujące czynności:

      • Oblicza współrzędne tekstury dla każdego podfrustu światła (chyba że wymagana współrzędna tekstury jest obliczana w cieniatorze pikseli).
      • Przekształca i włącza wierzchołek itd.
    3. Cieniowanie pikseli wykonuje następujące czynności:

      • Określa właściwą mapę w tle.
      • Przekształca współrzędne tekstury w razie potrzeby.
      • Przykładowe kaskady.
      • Podświetla piksel.

Partycjonowanie frustum

Partycjonowanie frustum jest aktem tworzenia podfrusta. Jedną z technik dzielenia frustum jest obliczanie interwałów od zera do stu procent w kierunku Z. Każdy interwał reprezentuje następnie płaszczyznę zbliżoną do płaszczyzny i płaszczyzny dalekiej jako wartość procentową osi Z.

Rysunek 3. Wyświetlanie partycjonowanych frustums arbitralnie

wyświetl frustums partycjonowane dowolnie

W praktyce ponowne obliczanie podziałów frustum na ramkę powoduje migotanie krawędzi cienia. Ogólnie akceptowaną praktyką jest użycie statycznego zestawu interwałów kaskadowych na scenariusz. W tym scenariuszu interwał wzdłuż osi Z służy do opisywania podfrustum występującego podczas partycjonowania frustum. Określenie prawidłowych interwałów rozmiaru dla danej sceny zależy od kilku czynników.

Orientacja geometrii sceny

W odniesieniu do geometrii sceny orientacja aparatu wpływa na wybór interwału kaskadowego. Na przykład aparat bardzo blisko ziemi, taki jak kamera naziemna w grze piłkarskiej, ma inny statyczny zestaw interwałów kaskadowych niż kamera na niebie.

Rysunek 4 przedstawia różne aparaty i odpowiednie partycje. Gdy zakres Z sceny jest bardzo duży, wymagana jest większa ilość płaszczyzn podzielonych. Na przykład, gdy oko znajduje się bardzo blisko płaszczyzny naziemnej, ale odległe obiekty są nadal widoczne, konieczne może być wiele kaskad. Podzielenie frustum tak, aby więcej podziałów było blisko oka (gdzie aliasowanie perspektywy zmienia się najszybciej) jest również cenne. Gdy większość geometrii jest zgrabowana w małą sekcję (taką jak widok narzutu lub symulator lotu) frustum widoku, konieczna jest mniejsza liczba kaskad.

Rysunek 4. Różne konfiguracje wymagają różnych podziałów frustum

różne konfiguracje wymagają różnych podziałów frustum

(Po lewej) Gdy geometria ma duży zakres dynamiczny w Z, wymagana jest duża liczba kaskad. (Środkowe) Gdy geometria ma niski zakres dynamiczny w warstwie Z, nie ma korzyści z wielu frustums. (Po prawej) Gdy zakres dynamiczny jest średni, potrzebne są tylko trzy partycje.

Orientacja światła i aparatu

Macierz projekcji każdej kaskady jest ściśle dopasowana do odpowiadającego jej podfrustu. W konfiguracjach, w których kamera widokowa i kierunek światła są ortogonalne, kaskady mogą być ściśle dopasowane z niewielkimi nakładającymi się. Nakładanie się staje się większe, gdy światło i kamera widoku przechodzą do wyrównania równoległego (Rysunek 5). Gdy światło i kamera widokowa są prawie równoległe, jest nazywana "dueling frusta", i jest bardzo trudnym scenariuszem dla większości algorytmów cieniowania. Nie rzadko ogranicza światło i kamerę tak, aby ten scenariusz nie występował. CsMs działają jednak znacznie lepiej niż wiele innych algorytmów w tym scenariuszu.

Rysunek 5. Nakładanie się kaskadowo zwiększa się, gdy kierunek światła staje się równoległy z kierunkiem kamery

nakładanie się kaskadowo zwiększa się, gdy kierunek światła staje się równoległy z kierunkiem kamery

Wiele implementacji CSM używa frusta o stałym rozmiarze. Cieniowanie pikseli może używać głębokości Z do indeksowania w tablicy kaskadowych, gdy frustum jest dzielone w interwałach o stałym rozmiarze.

Obliczanie granicy View-Frustum

Po wybraniu interwałów frustum podfrusta jest tworzona przy użyciu jednego z dwóch: dopasowania do sceny i dopasowania do kaskady.

Dopasuj do sceny

Wszystkie frusta można utworzyć z tą samą płaszczyzną blisko. Wymusza to nakładanie się kaskadowo. Przykład CascadedShadowMaps11 wywołuje tę technikę dopasowaną do sceny.

Dopasuj do kaskady

Alternatywnie można utworzyć frusta z rzeczywistym interwałem partycji używanym jako płaszczyzny bliskie i dalekie. Powoduje to ostrzejsze dopasowanie, ale degenerates dopasować się do sceny w przypadku dueling frusta. Próbki CascadedShadowMaps11 nazywają tę technikę kaskadową.

Te dwie metody przedstawiono na rysunku 6. Dopasuj do odpadów kaskadowych mniej rozdzielczości. Problem z dopasowaniem do kaskady polega na tym, że projekcja ortograficzna rośnie i zmniejsza się w oparciu o orientację widoku frustum. Technika dopasowania do sceny umożliwia wypełnienie projekcji ortograficznej przez maksymalny rozmiar frustum widoku, usuwając artefakty, które pojawiają się po przesunięciu kamery widokowej. typowe techniki ulepszania map głębokości cienia dotyczą artefaktów, które pojawiają się, gdy światło porusza się w sekcji "Przenoszenie światła w przyrostach wielkości texela".

Rysunek 6. Dopasuj do sceny, a dopasuj do kaskady

dopasować do sceny i dopasować do kaskadowych

Renderowanie mapy w tle

Przykład CascadedShadowMaps11 renderuje mapy w tle w jednym dużym buforze. Dzieje się tak, ponieważ funkcja PCF na tablicach tekstur jest funkcją Direct3D 10.1. Dla każdej kaskady tworzony jest widok, który obejmuje sekcję buforu głębokości odpowiadającego tej kaskadzie. Cieniowanie pikseli o wartości null jest powiązane, ponieważ wymagana jest tylko głębokość. Na koniec prawidłowa macierz widoków i cieni jest ustawiana dla każdej kaskady, ponieważ mapy głębokości są renderowane pojedynczo w głównym buforze cienia.

Renderowanie sceny

Bufor zawierający cienie jest teraz powiązany z cieniowaniem pikseli. Istnieją dwie metody wybierania kaskady zaimplementowanej w przykładzie CascadedShadowMaps11. Te dwie metody zostały wyjaśnione przy użyciu kodu cieniującego.

wybór kaskadowy Interval-Based

Rysunek 7. Wybór kaskadowy oparty na interwałach

wyboru kaskadowego opartego na interwałach

W zaznaczeniu na podstawie interwału (Rysunek 7) cieniator wierzchołków oblicza położenie w przestrzeni światowej wierzchołka.

Output.vDepth = mul( Input.vPosition, m_mWorldView ).z;

Cieniowanie pikseli otrzymuje interpolowaną głębokość.

fCurrentPixelDepth = Input.vDepth;

Wybór kaskadowy oparty na interwałach używa porównania wektorów i produktu kropkowego w celu określenia prawidłowej kakady. CASCADE_COUNT_FLAG określa liczbę kaskad. M_fCascadeFrustumsEyeSpaceDepths_data ogranicza partycje widoku frustum. Po porównaniu wartość fComparison zawiera wartość 1, gdzie bieżący piksel jest większy niż bariera, a wartość 0, gdy bieżąca kaskada jest mniejsza. Kropka produktu sumuje te wartości do indeksu tablicy.

        float4 vCurrentPixelDepth = Input.vDepth;
        float4 fComparison = ( vCurrentPixelDepth > m_fCascadeFrustumsEyeSpaceDepths_data[0]);
        float fIndex = dot(
        float4( CASCADE_COUNT_FLAG > 0,
        CASCADE_COUNT_FLAG > 1,
        CASCADE_COUNT_FLAG > 2,
        CASCADE_COUNT_FLAG > 3)
        , fComparison );

        fIndex = min( fIndex, CASCADE_COUNT_FLAG );
        iCurrentCascadeIndex = (int)fIndex;

Po wybraniu kaskady współrzędna tekstury musi zostać przekształcona w prawidłową kaskadę.

vShadowTexCoord = mul( InterpolatedPosition, m_mShadow[iCascadeIndex] );

Ta współrzędna tekstury jest następnie używana do próbkowania tekstury ze współrzędną X i współrzędną Y. Współrzędna Z służy do porównywania końcowej głębokości.

wybór kaskadowy Map-Based

Wybór oparty na mapie (Rysunek 8) sprawdza się po czterech stronach kaskadowych, aby znaleźć najciętszą mapę obejmującą konkretny piksel. Zamiast obliczać położenie w przestrzeni światowej, cieniowanie wierzchołków oblicza położenie obszaru widoku dla każdej kaskady. Cieniowanie pikseli iteruje kaskadowo w celu skalowania i przesunięcia współrzędnych tekstury, aby indeksować bieżącą kaskadę. Współrzędna tekstury jest następnie testowana względem granic tekstury. Gdy wartości X i Y współrzędnych tekstury spadną wewnątrz kaskady, są one używane do próbkowania tekstury. Współrzędna Z służy do porównywania końcowej głębokości.

Rysunek 8. Wybór kaskadowy oparty na mapie

wyboru kaskadowego opartego na mapie

wybór Interval-Based a wybór Map-Based

Wybór oparty na interwałach jest nieco szybszy niż wybór oparty na mapie, ponieważ wybór kaskadowy można wykonać bezpośrednio. Wybór oparty na mapie musi przecinać współrzędną tekstury z granicami kaskadowymi.

Wybór oparty na mapie wykorzystuje kaskadę wydajniej, gdy mapy w tle nie są idealnie wyrównane (patrz Rysunek 8).

Mieszanie między kaskadami

VsMs (omówione w dalszej części tego artykułu) i techniki filtrowania, takie jak PCF, mogą służyć do tworzenia nietrwałych cieni CSM o niskiej rozdzielczości. Niestety powoduje to widoczne szwy (Rysunek 9) między warstwami kaskadowymi, ponieważ rozdzielczość nie jest zgodna. Rozwiązaniem jest utworzenie przedziału między mapami w tle, w których test w tle jest wykonywany dla obu kaskad. Cieniowanie następnie interpoluje liniowo między dwiema wartościami na podstawie lokalizacji piksela w pasmie mieszanym. Przykłady CascadedShadowMaps11 i VarianceShadows11 zapewniają suwak graficzny interfejsu użytkownika, którego można użyć do zwiększenia i zmniejszenia tego rozmycia. Cieniowania wykonuje gałąź dynamiczną, tak aby zdecydowana większość pikseli odczytywała tylko z bieżącej kaskady.

Rysunek 9. Kaskadowe szwy

kaskadowych szwów

(Po lewej) Widoczne szwy można zobaczyć, gdzie kaskady nakładają się. (Po prawej) Gdy kaskady są mieszane między nimi, nie ma szwu.

Filtrowanie map w tle

PCF

Filtrowanie zwykłych map w tle nie powoduje miękkiego, rozmytego cienia. Sprzęt filtrujący rozmywa wartości głębokości, a następnie porównuje te rozmyte wartości z texelem przestrzeni lekkiej. Twarda krawędź wynikająca z testu pass/fail nadal istnieje. Rozmyte mapy cieni służą tylko do błędnego przenoszenia twardej krawędzi. Funkcja PCF umożliwia filtrowanie na mapach w tle. Ogólną ideą PCF jest obliczenie procentu piksela w cieniu na podstawie liczby podprzykładów, które przechodzą test głębokości na łączną liczbę podprzykładów.

Sprzęt Direct3D 10 i Direct3D 11 może wykonywać PCF. Dane wejściowe do próbkatora PCF składają się ze współrzędnych tekstury i wartości głębokości porównania. Dla uproszczenia funkcja PCF jest objaśniona za pomocą filtru czterociągowego. Próbkator tekstury odczytuje teksturę cztery razy, podobnie jak standardowy filtr. Jednak zwrócony wynik jest procentem pikseli, które przeszły test głębokości. Rysunek 10 pokazuje, jak piksel, który przechodzi jeden z czterech testów głębokości, wynosi 25 procent w cieniu. Zwracana wartość rzeczywista jest interpolacją liniową opartą na współrzędnych podtexelu odczytów tekstury w celu uzyskania płynnego gradientu. Bez tej interpolacji liniowej czterociętrowa funkcja PCF będzie mogła zwrócić tylko pięć wartości: { 0.0, 0.25, 0.5, 0.75, 1.0 }.

Rysunek 10. Przefiltrowany obraz PCF z 25 procentami zaznaczonego piksela

przefiltrowany obraz pcf z 25 procentami zaznaczonego piksela pokrytego

Można również wykonać PCF bez obsługi sprzętu lub rozszerzyć PCF na większe jądra. Niektóre techniki są nawet próbkowane z ważonym jądrem. W tym celu utwórz jądro (na przykład Gaussian) dla siatki N × N. Wagi muszą się sumować do 1. Tekstura jest następnie próbkowana N2 razy. Każda próbka jest skalowana według odpowiednich wag w jądrze. Przykład CascadedShadowMaps11 używa tego podejścia.

Odchylenie głębokości

Stronnicza odchylenie głębokości staje się jeszcze ważniejsze, gdy są używane duże jądra PCF. Ważne jest tylko, aby porównać głębokość światła piksela z pikselem, który mapuje na mapę głębokości. Sąsiedzi mapy głębokości texel odnoszą się do innej pozycji. Ta głębokość może być podobna, ale może być bardzo różna w zależności od sceny. Rysunek 11 wyróżnia artefakty, które występują. Pojedyncza głębokość jest porównywana z trzema sąsiednimi texelami na mapie cienia. Jeden z testów głębokości błędnie kończy się niepowodzeniem, ponieważ jego głębokość nie jest skorelowana z obliczoną głębokością światła bieżącej geometrii. Zalecanym rozwiązaniem tego problemu jest użycie większego przesunięcia. Zbyt duży przesunięcie może jednak spowodować Peter Panning. Obliczanie mocno bliskiej płaszczyzny i dalekiej płaszczyzny pomaga zmniejszyć skutki korzystania z przesunięcia.

Rysunek 11. Błędne samociemnianie

błędne samodzielnego cieniowania

Błędne samociemniające wyniki z porównywania pikseli w głębi przestrzeni światła do texels na mapie cieni, które nie są skorelowane. Głębokość w świetle jest skorelowana z cieniem texel 2 na mapie głębokości. Texel 1 jest większy niż głębokość światła, podczas gdy 2 jest równe, a 3 jest mniejsze. Texels 2 i 3 przechodzą test głębokości, podczas gdy Texel 1 kończy się niepowodzeniem.

Obliczanie stronniczości głębokości Per-Texel za pomocą DDX i DDY dla dużych plików PCFs

Obliczanie stronniczości głębokości na texel z ddx i ddy dla dużych plików PCFs jest techniką, która oblicza poprawną stronniczość głębokości — przy założeniu, że powierzchnia jest planarna — dla sąsiedniego texelu mapy cienia.

Ta technika pasuje do głębokości porównania do płaszczyzny przy użyciu informacji pochodnych. Ponieważ ta technika jest złożona obliczeniowo, powinna być używana tylko wtedy, gdy procesor GPU ma cykle obliczeniowe do stracenia. Gdy są używane bardzo duże jądra, może to być jedyna technika, która działa w celu usunięcia artefaktów z cieniem własnym bez powodowania Peter Panning.

Rysunek 12 podkreśla problem. Głębokość światła jest znana z jednego texel, który jest porównywany. Głębokości przestrzeni lekkiej, które odpowiadają sąsiednim texelsom na mapie głębokości, są nieznane.

Rysunek 12. Mapa sceny i głębokości

sceny i mapy głębokości

Renderowana scena jest wyświetlana po lewej stronie, a mapa głębokości z blokiem texel próbki jest wyświetlana po prawej stronie. Przestrzeń oczu texel mapuje na piksel oznaczony etykietą D w środku bloku. To porównanie jest dokładne. Prawidłowa głębokość w przestrzeni oczu korelujące z pikselami, które sąsiedzi D są nieznane. Mapowanie sąsiednich texels z powrotem na przestrzeń oczu jest możliwe tylko wtedy, gdy zakładamy, że piksel odnosi się do tego samego trójkąta co D.

Głębokość jest znana z texelu, który koreluje z położeniem światła. Głębokość jest nieznana dla sąsiednich texels na mapie głębokości.

Na wysokim poziomie ta technika używa ddx i ddy operacji HLSL w celu znalezienia pochodnej pozycji światła. Nie jest totrivial, ponieważ operacje pochodne zwracają gradient głębokości przestrzeni lekkiej w odniesieniu do przestrzeni ekranu. Aby przekonwertować tę wartość na gradient głębokości przestrzeni lekkiej w odniesieniu do przestrzeni lekkiej, należy obliczyć macierz konwersji.

Wyjaśnienie z kodem cieniowania

Szczegóły pozostałej części algorytmu są podane jako wyjaśnienie kodu cieniującego, który wykonuje tę operację. Ten kod można znaleźć w przykładzie CascadedShadowMaps11. Rysunek 13 przedstawia sposób mapowania współrzędnych tekstury światła na mapę głębokości oraz sposobu użycia pochodnych w kodzie X i Y do utworzenia macierzy transformacji.

Rysunek 13. Obszar ekranu do macierzy jasnej przestrzeni

miejsca na ekranie do macierzy światła

Pochodne pozycji światła w X i Y są używane do tworzenia tej macierzy.

Pierwszym krokiem jest obliczenie pochodnej pozycji odstępu w widoku światła.

          float3 vShadowTexDDX = ddx (vShadowMapTextureCoordViewSpace);
          float3 vShadowTexDDY = ddy (vShadowMapTextureCoordViewSpace);

Procesory GPU klasy Direct3D 11 obliczają te pochodne, uruchamiając 2 × 2 czworokąt pikseli równolegle i odejmując współrzędne tekstury od sąsiada w X dla ddx i od sąsiada w Y dla ddy. Te dwa pochodne składają się na wiersze macierzy 2 × 2. W bieżącej formie ta macierz może służyć do konwertowania pikseli sąsiednich przestrzeni ekranu na nachylenia przestrzeni lekkiej. Jednak odwrotność tej macierzy jest wymagana. Potrzebna jest macierz, która przekształca piksele sąsiadujące z światłem na nachylenie przestrzeni ekranu.

          float2x2 matScreentoShadow = float2x2( vShadowTexDDX.xy, vShadowTexDDY.xy );
          float fInvDeterminant = 1.0f / fDeterminant;

          float2x2 matShadowToScreen = float2x2 (
          matScreentoShadow._22 * fInvDeterminant,
          matScreentoShadow._12 * -fInvDeterminant,
          matScreentoShadow._21 * -fInvDeterminant,
          matScreentoShadow._11 * fInvDeterminant );

Rysunek 14. Odstęp na ekranie

światło na ekran

Macierz ta jest następnie używana do przekształcania dwóch texelów powyżej i po prawej stronie obecnego texelu. Sąsiedzi są reprezentowani jako przesunięcie z obecnego texelu.

          float2 vRightShadowTexelLocation = float2( m_fTexelSize, 0.0f );
          float2 vUpShadowTexelLocation = float2( 0.0f, m_fTexelSize );
          float2 vRightTexelDepthRatio = mul( vRightShadowTexelLocation,
          matShadowToScreen );
          float2 vUpTexelDepthRatio = mul( vUpShadowTexelLocation,
          matShadowToScreen );

Współczynnik tworzony przez macierz jest ostatecznie mnożony przez pochodne głębokości w celu obliczenia przesunięcia głębokości dla sąsiednich pikseli.

            float fUpTexelDepthDelta =
            vUpTexelDepthRatio.x * vShadowTexDDX.z
            + vUpTexelDepthRatio.y * vShadowTexDDY.z;
            float fRightTexelDepthDelta =
            vRightTexelDepthRatio.x * vShadowTexDDX.z
            + vRightTexelDepthRatio.y * vShadowTexDDY.z;

Te wagi można teraz używać w pętli PCF, aby dodać przesunięcie do pozycji.

    for( int x = m_iPCFBlurForLoopStart; x < m_iPCFBlurForLoopEnd; ++x ) 
    {
        for( int y = m_iPCFBlurForLoopStart; y < m_iPCFBlurForLoopEnd; ++y )
            {
            if ( USE_DERIVATIVES_FOR_DEPTH_OFFSET_FLAG )
            {
            depthcompare += fRightTexelDepthDelta * ( (float) x ) +
            fUpTexelDepthDelta * ( (float) y );
            }
            // Compare the transformed pixel depth to the depth read
            // from the map.
            fPercentLit += g_txShadow.SampleCmpLevelZero( g_samShadow,
            float2(
            vShadowTexCoord.x + ( ( (float) x ) * m_fNativeTexelSizeInX ) ,
            vShadowTexCoord.y + ( ( (float) y ) * m_fTexelSize )
            ),
            depthcompare
            );
            }
     }

PCF i CSMs

PcF nie działa na tablicach tekstur w direct3D 10. Aby korzystać z PCF, wszystkie kaskady są przechowywane w jednym dużym atlasie tekstur.

przesunięcie Derivative-Based

Dodanie przesunięć opartych na pochodnych dla csms stwarza pewne wyzwania. Jest to spowodowane obliczeniami pochodnymi w ramach sterowania przepływem rozbieżnym. Problem występuje z powodu podstawowego sposobu działania procesorów GPU. Procesory GPU Direct3D11 działają na 2 × 2 czworokątach pikseli. Aby wykonać pochodną, procesory GPU zazwyczaj odejmuje kopię bieżącego piksela zmiennej z kopii tej samej zmiennej w sąsiednim pikselu. Jak tak się dzieje, różni się od procesora GPU do procesora GPU. Współrzędne tekstury są określane przez wybór kaskadowy oparty na mapie lub interwałach. Niektóre piksele w czworokącie pikseli wybierają inną kaskadę niż reszta pikseli. Powoduje to widoczne szwy między mapami cieni, ponieważ przesunięcia na podstawie pochodnych są teraz całkowicie błędne. Rozwiązaniem jest wykonanie pochodnej na współrzędnych tekstury przestrzeni w widoku światła. Te współrzędne są takie same dla każdej kaskady.

Dopełnianie dla jądra PCF

Indeks jądra PCF poza partycją kaskadową, jeśli bufor w tle nie jest dopełniony. Rozwiązaniem jest wypełnienie zewnętrznej krawędzi kaskady o połowę rozmiaru jądra PCF. Należy to zaimplementować w cieniatorze, który wybiera kaskadę i macierz projekcji, która musi renderować kaskadowo wystarczająco duże, że obramowanie jest zachowywane.

Mapy wariancji w tle

VsMs (zobacz mapy wariancji w tle przez Donnelly i Lauritzen, aby uzyskać więcej informacji) umożliwiają bezpośrednie filtrowanie map w tle. W przypadku korzystania z programu VSM można używać wszystkich możliwości sprzętu filtrowania tekstur. Można użyć filtrowania trójliniowego i anisotropowego (Rysunek 15). Ponadto maszyny VSM mogą być rozmyte bezpośrednio przez splot. Maszyny VSM mają pewne wady; Należy przechowywać dwa kanały danych głębokości (głębokość i głębokość kwadratowa). Gdy cienie nakładają się, krwawiące światło jest powszechne. Działają one dobrze, jednak z niższymi rozdzielczościami i mogą być łączone z CSMs.

Rysunek 15. Filtrowanie anisotropowe

filtrowanie anisotropowe

Szczegóły algorytmu

Maszyny VSM działają, renderując głębokość i głębokość kwadratową do mapy w tle dwukanałowej. Ta dwukanałowa mapa w tle może być następnie rozmyta i filtrowana tak jak zwykła tekstura. Następnie algorytm używa nierówności Czebyszewa w cieniatorze pikseli, aby oszacować ułamek obszaru pikseli, który przejdzie test głębokości.

Cieniowanie pikseli pobiera wartości głębokości i głębokości kwadratu.

        float  fAvgZ  = mapDepth.x; // Filtered z
        float  fAvgZ2 = mapDepth.y; // Filtered z-squared

Wykonywane jest porównanie głębokości.

        if ( fDepth <= fAvgZ )
        {
        fPercentLit = 1;
        }

Jeśli porównanie głębokości zakończy się niepowodzeniem, szacowany jest procent oświetlonego piksela. Wariancja jest obliczana jako średnia kwadratów pomniejszona o kwadrat średniej.

        float variance = ( fAvgZ2 ) − ( fAvgZ * fAvgZ );
        variance = min( 1.0f, max( 0.0f, variance + 0.00001f ) );

Wartość fPercentLit jest szacowana z nierównością Czebyszewa.

        float mean           = fAvgZ;
        float d              = fDepth - mean;
        float fPercentLit    = variance / ( variance + d*d );

Jasne krwawienie

Największą wadą vsMs jest lekkie krwawienie (Rysunek 16). Lekkie krwawienie występuje, gdy wiele cieni kacytuje się nawzajem wzdłuż krawędzi. VsMs cieniuje krawędzie cieni w oparciu o różnice głębokości. Gdy cienie nakładają się na siebie, różnica głębokości istnieje w środku regionu, który powinien być cieniowany. Jest to problem z użyciem algorytmu VSM.

Rysunek 16. Krwawienie lekkie VSM

vsm lekkie krwawienie

Częściowym rozwiązaniem problemu jest podniesienie parametru fPercentLit do zasilania. Ma to wpływ na tłumienie rozmycia, co może spowodować artefakty, w których różnica głębokości jest niewielka. Czasami istnieje magiczną wartość, która złagodzi problem.

fPercentLit = pow( p_max, MAGIC_NUMBER );

Alternatywą dla podniesienia procentu oświetlonego do zasilania jest uniknięcie konfiguracji, w których nakładają się cienie. Nawet wysoce dostrojone konfiguracje cieni mają kilka ograniczeń dotyczących światła, kamery i geometrii. Lekkie krwawienie jest również zmniejszane przy użyciu tekstur o wyższej rozdzielczości.

Mapy cieni wariancji warstwowej (LVSMs) rozwiązują problem kosztem zerwania frustum na warstwy, które są prostopadłe do światła. Wymagana liczba map byłaby dość duża, gdy są również używane maszyny CSM.

Ponadto Andrew Lauritzen, współautor artykułu w programie VSMs i autor artykułu na LVSMs, omówił łączenie map cieni wykładniczych (ESMs) z vsMs w celu przeciwdziałania połączeniu światła w Beyond3D Forum.

VsMs z csms

Przykładowa VarianceShadow11 łączy maszyny VSM i CSM. Połączenie jest dość proste. Przykład wykonuje te same kroki co przykład CascadedShadowMaps11. Ponieważ PCF nie jest używany, cienie są rozmyte w dwuprzepustowej konwolucji. Nieużywanie struktury PCF umożliwia również przykładowi używanie tablic tekstur zamiast atlasu tekstur. PcF na tablicach tekstur jest funkcją Direct3D 10.1.

Gradienty z csms

Użycie gradientów z CSM może spowodować utworzenie szwu wzdłuż obramowania między dwoma kaskadami, jak pokazano na rysunku 17. Przykładowa instrukcja używa pochodnych między pikselami, aby obliczyć informacje, takie jak poziom mipmap, wymagane przez filtr. Powoduje to problem w szczególności w przypadku zaznaczenia mapy mipmap lub filtrowania anisotropowego. Gdy piksele w czworokącie przyjmują różne gałęzie w cieniowaniach, pochodne obliczane przez sprzęt procesora GPU są nieprawidłowe. Powoduje to poszarpane szwy wzdłuż mapy cienia.

Rysunek 17. Szwy na obramowaniach kaskadowych ze względu na filtrowanie anisotropowe z sterowaniem przepływem rozbieżnym

szwy na krawędziach kaskadowych ze względu na filtrowanie anisotropowe z przepływu rozbieżnego

Ten problem jest rozwiązywany przez obliczenie pochodnych na pozycji w przestrzeni światła; współrzędna przestrzeni w widoku światła nie jest specyficzna dla wybranej kaskady. Obliczone pochodne można skalować według części skali macierzy tekstury projekcji do poprawnego poziomu mipmap.

        float3 vShadowTexCoordDDX = ddx( vShadowMapTextureCoordViewSpace );
        vShadowTexCoordDDX *= m_vCascadeScale[iCascade].xyz;
        float3 vShadowTexCoordDDY = ddy( vShadowMapTextureCoordViewSpace );
        vShadowTexCoordDDY *= m_vCascadeScale[iCascade].xyz;

        mapDepth += g_txShadow.SampleGrad( g_samShadow, vShadowTexCoord.xyz,
        vShadowTexCoordDDX, vShadowTexCoordDDY );

VsMs w porównaniu do standardowych cieni z PCF

Zarówno vsMs, jak i PCF próbują przybliżyć ułamek obszaru pikseli, który przeszedłby test głębokości. Maszyny VSM współpracują ze sprzętem filtrowania i mogą być rozmyte za pomocą separowalnych jąder. Jądra konwoju z możliwością separacji są znacznie tańsze do zaimplementowania niż pełne jądro. Ponadto program VSM porównuje jedną głębokość przestrzeni lekkiej z jedną wartością na mapie głębokości przestrzeni lekkiej. Oznacza to, że maszyny VSM nie mają tych samych problemów z przesunięciem co PCF. Technicznie maszyny VSM mają głębokość próbkowania w większym obszarze, a także przeprowadzają analizę statystyczną. Jest to mniej precyzyjne niż PCF. W praktyce maszyny VSM wykonują bardzo dobrą robotę łączenia, co powoduje, że konieczne jest mniejsze przesunięcie. Jak opisano powyżej, wadą numer jeden do VSMs jest lekkie krwawienie.

VsMs i PCF reprezentują kompromis między mocą obliczeniową procesora GPU a przepustowością tekstur procesora GPU. Maszyny VSM wymagają wykonania większej liczby obliczeń matematycznych w celu obliczenia wariancji. PcF wymaga większej przepustowości pamięci tekstury. Duże jądra PCF mogą szybko stać się wąskim gardłem przez przepustowość tekstury. W przypadku zwiększania mocy obliczeniowej procesora GPU szybciej niż przepustowość procesora GPU, maszyny VSM stają się bardziej praktyczne w dwóch algorytmach. Maszyny VSM również wyglądają lepiej z mapami cieni o niższej rozdzielczości z powodu mieszania i filtrowania.

Streszczenie

CsMs oferują rozwiązanie problemu z aliasowaniem perspektywy. Istnieje kilka możliwych konfiguracji umożliwiających uzyskanie wymaganej wierności wizualnej dla tytułu. Komputery PCF i VSM są powszechnie używane i powinny być łączone z csms w celu zmniejszenia aliasów.

Odwołania

Mapy cieni Donnelly, W. i Lauritzen, A. Variance shadow. W SI3D '06: Proceedings of the 2006 sympozjum on Interactive 3D graphics and games. 2006. pp. 161–165. Nowy Jork, NY, USA: ACM Press.

Lauritzen, Andrew i McCool, Michael. warstwowe mapy wariancji w tle. Postępowanie nad interfejsem graficznym 2008, 28–30 maja 2008, Windsor, Ontario, Kanada.

Engel, Woflgang F. Sekcja 4. Kaskadowe mapy cieni. ShaderX5 , Advanced Rendering Techniques, Wolfgang F. Engel, Ed. Charles River Media, Boston, Massachusetts. 2006. s. 197–206.