390 likes | 564 Views
Rendering realistycznej wody jako efekt post-process. Wojciech Toman. Omawiane zagadnienia. Podstawowa teoria dotycząca wody Dotychczasowe podejście do renderingu wody Rendering przy wykorzystaniu prezentowanej techniki Wady i zalety prezentowanego rozwiązania Demo i rezultaty.
E N D
Rendering realistycznej wody jako efekt post-process Wojciech Toman
Omawiane zagadnienia • Podstawowa teoria dotycząca wody • Dotychczasowe podejście do renderingu wody • Rendering przy wykorzystaniu prezentowanej techniki • Wady i zalety prezentowanego rozwiązania • Demo i rezultaty
Rendering realistycznej wody jako efekt post-process Podstawowa teoria dotycząca wody
Podstawowa teoria dotycząca wody • Wady istniejących modeli formalnych • Żaden nie jest adekwatny • Zbyt duża złożoność obliczeniowa do zastosowania w grach • Konieczność znalezienia innego rozwiązania • Symulacja rozchodzenia się fal np. za pomocą FFT (Fast Fourier Transform) • Prawdziwy i postrzegany kolor wody • Zjawisko odbicia i załamania światła • Zanik barw wraz z głębokością
Prawdziwy i postrzegany kolor wody • Skład chemiczny wody i dna • Obecność materii organicznej (np. glony, plankton, szczątki) oraz nieorganicznej (np. skały, wraki) • Kolor nieba i pora dnia • Prawdziwy kolor – czysta woda bez dodatkowych związków chemicznych – lekko niebieski, nie biały/przezroczysty
wektor normalny promień światła α α promień odbity ośrodek A ośrodek B promień załamany Zjawisko odbicia i załamania • Promień światła padając na granicę ośrodków ulega odbiciu i załamaniu:
Zjawisko odbicia i załamania • Zależność Fresnela: • Mówi jaki stopień padającego światła ulega odbiciu a jaki załamaniu i transmisji przez ośrodek • Prawdziwa tylko dla dwóch ośrodków o różnej gęstości • Układ „powietrze – woda” spełnia te warunki • Układ „powietrze – szyba” nie (w rzeczywistości trzy ośrodki) • Indeks załamania dla wody: IOR = 1,33333
Zjawisko odbicia i załamania • Wzór Fresnela: • Gdzie: • Zbyt skomplikowany by liczyć go per-pixel • Niemal doskonała aproksymacja: • Często stosowana w praktyce • R(0) jest stałą
Zanik barw wraz z głębokością • Założenie: woda jest jednorodna na całej głębokości • Duże uproszczenie, ale wystarczające dla naszych potrzeb - powyżej powierzchni wody jest to niezauważalne • Światło widzialne zanika liniowo wraz z głębokością • Tempo zaniku jest inne dla każdej składowej światła widzialnego, co wynika z różnych długości fal • Najważniejszy czynnik wpływający na kolor wody obok rozpraszania światła przez cząsteczki zawarte w wodzie • Nie wpływa na prawdziwy kolor wody • Ciekawostka: podczerwień i ultrafiolet zanikają praktycznie przy powierzchni wody
Zanik barw wraz z głębokością w przypadku grafiki komputerowej
Rendering realistycznej wody jako efekt post-process Dotychczasowe podejście do renderingu wody
Dotychczasowe podejście do renderingu wody • Normal-mapping z odbiciami i refrakcją • Wykorzystuje geometrię w postaci płaszczyzny • Nadaje się tylko do prezentacji jezior – woda jest tylko „pomarszczona” • Projected-grid lub vertex texturefetch • Wykorzystuje gęstą siatkę wierzchołków • Możliwość uzyskania realistycznych i wysokich fal przy odpowiednio gęstej siatce
Wady klasycznych rozwiązań • „Ostre” brzegi – nierealistyczne przejście między powierzchnią wody a lądem • Nie istnieją w naturze bez względu na gęstość cieczy • Nierealistyczny zanik barw wraz z głębokością • Brak informacji o głębokości akwenu • Dla uzyskania dobrej jakości fal wymagana jest gęsta siatka wierzchołków • Brak elastyczności • Zalecane stosowanie technik LOD
Rendering realistycznej wody jako efekt post-process Rendering przy wykorzystaniu omawianej techniki
Rendering przy wykorzystaniu prezentowanej techniki • Cel: • Wyeliminować problemy wymienione wcześniej • Uzyskać efektywne i elastyczne rozwiązanie • Sposób realizacji: • Woda rysowana jako efekt post-process • Fale • Wyznaczenie wektorów normalnych • Odbicie i załamanie światła • Odblaski od światła globalnego • Zanik barw wraz z głębokością • Piana
Woda rysowana jako efekt post-process • Całkowity brak geometrii • Dostępne dane o głębokości akwenu w dowolnym jego punkcie • Naturalne podejście w przypadku deferred shadingu • Możliwość wykorzystania również w przypadku forward renderingu
Fale • Operując na buforze geometrii, dokonujemy faktycznej modyfikacji geometrii • Można zmienić każdy obiekt lub utworzyć całkowicie nową „geometrię” • Tekstura przechowująca dane o położeniu może być traktowana jako tekstura głębokości akwenu • Algorytm polega na wytłoczeniu fal w kierunku patrzenia poprzez śledzenie promieni
Fale - algorytm • Dla każdego punktu wody wykonywanych jest n iteracji • W każdej z nich height-mapa jest samplowana • Fale są wytłaczane w kierunku patrzenia o pobraną wartość • Modyfikacji ulega aktualna wysokość lustra wody • Znajdowane jest przecięcie pomiędzy aktualnym lustrem wody a wektorem patrzenia – wynik to nowe koordynaty tekstur do samplowaniaheight-mapy
Wyznaczenie wektorów normalnych • Brak wektorów normalnych! • Liczymy je tak jak dla terenu: • N = {w – e, 2d, s – n} • w, e, s, n – wartości pobrane z height-mapy dla sąsiadów • Normal-mapping • Brak wektorów binormalnych i stycznych • Można je wyznaczyć w sposób przybliżony w pixel shaderze • Kilkanaście dodatkowych instrukcji • Znaczny wzrost jakości wody • Kilkukrotne samplowanie mapy normalnych pozwala uzyskać małe i duże fale interferujące ze sobą • Zgodne z naturą • Dalszy wzrost jakości wody
Wyznaczenie wektorów normalnych • Wyznaczenie tangent-frame (sposób autorstwa Schulera): • gdzie: • Normal – wektor normalny, wektor wyznaczony przed chwilą, • Position – pozycja punktu w przestrzeni świata, • UV – koordynaty tekstur. float3x3 compute_tangent_frame(float3 Normal, float3 View, float2 UV) { float3 dp1 = ddx(View); float3 dp2 = ddy(View); float2 duv1 = ddx(UV); float2 duv2 = ddy(UV); float3x3 M = float3x3(dp1, dp2, cross(dp1, dp2)); float2x3 inverseM = float2x3(cross(M[1], M[2]), cross(M[2], M[0])); float3 Tangent = mul(float2(duv1.x, duv2.x), inverseM); float3 Binormal = mul(float2(duv1.y, duv2.y), inverseM); return float3x3(normalize(Tangent), normalize(Binormal), Normal); }
Odbicie i załamanie światła • Odbicie musi zostać wyrenderowane do tekstury w sposób klasyczny • Zastosowanie płaszczyzny przycinania • Dla załamania można wykorzystać zawartość bufora ramki • Wiele efektów post-process tę informacje wykorzystuje • Niewielki wpływ na jakość • Pozwala uniknąć renderingu do kolejnej tekstury
wektor forward H lustrowody H zmodyfikowanywektor forward Odbicie i załamanie światła • Rendering odbicia:
Odblaski • Jedynie od słońca • Brak pozostałych jest mało zauważalny • Woda ma bardzo wysoką połyskliwość • Bardzo dobre wyniki dla następującego kodu: half3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal -eyeVecNorm); half dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5); specular = (1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (shininess * 1.8 + 0.2)); specular += specular * 25 * saturate(shininess - 0.05);
Zanik barw wraz z głębokością • Dwa zjawiska • Zanik koloru wraz z głębokością • Zanik koloru wzdłuż wektora patrzenia – przejrzystość (widoczność) pozioma • Trzy składowe r, g, b: • Przykładowy wektor zaniku: [4.5; 75; 300] • Prawidłowy dla czystych wód • Dla jezior, rzek wymagana jest jego modyfikacja (np. [5; 40; 30]), aby dominował kolor zielony • Pominięcie pozostałych składowych nie pogarsza końcowego efektu
Zanik barw wraz z głębokością • Uwzględnienie prawdziwego koloru wody: • Gdzie: • surfaceColor – kolor powierzchni (prawdziwy kolor wody), • depthColor – kolor głębi. Zwykle czarny. Jeśli jest szary woda będzie przypominała mętną, • wykorzystaniu akumulacji wody A – ilości wody przez którą przechodzi promień światła • wprowadzeniu widoczności poziomej visibility. Im mniejsza wartość tego parametru tym woda będzie mniej przejrzysta. • Uzyskany kolor to ostateczny kolor dla załamania światła
Ostateczny kolor wody • Zmieszanie refrakcji i odbić w stopniu określonym przez wartość z zależności Fresnela • Dodanie odblasków do wyniku • Ponowne zmieszanie koloru z refrakcją w stopniu określonym przez akumulację wody • Zapewnia miękkie brzegi
Aktualny wygląd wody Woda po dodaniu opisywanych elementów. Woda wygląda dobrze, ale nadal nie idealnie
Piana • Powstająca przy brzegu • Występuje pomiędzy głębokościami 0, a H1. Od H1 do H2 całkowicie zanika. • Powstająca na szczycie wysokich fal w wyniku ich załamania • Gdzie: • H – aktualna wysokość ponad poziomem bazowym wody • H0 – wysokość, na której pojawia się piana • Hmax – maksymalna wysokość, do której pojawia się piana • Zapewnia interakcję pomiędzy sceną a wodą • Obiekty wpadające do wody powodują pojawienie się piany • Fale „rozbijają się” o skały i brzeg
Piana Dodanie piany wydatnie polepszyło jakość wody, a ponadto sprawiło że obraz stał się cieplejszy
Rendering realistycznej wody jako efekt post-process Wady i zalety
Wady • Dodatkowo zwiększa fill-rate • Woda nie najlepiej wygląda przy ostrych kątach • Światła lokalne nie wpływają na wygląd wody
Zalety • Model oparty głównie na obserwacji • Uzyskano rozwiązanie elastyczne – można uzyskać wody od mętnych jezior po krystaliczne morza tropikalne • Położenie i rozmiar akwenu można opisać w pixel shaderze • Wyeliminowana większość wad typowych rozwiązań
Rendering realistycznej wody jako efekt post-process Demo i rezultaty
Demo i rezultaty • Dostępne na: • http://wojtektoman.blogspot.com • http://www.gamedev.pl • http://www.youtube.com/wtoman - kilka filmów prezentujących wodę • Pełny kod źródłowy • Implementacja w HLSL + DirectX 9.0 • Wykorzystuje mój prywatny framework
Rezultaty Przykładowa scena uzyskana za pomocą przedstawionej techniki. Obszary o głębszej wodzie są wyraźnie ciemniejsze (granatowe). Tam gdzie jest płyciej woda jest turkusowa
Rezultaty Przykładowa scena uzyskana za pomocą przedstawionej techniki. Przy brzegu widać zanik światła i szybkie przejście do głębi
Rezultaty Rozwiązanie jest na tyle elastyczne, że pozwala osiągnąć również wodę, która będzie przypominała nieco mętną
Rezultaty Woda wygląda również realistycznie o innych porach dnia – odbicia od nieba i chmur są prawidłowe, a ponadto fale z tej odległości i pod tym kątem są niezauważalne