Advanced Soft Shadows Michał Drobot Technical Art Director Reality Pump
Optymalizacja samplowaniaOptymalizacja samplowania PCFPCF JitteringJittering Fixed Size PenumbraFixed Size Penumbra VSMVSM CSMCSM ESMESM Variable-Size PenumbraVariable-Size Penumbra PCSSPCSS InneInne Plan wykładu
AntialiasingAntialiasing Filtrowanie krawędzi cieniaFiltrowanie krawędzi cienia AnizotropiaAnizotropia Ukrywanie zbyt małej rozdzielczości shadow mapyUkrywanie zbyt małej rozdzielczości shadow mapy Światła obszaroweŚwiatła obszarowe Rzucają penumbrę ze zmienną wielkościąRzucają penumbrę ze zmienną wielkością Cień ostrzejszy w miejscu kontaktuCień ostrzejszy w miejscu kontaktu Miękkie cienie
Shadow mappingShadow mapping Najłatwiejsza implementacja miękkich cieniNajłatwiejsza implementacja miękkich cieni Oparta na przestrzeni obrazuOparta na przestrzeni obrazu Działa z dowolną rasteryzowalną geometriąDziała z dowolną rasteryzowalną geometrią Inne technikiInne techniki Stencil shadowsStencil shadows Wymaga rasteryzacji cienia i operacji na obrazieWymaga rasteryzacji cienia i operacji na obrazie KosztowneKosztowne 2 przebiegi2 przebiegi Metody oparte na analizie sylwetkiMetody oparte na analizie sylwetki Dokładne lecz kosztowne obliczeniowo lub pamięciowoDokładne lecz kosztowne obliczeniowo lub pamięciowo Miękkie cienie
Shadow mappingShadow mapping Najłatwiejsza implementacja miękkich cieniNajłatwiejsza implementacja miękkich cieni Oparta na przestrzeni obrazuOparta na przestrzeni obrazu Działa z dowolną rasteryzowalną geometriąDziała z dowolną rasteryzowalną geometrią Inne technikiInne techniki Stencil shadowsStencil shadows Wymaga rasteryzacji cienia i operacji na obrazieWymaga rasteryzacji cienia i operacji na obrazie KosztowneKosztowne 2 przebiegi2 przebiegi Metody oparte na analizie sylwetkiMetody oparte na analizie sylwetki Dokładne lecz kosztowne obliczeniowo lub pamięciowoDokładne lecz kosztowne obliczeniowo lub pamięciowo Miękkie cienie
Shadow mapa przechowuje dystans Z do źródła światłaShadow mapa przechowuje dystans Z do źródła światła Pytany punkt P jest oświetlony jeśli d < zPytany punkt P jest oświetlony jeśli d < z Shadow mapping P z d
PCF
PCF
Sampluj wynik (d < z) dookoła odczytywanego punktuSampluj wynik (d < z) dookoła odczytywanego punktu Przefiltruj binarne wyniki testu cieniaPrzefiltruj binarne wyniki testu cienia Bilinearny BCFBilinearny BCF Sprzętowa funkcja 2x2 PCF w kartach NvidiiSprzętowa funkcja 2x2 PCF w kartach Nvidii Ati Fetch 4Ati Fetch 4 Użyj miejsca samplowania oraz wagi jak przy filtrowaniu bilinearnymUżyj miejsca samplowania oraz wagi jak przy filtrowaniu bilinearnym PCF
Możliwość użycia kerneli przy samplowaniuMożliwość użycia kerneli przy samplowaniu GaussGauss … Kernele mogą wykorzystywać filtrowanie sprzętoweKernele mogą wykorzystywać filtrowanie sprzętowe Np. filtrowanie obszary 4x4 przy użyciu 4 sampli sprzętowychNp. filtrowanie obszary 4x4 przy użyciu 4 sampli sprzętowych PCF
Zwiększenie ilości sampli oraz ich zasięgu wpływa naZwiększenie ilości sampli oraz ich zasięgu wpływa na Miękkość cieniaMiękkość cienia Większy obszar penumbryWiększy obszar penumbry JakośćJakość Mniejszy banding poprzez większą gradacje szarośćiMniejszy banding poprzez większą gradacje szarośći Stopnie szarości = ilość sampliStopnie szarości = ilość sampli PCF
Różne kerneleRóżne kernele PCF
Float fsize = shadowMapRes * width; for (int i = 0; i<SAMPLES_COUNT; i++) { smCoord.xy = offsets[i] * fsize + shadowMapPos; shadow += texture2DProj(shadowMap, smCoord) * INV_SAMPLES_COUNT; } PCF
Metody Monte Carlo do obliczenia wyniku cieniowaniaMetody Monte Carlo do obliczenia wyniku cieniowania Funkcja określonej liczby, losowo zadanych testów shadow mapyFunkcja określonej liczby, losowo zadanych testów shadow mapy Uśredniona wartość sumy odwzorowuje całkę po całym zbiorze testówUśredniona wartość sumy odwzorowuje całkę po całym zbiorze testów Jittering
Samplujemy shadow mapę w innych losowych miejsca dla każdego miejsca liczenia cieniaSamplujemy shadow mapę w innych losowych miejsca dla każdego miejsca liczenia cienia Błąd aproksymacji odmienny dla każdego pixelaBłąd aproksymacji odmienny dla każdego pixela Zamieniamy banding na wysoko częstotliwościowy szumZamieniamy banding na wysoko częstotliwościowy szum Ludzkie oko łatwiej filtruje szum niż błędy gradientuLudzkie oko łatwiej filtruje szum niż błędy gradientu Błąd pozostaje, lecz jest lepiej maskowanyBłąd pozostaje, lecz jest lepiej maskowany Jittering
Jittering
Losowość wg odpowiednio zadanej dystrybucjiLosowość wg odpowiednio zadanej dystrybucji Rozkład normalnyRozkład normalny Zbyt duża nierównomierność rozkładuZbyt duża nierównomierność rozkładu Rozkład poissonaRozkład poissona Umożliwia ograniczenie losowościUmożliwia ograniczenie losowości Większa stabilność szumuWiększa stabilność szumu Jittering
Rozkłady mieszaneRozkłady mieszane Ustalenie stałych obszarów samplowania i ustalanie losowych odchyleń wewnątrz obszaruUstalenie stałych obszarów samplowania i ustalanie losowych odchyleń wewnątrz obszaru Zapewnia równomierność rozkładu przy zachowaniu zalet losowościZapewnia równomierność rozkładu przy zachowaniu zalet losowości StratificationStratification Jittering po obszarze dyskuJittering po obszarze dysku Generujemy siatkę punktówGenerujemy siatkę punktów Każdy punkt odchylamy o losową wartość wewnątrz jego komórkiKażdy punkt odchylamy o losową wartość wewnątrz jego komórki Zawijamy siatkę do przestrzeni dyskuZawijamy siatkę do przestrzeni dysku Jittering
StratificationStratification Wygenerowanie jitterowanej siatkiWygenerowanie jitterowanej siatki WrapowanieWrapowanie X = sqrt(v) * cos(2 * PI * u)X = sqrt(v) * cos(2 * PI * u) Y = sqrt(v) * sin(2 * PI * u)Y = sqrt(v) * sin(2 * PI * u) U,V : [0..1] w przestrzeni siatki kwadratowejU,V : [0..1] w przestrzeni siatki kwadratowej X,Y – pozycje samplowania w przestrzeni dyskuX,Y – pozycje samplowania w przestrzeni dysku Jittering
Punkty samplowania pregenerujemyPunkty samplowania pregenerujemy Zapisujemy w teksturze 3DZapisujemy w teksturze 3D 8 – bit8 – bit Postać znormalizowanaPostać znormalizowana dla offsetów na dysku dla offsetów na dysku Korzystamy z 4 kanałówKorzystamy z 4 kanałów RG - pierwszy offset, BA – drugi offsetRG - pierwszy offset, BA – drugi offset Teksturę adresujemy z tile-owaniemTeksturę adresujemy z tile-owaniem Z – kolejne unikatowe sekwencje jitterowanych sampliZ – kolejne unikatowe sekwencje jitterowanych sampli Z uzależnione od ilości sampli jakie chcemy pobraćZ uzależnione od ilości sampli jakie chcemy pobrać X, Y – mapowane przez koordynaty w przestrzeni obrazu, punktów dla których liczymy cieniowanieX, Y – mapowane przez koordynaty w przestrzeni obrazu, punktów dla których liczymy cieniowanie Wielkość wyznacza region niepowtarzający się sekwencjiWielkość wyznacza region niepowtarzający się sekwencji Jittering
for (int i = 0; i<SAMPLES_COUNT_DIV_2 - 4; i++) { vec4 offset = texture3D(jitter, jcoord); jcoord.z += 1.0f / SAMPLES_COUNT_DIV_2; smCoord.xy = offset.xy * fsize + shadowMapPos; shadow += texture2DProj(shadowMap, smCoord)* INV_SAMPLES_COUNT; smCoord.xy = offset.zw * fsize + shadowMapPos; shadow += texture2DProj(shadowMap, smCoord)* INV_SAMPLES_COUNT; } Jittering
DitheringDithering Najprostsza dystrybucjaNajprostsza dystrybucja 2 zbiory miejsc samplowań, alternujące się dla pixelu wg schematu szachownicy2 zbiory miejsc samplowań, alternujące się dla pixelu wg schematu szachownicy Szybkość przy stosunkowo dobrej jakościSzybkość przy stosunkowo dobrej jakości Jittering Pixel ekranu parzysty Pixel ekranu nieparzysty
Dwa zapisane schematy offsetówDwa zapisane schematy offsetów Alternujące się dla pixeli parzystych i nieparzystychAlternujące się dla pixeli parzystych i nieparzystych Dodatkowo mogą być pseudolosowo skalowaneDodatkowo mogą być pseudolosowo skalowane Wyliczone z kooordynatów ekranuWyliczone z kooordynatów ekranu Jittering
OptymalizacjaOptymalizacja Wyliczyć dobra dystrybucje opartą o dyskWyliczyć dobra dystrybucje opartą o dysk Względnie uniformicznąWzględnie uniformiczną Obracać ją dookoła poprzez reflect o pojedynczy losowy wektorObracać ją dookoła poprzez reflect o pojedynczy losowy wektor Jittering
Adaptywne samplowanieAdaptywne samplowanie Wykonać test krawędzi cieniaWykonać test krawędzi cienia TEST = Szybki shadow test z mała ilością sampliTEST = Szybki shadow test z mała ilością sampli TEST = (TEST > 0 && TEST 0 && TEST < 1) ? 1 : 0 TEST * dot(N,L)TEST * dot(N,L) If(TEST > 0) znaleziono krawędź cieniaIf(TEST > 0) znaleziono krawędź cienia Wykonać ciężki soft shadowingWykonać ciężki soft shadowing Optymalne jedynie przy bardzo dużych ilościach sampliOptymalne jedynie przy bardzo dużych ilościach sampli Zwykle nie używane w cieniowaniuZwykle nie używane w cieniowaniu PCF
AliasingAliasing W tekturach koloru rozwiązany przezW tekturach koloru rozwiązany przez Mip-mappingMip-mapping Filtrowanie anizotropoweFiltrowanie anizotropowe FiltrowanieFiltrowanie Nie można zastosować preprocessingu do shadow mapNie można zastosować preprocessingu do shadow map Patrz PCF i błąd średniejPatrz PCF i błąd średniej VSM
Potrzebujemy dystrybuanty –Cumulative Distribution Function – CDF zestawu punktów głębiPotrzebujemy dystrybuanty –Cumulative Distribution Function – CDF zestawu punktów głębi F(t) = P(x<=t)F(t) = P(x<=t) F(t) – wyraża prawdopodobieństwo zacieniowania punktu w odległości t od światłaF(t) – wyraża prawdopodobieństwo zacieniowania punktu w odległości t od światła VSM t F(t) 0 1 t f(t)
Szukamy reprezentacji liniowejSzukamy reprezentacji liniowej Chcemy skorzystać z filtrowania liniowegoChcemy skorzystać z filtrowania liniowego Używamy momentów dystrybucji funkcjiUżywamy momentów dystrybucji funkcji E(x) to średnia, E(x 2 ), E(x 3 ), etc.E(x) to średnia, E(x 2 ), E(x 3 ), etc. Liniowa dystrybucjaLiniowa dystrybucja VSM
Przechowujemy kwadrat głębi jak i głębiePrzechowujemy kwadrat głębi jak i głębie Daje nam to momenty E(x) i E(x 2 ) dla x będącego odległością do okluderaDaje nam to momenty E(x) i E(x 2 ) dla x będącego odległością do okludera Używamy momentów do aproksymacji wycinka dystrybucji, który ocenia prawdopodobieństwo zacieniowaniaUżywamy momentów do aproksymacji wycinka dystrybucji, który ocenia prawdopodobieństwo zacieniowania Dystrybucje wyznacza samplowany obszar pixeliDystrybucje wyznacza samplowany obszar pixeli Dowolne liniowe filtrowanie dystrybucji da nam uśrednione wartości oraz ich kwadratyDowolne liniowe filtrowanie dystrybucji da nam uśrednione wartości oraz ich kwadraty Możliwość filtrowaniaMożliwość filtrowania VSM
Szukamy P(xt)Szukamy P(xt) Mamy średnie więc wyliczmy wariancjęMamy średnie więc wyliczmy wariancję μ = E(x)μ = E(x) σ 2 = E(x 2 ) – E(x) 2σ 2 = E(x 2 ) – E(x) 2 Nie liczymy CDF dokładnieNie liczymy CDF dokładnie Korzystamy z Nierówności CzebyszewaKorzystamy z Nierówności Czebyszewa VSM
X jest wartością losową reprezentującą dystrybucję głębi okluderaX jest wartością losową reprezentującą dystrybucję głębi okludera T jest głębią aktualnego pixelaT jest głębią aktualnego pixela Stąd P(x >= t) – jest dokładnie procentem pixeli z regionu będących dalej niż testowany pixel t, czyli procentem oświetlonych pixeliStąd P(x >= t) – jest dokładnie procentem pixeli z regionu będących dalej niż testowany pixel t, czyli procentem oświetlonych pixeli VSM
Nierówność zadaje jedynie górne ograniczenie na procent oświetleniaNierówność zadaje jedynie górne ograniczenie na procent oświetlenia Staje się równością dla planarnych płaszczyzn : okludera i płaszczyzny cieniowanejStaje się równością dla planarnych płaszczyzn : okludera i płaszczyzny cieniowanej Przy odpowiednio małej odległości okludera od płaszczyzny, p maxb będzie dążyć do pPrzy odpowiednio małej odległości okludera od płaszczyzny, p maxb będzie dążyć do p Mając to na uwadze do renderignu cieni stosujemy p maxMając to na uwadze do renderignu cieni stosujemy p max VSM
// Pobierz dane z shadow mapy// Pobierz dane z shadow mapy Float2 moments = shadow_map(tex_coord); //R = X G = X^2Float2 moments = shadow_map(tex_coord); //R = X G = X^2 // Standardowy test shadow mapy// Standardowy test shadow mapy Float shadow = (dist_to_light <= moments.x);Float shadow = (dist_to_light <= moments.x); // VSM// VSM Float E_x2 = moments.y;Float E_x2 = moments.y; Float Ex_2 = moments.x * moments.x;Float Ex_2 = moments.x * moments.x; Float variance = E_x2 - Ex_2;Float variance = E_x2 - Ex_2; Float m_d = moments.x - dist_to_light;Float m_d = moments.x - dist_to_light; Float p_max = variance / (variance + m_d * m_d);Float p_max = variance / (variance + m_d * m_d); // Zacieniuj pixel// Zacieniuj pixel light_contrib *= max(shadow, p_max);light_contrib *= max(shadow, p_max); VSM
VSM
VSM
FiltrowanieFiltrowanie VSM możemy filtrować w czasie odczytuVSM możemy filtrować w czasie odczytu LiniowoLiniowo AnizotropowoAnizotropowo Pre filtrowaćPre filtrować Gaussian blurGaussian blur Dużo lepsza wydajność niż PCFDużo lepsza wydajność niż PCF PCF = O(n^2)PCF = O(n^2) Separowalny gaussian = O(n)Separowalny gaussian = O(n) VSM
VSM SMPCF 5x5Bil.PCF 5x5VSM
SupersamplingSupersampling Możliwość wygenerowania VSM w wyższej rozdzielczości i przeskalowania w dółMożliwość wygenerowania VSM w wyższej rozdzielczości i przeskalowania w dół Generacja mipmapGeneracja mipmap Filtrowanie trilinearneFiltrowanie trilinearne MSAAMSAA Możemy renderować do tekstury z MSAA dla filtrowanych krawędziMożemy renderować do tekstury z MSAA dla filtrowanych krawędzi VSM
Szukamy odpowiedniego formatu tekstury:Szukamy odpowiedniego formatu tekstury: RenderowalnyRenderowalny Dwu komponentowyDwu komponentowy Wysoka precyzjaWysoka precyzja Wsparcie dla filtrowaniaWsparcie dla filtrowania VSM
16 Bitowych16 Bitowych W zależności od zakresu wartości głębi w scenieW zależności od zakresu wartości głębi w scenie 2xFP162xFP16 2xINT162xINT16 32 bitowych32 bitowych Wystarczająca dokładność w każdej sytuacjiWystarczająca dokładność w każdej sytuacji 2x32FP, 2x32INT2x32FP, 2x32INT 4x16FP, 4x16INT – ręczne pakowanie4x16FP, 4x16INT – ręczne pakowanie VSM Formaty Tekstur
Możliwość wykorzystania innych formatówMożliwość wykorzystania innych formatów Konieczność ręcznego pakowania danychKonieczność ręcznego pakowania danych Problematyczny odczytProblematyczny odczyt Brak wsparcia sprzętowegoBrak wsparcia sprzętowego Idealnie programowalne filtrowanie teksturIdealnie programowalne filtrowanie tekstur VSM Formaty Tekstur
Używamy dowolnej metryki odległościUżywamy dowolnej metryki odległości Głębia z Z-buffora nieadekwatna ze względu na mało stabilną skalę logGłębia z Z-buffora nieadekwatna ze względu na mało stabilną skalę log Korzystamy z metryki liniowejKorzystamy z metryki liniowej Np. odległość do światła/kameryNp. odległość do światła/kamery Używając floatówUżywając floatów Przeskalować do [-1,1]Przeskalować do [-1,1] Dodatkowy bit precyzji ze znakuDodatkowy bit precyzji ze znaku VSM Stabilność
p max skuteczne w większości sytuacjip max skuteczne w większości sytuacji Gdy wariancja jest za duża może dojść do błędówGdy wariancja jest za duża może dojść do błędów przeciekanie światłaprzeciekanie światła Duża złożoność geometryczna = duża wariancjaDuża złożoność geometryczna = duża wariancja Zakres artefaktu zależy od filtrowanego obszaruZakres artefaktu zależy od filtrowanego obszaru Istnieją skuteczne rozwiązaniaIstnieją skuteczne rozwiązania Szukać VSM light bleedSzukać VSM light bleed Możliwość kalibrowania zakresami momentówMożliwość kalibrowania zakresami momentów VSM Artefakty
Podsumowanie For more information contact me Slides will be available at Drobot.org
Questions ?