Teksturowanie proceduralne przy pomocy języka funkcyjnego Michał Radziszewski czerwiec 2007
Plan prezentacji Teksturowanie zwykłe i proceduralne Rendering w czasie rzeczywistym a rendering off-line Teksturowanie a cieniowanie (shading) Języki cieniowania Języki funkcyjne Projekt funkcyjnego języka teksturowania
Plan prezentacji – c.d. Gramatyka funkcyjnego języka teksturowania Biblioteka standardowa, operatory Tworzenie rozszerzeń Przykłady i wyniki Implementacja interpretera Możliwe udoskonalenia
Teksturowanie obiektów 3D Znacznie podnosi jakość wygenerowanej grafiki W przypadku użycia plików z obrazami (mapami) 2D powoduje duże zapotrzebowanie na pamięć Możliwość teksturowania z użyciem skompresowanych map
Teksturowanie proceduralne Zastosowanie programu do utworzenia tekstur Program wykonywany jest w trakcie renderingu Niemal brak zużycia pamięci Wymagana duża moc obliczeniowa Texturing and Modeling: a procedural approach
Zalety i ograniczenia teksturowania proceduralnego Możliwość efektywnej kontroli nad parametrami tekstury Duża ilość szczegółów Olbrzymia różnorodność scen Nie zawsze łatwo da się zastosować np. twarz człowieka ściana z obrazem
Rendering w czasie rzeczywistym vs. rendering off-line Płynna animacja – minimum 30 klatek/s co można zrobić w 1/30 sekundy? niestety nie jest możliwa symulacja oświetlenia zgodnego z prawami fizyki Wymagana wysoka jakość obrazów ile czasu potrzeba na poprawne oświetlenie sceny? obecnie od kilku minut do kilku(nastu) godzin
Rendering w czasie rzeczywistym vs. rendering off-line – c.d. Oświetlenie lokalne, malowanie trójkątów konieczność teselacji sceny w czasie malowania danej figury brak informacji o reszcie sceny Oświetlenie globalne śledzenie promieni albo bilans energetyczny uwzględnienie odbić wielokrotnych użycie informacji o całej scenie Algorytm decyduje o języku teksturowania
Śledzenie promieni Prezentowany język zoptymalizowany pod katem współpracy z ww. algorytmem Promienie transportują światło Przecięcia promieni z obiektami sceny Losowe odbicia promieni od obiektów z zadanym rozkładem prawdopodobieństwa Obraz powstaje poprzez uśrednienie mocy wielu promieni
Śledzenie promieni vs. malowanie trójkątów
Teksturowanie a cieniowanie Teksturowanie – obliczanie koloru, faktury, chropowatości, przeźroczystości itd. powierzchni w danym punkcie Cieniowanie – teksturowanie + oświetlenie danego punktu powierzchni, obliczenie ostatecznego koloru piksela na ekranie Zewnętrzne języki teksturowania / cieniowania operują na danych lokalnych
Teksturowanie a cieniowanie – c.d. Cieniowanie przy pomocy języka cieniowania możliwe jest tylko przy uproszczonym oświetleniu lokalnym Przy oświetleniu globalnym możliwe jest jedynie teksturowanie, a oświetlenie jest ściśle zdefiniowane prawami fizyki i jest juz zapewnione przez wybrany algorytm Wobec tego prezentowany tutaj język celowo nie pozwala na obliczanie oświetlenia
Języki cieniowania Wykorzystują lokalny model oświetlenia Popularne ze względu na rozwój przemysłu gier komputerowych Kompilowane do kodu maszynowego karty graficznej Obliczają ostateczny kolor pikseli ekranu Popularnym przykładem jest Cg NVIDII
Języki funkcyjne Program konstruowany jest z wywołań i deklaracji funkcji Brak instrukcji przypisania Brak obiektów zachowujących określony stan Brak pętli, zamiast nich jest rekurencja Przykład: silnia(n): cond(n>1, n*silnia(n-1), 1) Bliższe notacji matematycznej
Język funkcyjny a teksturowanie Nowe zastosowanie języków funkcyjnych Własności powierzchni widziane jako funkcja położenia, normalnej, czasu, etc. Umożliwia zarówno teksturowanie proceduralne, użycie standardowych obrazów 2D z zewnętrznych plików, a także podejście hybrydowe
Wymagania wobec funkcyjnego języka teksturowania Musi być obliczeniowo zupełny (języki kompilowane do kodu karty graficznej nie spełniają tego wymagania) Współpracować z algorytmem śledzenia promieni Umożliwiać tworzenie rozszerzeń Umożliwiać łatwe pisanie skryptów
Projekt języka Podział elementów na trzy kategorie materiały, mapy nierówności, źródła światła źródła kolorów, źródła wartości skalarnych, tablice stałe – całkowitoliczbowe i łańcuchowe Podział ten znacznie ogranicza liczbę funkcji w bibliotece standardowej i rozszerza możliwości języka
Projekt języka – c.d. Materiały, mapy nierówności, źródła światła tylko one mogą być dołączane do powierzchni określają powierzchnie jako np. matowe, półprzeźroczyste, chropowate itd. określenie jest niekompletne, wymagają podania źródła koloru / skalaru w celu uzupełnienia są zbiorami procedur; nie umożliwiają wyliczenia pojedynczej wartości; funkcja odpowiadająca materiałowi zwraca materiał (obiekt), a nie wyliczoną wartość w teksturowanym punkcie
Projekt języka – c.d. źródła kolorów, skalarów, tablice uzupełniają definicje materiałów wyliczane do odpowiednio: liczby rzeczywistej, funkcji opisującej widmo albo tablicy ww. wartości elementy tylko i wyłącznie z tej kategorii mogą być argumentami bądź wartościami zwracanymi przez funkcje rekurencyjne tylko te elementy mogą być argumentami operatorów materiał * materiał = ?
Projekt języka – c.d. stałe – całkowitoliczbowe i łańcuchowe stałe całkowitoliczbowe są używane podobnie jak #define w c stałe łańcuchowe są zwykle używane do określania nazw plików z teksturami język nie posiada operacji na łańcuchach znaków, łańcuchy mogą być tylko stałymi, nie mogą być zwracane przez funkcje nie są one potrzebne, gdyż projektowany język jest przeznaczony do obliczeń numerycznych
Funkcje Są podstawą języka funkcyjnego Każdy element jest albo stałą albo funkcją Funkcje mogą być zdefiniowane w standardowej bibliotece, w rozszerzeniach biblioteki albo w skrypcie Funkcje można wywoływać przekazując parametry w kolejności zapisu albo według nazw
Gramatyka Maksymalnie uproszczona Skrypt składa się tylko i wyłącznie z definicji funkcji Definicje funkcji mogą zawierać definicje zagnieżdżone Funkcje pobierają dowolna ilość argumentów Funkcja musi zawierać wyłącznie 1 wyraże- nie, będące jedyną wartością zwracaną
Biblioteka standardowa Zawiera często używane funkcje niezbędne do utworzenia skryptu Podejście z bardzo uproszczonym rdzeniem języka i bogatą biblioteką standardową W bibliotece znajdują się materiały oraz źródła kolorów i wartości skalarnych
Biblioteka standardowa – c.d. Materiały: matowy, lustrzany, połyskliwy, załamujący materiały złożone Źródła kolorów/skalarów, tablice alpha blending funkcje warunkowe i logiczne funkcje arytmetyczne funkcje wektorowe – normy, sumy, iloczyny, … konwersje kolor skalar
Biblioteka standardowa – c.d. Źródła kolorów/skalarów, tablice konwersja RGB -> kolor zjawiska fizyczne ciało doskonale czarne odbicie Fresnela teksturowanie obrazami 2D – wartość tekstury w punkcie, rozmycie, gradient szumy Perlina – funkcje podstawowe, marmur, drewno, chmury
Zaawansowane funkcje tekstur
Zaawansowane funkcje tekstur – c.d.
Dostęp do zmiennych aplikacji Dostęp do parametrów teksturowanego punktu analogiczny do semantyk wejściowych z Cg $P, $N, $T, $UV, $x, $y, $z, $t, $u, $v Dostęp do dodatkowych (nazwanych) zmiennych aplikacji analogiczny do zmiennych uniform z Cg funkcja get_host_variable(const string name)
Operatory Zdefiniowane tylko dla źródeł kolorów, skalarów i tablic, przeciążone Logiczne i relacyjne: and, nand, or, xor, not,, >=, =, != Arytmetyczne: +, -, *, /, ^ Tablicowe tworzenie – [f($u), 0.5, 1.0] wariacja – [0.7,0.5,-4]{0,1,1}, wariacja 2 – [0.7,0.5,-4]\{1} adresowanie – g($v)[h($P)]
Tworzenie rozszerzeń Umożliwia tworzenie całkiem nowych materiałów Umieszczenie często używanych funkcji w dodatkowej bibliotece DLL, kompilowanej z optymalizacjami na dany procesor Import funkcji w skrypcie deklaracja funkcji libname:classname zamiast ciała funkcji
Przykłady i wyniki color main { return blend( blend(color([ ]), color([ ]), noise(addr=8.0*$uv+16.0)* ), color([ ]), marble(addr=12.0*$uv, layers=[0.375, 0.375], amplitude=1.0, roughness=0.25, bright_dark=0.5, c_octaves=6 )) * blend( blend(color([ ]), color([ ]), noise(addr=8.0*$uv+48.0)* ), blend(color([ ]), color([ ]), noise(addr=8.0*$uv+128)* ), marble(addr=12.0*$uv+4.0, layers=[0.375, 0.375], amplitude=0.75, roughness=0.375, bright_dark=0.375, c_octaves=6 )) }
Przykłady i wyniki – c.d. color main { return tex( name="testimg.bmp", mode=#iaddr_clamp, addr=$uv )^(1+4*tex_mono( name="testimg.bmp", mode=#iaddr_clamp, addr=$uv, blur=[0.015,0.015]) )}
Przykłady i wyniki – c.d.
color main { return blend( cs=[color([ ]) color([ ]) color([ ]) color([ ]) color([ ]) color([ ])] alpha = 2^(-mandelbrot( addr=$uv*[3,2]-[2.0,1.0])) )} scalar mandelbrot(scalar[] addr){ return norm_l2(mdb_rec( x=[0, 0, 0], addr=addr){0, 1}) } scalar[] mdb_rec(scalar[] x, addr){ return cond( sqr(sqr(x[0])-sqr(x[1])+addr[0])+ sqr(2*x[0]*x[1] + addr[1]) > 4 or x[2]>24, x, mdb_rec(x=[ sqr(x[0])-sqr(x[1])+addr[0], 2*x[0]*x[1] + addr[1], x[2]+1 ], addr=addr) )}
Przykłady i wyniki – c.d.
Implementacja interpretera Parser wykonany ręcznie (bardzo prosta gramatyka), metoda zejść rekurencyjnych Jeżeli skrypt nie zawiera funkcji rekurencyjnych, to na jego podstawie jest budowane drzewo wywołań funkcji wirtualnych Przy rekurencji interpreter używa obiektów tworzących ramki stosu i jawnie alokujących pamięć na zmienne automatyczne
Przyszłe udoskonalenia Obsługa macierzy – nowy typ danych, nowe funkcje w bibliotece standardowej, dodatkowe przeciążenie operatorów – łatwe, do wykonania w najbliższej przyszłości Kompilacja, np. do kodu FPU x86 zamiast sklejania wywołań funkcji wirtualnych – kompilacja z optymalizacją jest zadaniem bardzo trudnym
Literatura Ebert, D. S., Musgrave, F. K., Peachey, D., Perlin, K., Worley, S.: Texturing and Modeling: A Procedural Approach, 3rd edition. Morgan Kaufmann Fernando, R., Kilgard, M. J.: Język Cg. Programowanie grafiki w czasie rzeczywistym. Helion Pixar: The RenderMan Interface. Pixar 2005.
Dziękuję za uwagę Dodatkowe materiały związane z publikacją można znaleźć na stronie