České vysoké učení technické v Praze Fakulta elektrotechnická Katedra počítačové grafiky a interakce
Diplomová práce
Přibližný výpočet efektů globálního osvětlení na GPU Bc. Miroslav Novotný
Vedoucí práce: Ing. Jiří Bittner, Ph.D.
Studijní program: Elektrotechnika a informatika, strukturovaný, Navazující magisterský Obor: Výpočetní technika 29. prosince 2010
iv
v
Poděkování Rád bych poděkoval Ing. Jiřímu Bittnerovi, Ph.D. za pomoc při vedení práce a ochotu při řešení všech problémů, které nastaly. Dále bych chtěl poděkovat Mgr. Antonínovi Míškovi, Ph.D. za pomoc při implementaci a testování. Na závěr chci poděkovat svým rodičům za vřelou podporu při studiu.
vi
vii
Prohlášení Prohlašuji, že jsem práci vypracoval samostatně a použil jsem pouze podklady uvedené v přiloženém seznamu. Nemám závažný důvod proti užití tohoto školního díla ve smyslu §60 Zákona č. 121/2000 Sb., o právu autorském, o právech souvisejících s právem autorským a o změně některých zákonů (autorský zákon).
V Oseku nad Bečvou dne 30. 12. 2010
.............................................................
viii
Abstract In forepart of work are described some existing method for approximate computation global illumination effect in 3D scenes. Primary objective surveyed method here is method screen space direct occlusion (SSDO). This method work in image space right on the graphic processing unit (GPU). Creates local occlusion near object in scene and in addition includes information obout directionality incoming lighting. Further respects coloured reflections from near object, one bounce of indirect illumination. Second part of the work describes implementation surveyed method to the existing system for visualization and processing 3D scenes (VRUT). Implementation will supplemented about shadow maps method for more realistic. Implemented will also be screen space ambient occlusion method (SSAO). Final part of the work will give to comparison and testing on implemented methods on several 3D scenes with different characteristics.
Abstrakt V první části práce jsou popsány některé existující metody pro přibližný výpočet efektu globálního osvětlení v 3D scénách. Hlavní zkoumanou metodou je zde metoda směrového zastínění v prostoru obrázku (SSDO). Tato metoda pracuje v prostoru obrázku přímo na grafickém akcelerátoru (GPU). Vytváří lokální zastínění blízkých objektů ve scéně a navíc zahrnuje informaci o směrovosti příchozího osvětlení. Dále respektuje barevné odrazy od blízkých objektů, tedy jeden odraz nepřímého osvětlení. Druhá část práce popisuje implementaci zkoumané metody do existujícího systému pro vizualizaci a zpracování 3D scén (VRUT). Implementace bude doplněna o metodu stínových map pro větší realističnost. Implementovaná bude také metoda zastínění okolím v prostoru obrázku (SSAO). Závěrečná část práce poskytne porovnání a testování naimplementovaných metod na několika 3D scénách o různých charakteristikách.
ix
x
Obsah 1 Úvod
1
2 Existující metody 2.1 Historie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Zastínění okolím (AO) . . . . . . . . . . . . . . . . . . . . . 2.3 Zastínění okolím v prostoru obrázku (SSAO) . . . . . . . . . 2.3.1 Základní princip . . . . . . . . . . . . . . . . . . . . 2.3.2 Vylepšení nedostatků . . . . . . . . . . . . . . . . . . 2.3.3 Použití . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4 Přímé zastínění v prostoru obrázku (SSDO) . . . . . . . . . 2.4.1 Směrové zastínění . . . . . . . . . . . . . . . . . . . . 2.4.2 Nepřímé odrazy . . . . . . . . . . . . . . . . . . . . . 2.4.3 Nedostatky a jejich odstranění . . . . . . . . . . . . . 2.4.3.1 Mnohonásobné vzorkování v jednom směru . 2.4.3.2 Členěná paměť hloubky . . . . . . . . . . . 2.4.3.3 Dodatečné pohledy . . . . . . . . . . . . . . 2.5 Stínové mapy . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.1 Základní princip . . . . . . . . . . . . . . . . . . . . 2.5.2 Algoritmus . . . . . . . . . . . . . . . . . . . . . . . 2.5.2.1 Vytvoření stínové mapy . . . . . . . . . . . 2.5.2.2 Aplikace stínové mapy na scénu . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
3 3 4 6 7 9 10 11 11 13 14 14 15 15 16 16 17 17 18
3 Analýza a návrh implementace 3.1 Implementační prostředí . . . . . . . . . 3.2 Podpora vykreslování v systému VRUT . 3.2.1 RenderGlModule . . . . . . . . . 3.2.1.1 Vykreslení scény . . . . 3.2.1.2 Antialiasing . . . . . . . 3.2.2 RenderTarget . . . . . . . . . . . 3.2.3 Mapa okolí . . . . . . . . . . . . 3.3 Výpočet zastínění . . . . . . . . . . . . . 3.3.1 Před-výpočet . . . . . . . . . . . 3.3.1.1 Neprůhledné materiály . 3.3.1.2 Průhledné materiály . . 3.3.2 Výpočet zastínění a odrazů barev 3.3.2.1 Generování vzorků . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
21 21 21 22 23 23 24 24 25 25 26 26 27 27
xi
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
xii
OBSAH
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
28 28 29 30 30 31 32 32 32 32
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
35 35 35 36 36 37 37 38 38 38 39 39 39 39 39 40 40 40 40
5 Testování 5.1 Scény pro testování . . . . . . . . . . . . . . . . 5.1.1 Základní barevná scéna . . . . . . . . . . 5.1.2 Scéna pro barevné odrazy . . . . . . . . 5.1.3 Sponza . . . . . . . . . . . . . . . . . . . 5.1.4 Scéna chrám . . . . . . . . . . . . . . . . 5.1.5 Scéna město . . . . . . . . . . . . . . . . 5.1.6 Závodní trať Forza a model Fábie . . . . 5.2 Rychlost . . . . . . . . . . . . . . . . . . . . . . 5.2.1 Testovací sestavy . . . . . . . . . . . . . 5.2.1.1 Intel Xeon X5260 . . . . . . . . 5.2.1.2 Intel Core 2 Duo E8400 . . . . 5.2.1.3 Intel Core 2 Duo T8300 . . . . 5.2.2 Závislost rychlosti na rozlišení obrazu . . 5.2.3 Závislost rychlosti na aktivovaném efektu
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
41 41 42 43 44 45 46 47 48 48 48 48 48 49 50
3.4
3.5
3.3.2.2 Převod mezi prostory . . . 3.3.2.3 Zastínění . . . . . . . . . . 3.3.2.4 Odrazy nepřímého osvětlení 3.3.2.5 Výstupní textury . . . . . . 3.3.3 Finální obraz . . . . . . . . . . . . . 3.3.3.1 Gaussův filtr . . . . . . . . Stíny od lokálního světla . . . . . . . . . . . 3.4.1 Sebe-zastínění . . . . . . . . . . . . . 3.4.2 Kombinace s metodou SSDO . . . . . Nastavovací parametry a GUI . . . . . . . .
4 Popis implementace 4.1 Nový modul . . . . . . . . . . . 4.2 Správa shaderů . . . . . . . . . 4.3 Frame buffer objects . . . . . . 4.4 Implementace shaderů . . . . . 4.4.1 Náhodné číslo . . . . . . 4.4.2 Generování vzorků . . . 4.4.3 Převod prostorů . . . . . 4.5 Filtrování obrazu (Blur) . . . . 4.6 Konfigurace . . . . . . . . . . . 4.6.1 Kompilace . . . . . . . . 4.6.2 Instalace . . . . . . . . . 4.6.3 Nastavení . . . . . . . . 4.6.3.1 Rádius . . . . . 4.6.3.2 numSamples . 4.6.3.3 shadowAtt . . 4.6.3.4 colorBounceAtt 4.6.3.5 blurOffset . . . 4.6.3.6 drawTtexture .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
OBSAH
5.3
xiii
5.2.4 Závislost rychlosti na počtu vzorků pro výpočet zastínění . . 5.2.5 Závislost rychlosti na velikosti scény . . . . . . . . . . . . . . Kvalita výpočtů . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51 52 53
6 Závěr
55
Literatura
57
A Seznam použitých zkratek
59
B Obsah přiloženého DVD
61
xiv
OBSAH
Seznam obrázků 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11 2.12 2.13 2.14 2.15
Ukázka výsledku metody [SA07] . . . . . . . . . . . . . . . . . . . . Příklady zastínění bodu okolím . . . . . . . . . . . . . . . . . . . . Použití polo-krychle místo hemisféry . . . . . . . . . . . . . . . . . Směrová normála pro výpočet zastínění . . . . . . . . . . . . . . . . Zastiňující body vzhledem k paměti hloubky . . . . . . . . . . . . . Objekt A by měl ovlivnit zastínění bodu P . . . . . . . . . . . . . . Projekce vzorkovacích bodů do paměti hloubky . . . . . . . . . . . Příklad textury s pseudonáhodnými čísly ve hře Crysis . . . . . . . Vznik zastínění nakloněných rovin . . . . . . . . . . . . . . . . . . . Použití normály pro redukci samo-zastínění . . . . . . . . . . . . . . Ukázka výsledku metody [RGS09] . . . . . . . . . . . . . . . . . . . Vygenerované vzorky a jejich vyhodnocení . . . . . . . . . . . . . . Nepřímé odrazy osvětlení . . . . . . . . . . . . . . . . . . . . . . . . Ukázka možných chyb výpočtu . . . . . . . . . . . . . . . . . . . . Porovnání jedné kamery (nalevo) a více kamer (napravo) pro vyhodnocení nepřímých odrazů světla v metodě [RGS09] . . . . . . . . . . 2.16 Scéna se stíny od světelného zdroje (vlevo) a bez stínů (vpravo) . . 3.1 3.2 3.3
4 4 6 6 7 7 8 9 9 10 11 13 14 15 16 17
3.6 3.7 3.8 3.9
Ukázka systému VRUT . . . . . . . . . . . . . . . . . . . . . . . . . Rozdělení scény na vykreslované celky . . . . . . . . . . . . . . . . Vykreslení objektu bez antialiasingu (nalevo) a s antialiasingem (napravo) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ukázka hloubkové a normálové mapy . . . . . . . . . . . . . . . . . Příklad Gaussova (vlevo) a uniformního (vpravo) rozložení vzorků na hemisféře . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Příklad projekce bodu S na povrch . . . . . . . . . . . . . . . . . . Ukázka aplikace filtrování . . . . . . . . . . . . . . . . . . . . . . . . Schéma vykreslovacích průchodů . . . . . . . . . . . . . . . . . . . . Grafické rozhraní ovládání parametrů ssdoRendereru . . . . . . . .
28 30 31 33 34
5.1 5.2 5.3 5.4 5.5 5.6
Scéna Scéna Scéna Scéna Scéna Scéna
42 42 43 43 44 44
3.4 3.5
colorTestScene.wrl bez efektů . . . . . . colorTestScene.wrl se zapnutými efekty colorBounce.wrl bez efektů . . . . . . . colorBounce.wrl se zapnutými efekty . . sponza97.wrl bez efektů . . . . . . . . . sponza97.wrl se zapnutými efekty . . .
xv
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
22 23 24 26
xvi
SEZNAM OBRÁZKŮ
5.7 5.8 5.9 5.10 5.11 5.12 5.13 5.14 5.15
Scéna temple.wrl bez efektů . . . . . . . . . . . . . . . . . . . . . . Scéna temple.wrl se zapnutými efekty . . . . . . . . . . . . . . . . . Scéna city.wrl bez efektů . . . . . . . . . . . . . . . . . . . . . . . . Scéna city.wrl se zapnutými efekty . . . . . . . . . . . . . . . . . . . Scéna forza.acc + fabia2.fhs bez efektů . . . . . . . . . . . . . . . . Scéna forza.acc + fabia2.fhs se zapnutými efekty . . . . . . . . . . . Graf poklesu rychlosti vykreslování v závislosti na rozlišení obrazu . Graf poklesu rychlosti vykreslování v závislosti na zvoleném efektu . Graf poklesu rychlosti vykreslování v závislosti na počtu vzorků pro výpočet zastínění . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.16 Graf poklesu rychlosti vykreslování v závislosti na velikosti scény . . 5.17 Chyba výpočtu odrazů na odvrácených stranách . . . . . . . . . . .
45 45 46 46 47 47 49 50 51 52 53
Seznam tabulek 5.1 5.2 5.3 5.4
FPS FPS FPS FPS
v v v v
závislosti závislosti závislosti závislosti
na na na na
rozlišení obrazu . . . . . . . . . . . zvoleném efektu . . . . . . . . . . . počtu vzorků pro výpočet zastínění velikosti scény . . . . . . . . . . . .
xvii
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
49 50 51 52
xviii
SEZNAM TABULEK
Kapitola 1 Úvod V dnešní počítačové grafice dokážeme vytvářet objekty, které jsou k nerozeznání od objektů reálných. Ať už jsou ale tyto objekty vytvořeny modelářem, nebo některou z moderních technologií jako je například 3D skener, samy o sobě nevypadají příliš realisticky. Pro simulaci reality je potřeba scéně ještě dopočítat osvětlení. To je pro finální vizuální kvalitu velice důležité, ale pro svou nesmírnou složitost také výpočetně velice náročné. Fyzikálně korektní osvětlení je i v dnešní technicky vyspělé době díky své výpočetní a časové náročnosti nemožné v reálném čase, a proto se používají různé aproximační metody. Nejjednodušší metodou simulace osvětlení je vytvořit texturu z modelu v reálném světě a tu potom použít v 3D scéně. Tato technika je velice primitivní a pro dynamické scény naprosto nevhodná. Sofistikovanější je metoda sledování paprsku (ray-tracing). Tato moderní metoda je v dnešní době díky svým velice kvalitním vizuálním výsledkům velice populární. Pro kvalitní výsledky ale potřebuje také velký výpočetní výkon. Moderní grafické akcelerátory již dovolují tuto metodu použít pro výpočet v reálném čase, je ovšem zapotřebí mnoha dalších urychlujících struktur jako například BVH (Bounding Volume Hierarchies) a jiné. Další nevýhodou této metody je růst výpočetních nároků s počtem světel ve scéně a velikostí scény. Proto je stále pro velké scény a vykreslování v reálném čase dnes nevhodná. V posledních letech se v počítačové grafice pro výpočet globálního osvětlení hojně využívají aproximační metody pracující na grafickém akcelerátoru v prostoru obrázku. Tato technika je striktně nezávislá na velikosti scény. Je pouze závislá na velikosti výsledného rozlišení obrazu. Proto je velice vhodná pro jakékoliv rozsáhlé a dynamické scény. Jednou z nejpopulárnějších je metoda zastínění okolím v prostoru obrázku (Screen Space Ambiente Occlusion - SSAO)[SA07], ), někdy také označována jako ISAO (Image Space Ambient Occlusion), která počítá lokální osvětlení a díky své jednoduchosti a snadné implementaci je hojně používána v produkci například celovečerních filmů nebo počítačových her. Poprvé byla použita ve hře Crysis. Tuto metodu v následující části podrobněji rozeberu. Metoda zastínění okolím je ovšem hrubou aproximací výpočtu osvětlení. Počítá pouze lokální osvětlení nezávislé na jakékoliv směrové informaci světel. Typickým výsledkem této metody je tzv. tmavnutí dutin nebo vnitřních rohů objektů. Právě
1
2
KAPITOLA 1. ÚVOD
směrovou informaci k výpočtu osvětlení již používá metoda směrového zastínění v prostoru obrázku (screen-space directional occlusion - SSDO)[RGS09]. Tato metoda je postavena na předchozí a k ní započítává směr příchozího světla a také dopočítává jeden odraz nepřímého světla. Tuto metodu budu dále nejpodrobněji zkoumat, poté ji naimplementuji a na závěr otestuji a porovnám s metodou zastínění okolím v prostoru obrázku (SSAO).
Kapitola 2 Existující metody V této kapitole rozebereme některé existující metody pro výpočet zastínění v 3D scénách. První část kapitoly rozebere historický vývoj těchto metod. Dále rozebereme základní funkcionalitu metod zastínění okolím (AO), zastínění okolím v prostoru obrazu (SSAO) a metody přímého zastínění v prostoru obrazu (SSDO).
2.1
Historie
Namísto metod vypočítávajících globální osvětlení ve filmech začala být používána metoda okolního zastínění (AO). Pro fotorealistické vykreslování metoda pracuje na principu viditelnosti z různých směrů. Bohužel pro současné aplikace je tuto metodu nemožné zvládat počítat v reálním čase. Pro aplikace běžící v reálném čase bylo vytvořeno mnoho aproximací AO. Dříve bylo zastínění okolím nazýváno jako „přístupnost“ plochy. Metoda [Mil94] využívá přístupnost k zjišťování hrubých stínu modelu napodobující AO. Metoda [M.05] používá diskově založené zastínění vypočítávané pro jednotlivé vrcholy. Bohužel tyto metody potřebují mnoho výpočetních operací předem, a tak nejsou vhodné pro dynamické scény. Potřebují také spoustu datových struktur pro jemné dělení scény. Metoda [KL05] částečně řeší problém dynamických scén, ale pouze pro přesné pohyby těles a nepodporuje tak jejich deformaci. Zároveň potřebuje spoustu operací pro před-počítání a využívá velké množství textur. Další metoda [RWS+ 06] používá kulovité zastínění pro výpočet AO. Tato technika řeší problém sebe-zastínění a pro podporu deformace objektů si vystačí s jednoduchým před-výpočetním krokem. Její nevýhodou ovšem je, že pro velké množství modelů ve scéně se stává příliš náročnou. Kromě metod vyvíjených pro obecné scény se vyvíjely také metody pro konkrétní typy scén jako je například příroda (tráva, stromy aj.) nebo molekulární vykreslování. Těchto metod je celá řada a je zbytečné je zde vypisovat.
3
4
KAPITOLA 2. EXISTUJÍCÍ METODY
Obrázek 2.1: Ukázka výsledku metody [SA07]
2.2
Zastínění okolím (AO)
Zastínění bodu okolím (AO) je dáno tím, jak moc je daný bod uzavřen obklopující geometrií, neboli jak moc rozptýleného světla z okolí se k němu může dostat. Všechny možné varianty AO pracují na podobném základním principu. Nad daným bodem máme hemisféru. Celkové zastínění bodu pak závisí na tom, jak moc do hemisféry zasahují blízké objekty.
Obrázek 2.2: Příklady zastínění bodu okolím
Jak je vidět na obrázku 2.2a), bod P má všechny směry na hemisféře nezastíněné. Na obrázku 2.2b) a 2.2c) zasahují do hemisféry v bodě P okolní objekty, které zapříčiní zastínění daného bodu. Díky tomu na bod P v obrázku 2.2a) dopadne maximum přímého osvětlení. Na obrázku 2.2c) dopadne v bodě P větší polovina přímého osvětlení a na obrázku 2.2b) už jen jeho malá část. Proto pro realistický výpočet AO potřebujeme znát hodnotu zastínění v každém bodě scény. Nejjednodušší varianta okolního zastínění bodu se dá vyjádřit jako podíl hemisféry obklopující daný bod a hemisféry nezasažené obklopujícími blízkými objekty tako: A(P ) =
1 Z (V (P, ω))dω 2π Ω
(2.1)
2.2. ZASTÍNĚNÍ OKOLÍM (AO)
5
Kde Ω je hemisféra nad bodem P . V je funkce viditelnosti, která určuje, zda je daný směr ω z bodu P zastíněn nebo ne. Funkce vrací hodnotu 1, pokud se v daném směru ω nenachází žádný blízký objekt, nebo 0, pokud je ve směru překážející objekt. První funkce pro výpočet zastínění je ale příliš jednoduchá a proto si zavedeme další, specifičtější definici pro výpočet zatemnění bodu. W (P ) =
1Z ρ(L(P, ω)) cos ωdω π Ω
(2.2)
Zde se přidává pro zpřesnění výsledku vzdálenost daného bodu od zastiňujícího objektu a také, že osvětlení nebo zatemnění přichází z určitých směrů. To je definováno úhlem dopadu cos ω. Pro výpočet vzdálenosti se zde používá specifická funkce, u které předpokládáme následující požadavky: (
ρ(L) =
0, L = 0 , ρ0 (L) > 0, ρ00 (L) < 0 1, L → ∞
(2.3)
Jednoduchý příklad této funkce může být následující: ρ(L) = 1 − e−τ L
(2.4)
Velice důležité je, že vzdálenost z bodu do zastiňujícího objektu se počítá jen do určité vzdálenosti. Definuje se tak vzdálenost blízkého okolí daného bodu. Jak je zřejmé ze vzorců uvedených výše, funkce spočívají na výpočtu plošného integrálu přes hemisféru. Tento výpočet je klasicky proveden pomocí vyslání velkého množství paprsků z daného bodu ve směrech hemisféry. První integrál se tak vypočte jako poměr všech paprsků neprotínajících žádný blízký objekt v dané maximální vzdálenosti vůči všem vyslaným paprskům. Druhý integrál se počítá o něco složitěji, ale stejným způsobem. Obvykle se používají náhodné směry s rovnoměrným rozložením. K tomu dobře poslouží metoda Monte Carlo. Nicméně tento způsob je také velice výpočetně náročný. Existuje její obdobná simulace na GPU, která využívá výhody moderních GPU. Myšlenka této metody spočívá v záměně hemisféry půl-krychlí a vykreslení všech blízkých objektů na hranici této polo-krychle. To nám zajistí pětinásobné vykreslení, kde projekci vždy nastavujeme na další stěnu polo-krychle. Přitom stačí provádět pouze zápis do paměti hloubky. Po pětinásobném vykreslení pouze do paměti hloubky bude obsahovat informace o zakrytých a odkrytých směrech pro dané stěny polo-krychle. Tyto textury hloubek se využijí pro výsledný výpočet zastínění v shaderu na GPU. Tímto si vystačíme s pětinásobným vykreslením a jedním dalším průchodem pro výsledný výpočet. Pro tuto techniku existuje vytvořený paket nazývaný generátor rychlého zastínění okolím (Fast Ambient Occlusion Generator). Dnes je tato technika rozšířena hlavně pro výpočet zastínění pro scény se statickou geometrií a občas vyžaduje dodatečnou teselaci pro zajištění dostatečné hustoty vrcholů.
6
KAPITOLA 2. EXISTUJÍCÍ METODY
Obrázek 2.3: Použití polo-krychle místo hemisféry
Kromě výpočtu samotného zastínění se mnohdy vypočítavá i takzvaná směrová normála (bent normal). Ta je vypočítána jako průměrná hodnota všech neblokovaných směrů, viz obrázek 2.4. Tato normála se potom používá namísto klasické normály pro výpočet přímého osvětlení. Což realističtěji respektuje celkové osvětlení scény.
Obrázek 2.4: Směrová normála pro výpočet zastínění
Tímto způsobem stačí uchovávat pro každý vrchol ve scéně pouze čtyři hodnoty. Okolní zastínění a tři prvky pro směrovou normálu. Nicméně i s využitím výkonných moderních GPU je s touto metodou výpočet v reálném čase ve scénách s milióny vrcholů takřka nemožný.
2.3
Zastínění okolím v prostoru obrázku (SSAO)
Zásadní nedostatek předchozích metod je, že nedokážou pracovat v reálném čase pro rozsáhlé a dynamické scény. Z tohoto důvodu jsou vyvíjeny aproximační metody, které dokážou pracovat v reálném čase. Jednou z nejznámějších a nejrozšířenějších je právě metoda výpočtu zastínění blízkým okolím v prostoru obrázku [SA07].
2.3. ZASTÍNĚNÍ OKOLÍM V PROSTORU OBRÁZKU (SSAO)
2.3.1
7
Základní princip
Základní myšlenka této metody je velice jednoduchá. Za prvé nás zajímá pouze viditelná část scény a za druhé paměť hloubky, kterou získáme při prvním vykreslení scény. Ta pak obsahuje dostatečné informace pro výpočet lokálního zastínění zobrazených pixelů. Díky tomu můžeme pro každý pixel obrazovky získat zpět prostorové souřadnice v souřadnicovém systému kamery. V blízkém okolí daného bodu potom zvolím N vzorků a každý z nich se pak testuje, jestli je viditelný z daného bodu. Tak získám výslednou hodnotu zastínění v určitém pixelu.
Obrázek 2.5: Zastiňující body vzhledem k paměti hloubky
Je ale třeba mít na paměti, že tato metoda počítá pouze přibližné zastínění. Problém je, že v paměti hloubky nejsou informace o objektech neviditelných z kamery, ale i tyto objekty mohou značně přispět k výslednému zastínění.
Obrázek 2.6: Objekt A by měl ovlivnit zastínění bodu P
Tuto situaci znázorňuje obrázek 2.6. Při vzorkování z paměti hloubky se bude počítat pouze s hranou zakrývající objekt A, a tím pádem se v zastínění bodu P neobjeví vliv objektu A. To může v takovémto případě znamenat značnou chybu.
8
KAPITOLA 2. EXISTUJÍCÍ METODY
Trasování paprsků z bodu pohledu do všech vzorků v blízkém okolí, jak je dáno v prvním vzorci, a získání tak dat z paměti hloubky o příspěvku k zastínění je velice náročné. V praxi a i ve hře Crysis se používá mnohem jednodušší postup. Všechny vzorkovací body v okolí (xi , yi , zi )zastiňovaného bodu P se projektují do paměti hloubky a vzniknou tak body (x0i , yi0 , zi0 ). Tyto získané body se poté vyhodnotí s bodem P , zda zastiňují nebo ne. Výsledné zastínění bodu P se pak jednoduše vypočte jako suma všech příspěvků zastínění. A stupeň zastínění od určitého vzorku (x0i , yi0 , zi0 ) se vypočte pomocí jednoduché rozdílové funkce: dz = Pz − zi0
(2.5)
Obrázek 2.7: Projekce vzorkovacích bodů do paměti hloubky Nejjednodušší varianta pro definici stupně zastínění používá následující funkci: (
f (∆z) =
1 1+∆z 2
1, L → ∞
, ∆z >
(2.6)
Z funkce je zřejmé, že jestliže nastane případ, kdy dz je menší než nula, zastínění se nezapočítává. Pro volbu směrů vzorků obvykle volíme předem definované vektory uloženy například v tabulce. Ta je velká podle jejich počtu. Tohle samotné je ale nedostačující, protože opakování stejných nenáhodných hodnot způsobí aliasing. Ve hře Crysis byla proto použita speciální textura malého rozměru (dostačující je např. 4x4), ve které jsou uloženy jednotkové trojrozměrné pseudonáhodné vektory. Kombinací této textury a předem definovaných vektorů dostaneme pseudonáhodné vzorky. Tím se z větší části aliasingu zbavíme. Zavedením pseudonáhodných vektorů sice způsobí šum ve výsledném zastínění, ale ten se jednoduše odstraní pomocí vyhlazování. Získaný posun ještě vynásobím hodnotou poloměru blízkého okolí, která určuje, do jaké vzdálenosti budou vzorky zasahovat. Pomocí těchto vektorů poté najdu příslušné hodnoty v paměti hloubky a hodnoty převedu do souřadnicového systému kamery. Potom již stačí dle uvedených vzorců vypočítat zastínění daného bodu
2.3. ZASTÍNĚNÍ OKOLÍM V PROSTORU OBRÁZKU (SSAO)
9
Obrázek 2.8: Příklad textury s pseudonáhodnými čísly ve hře Crysis
2.3.2
Vylepšení nedostatků
Uvedený postup ale ještě zahrnuje určité nedostatky. Hlavním z nich je, že postup uvedený výše bude zastiňovat i velké rovné plochy, které nebudou kolmé k pozorovateli. A čím víc budou nakloněny, tím víc budou zastíněny. Problém je, že rozdíl souřadnic z v rovné nakloněné ploše bude u poloviny vzorků kladný a u poloviny záporný. A právě polovina vzorků s kladnou hodnotou se zde projeví. Tento nedostatek se řeší definicí proměnné pro sklon (bias). Nastavením této hodnoty se dá tato chyba do jisté míry kompenzovat.
Obrázek 2.9: Vznik zastínění nakloněných rovin
Další problém nastává, že zastínění je vytvořeno i pro vzdálené objekty, pro
10
KAPITOLA 2. EXISTUJÍCÍ METODY
které by nemělo nabývat takových hodnot. Tuto chybu zapříčiňuje velké dz, které vznikne právě při velké vzdálenosti na vzorkovaných objektech. A jeden vzorek tak dokáže přispět k celkovému zastínění více než je správné. Proto je vhodné výslednou hodnotu upravit pomocí následující funkce: !
!
dz dz dz = clamp ∗ 2− , 0.1 D D 0
(2.7)
Kde D je počet vzorků a funkce clamp() ořeže výslednou hodnotu do intervalu (0, 1). Další možností jak zabránit samo-zastínění rovných nakloněných ploch je použití normálových vektorů. Toto řešení sice o něco málo komplikuje výpočet, ale zato redukuje tuto chybu téměř na nulu. Na obrázku 2.10 vidíme zastiňovací vzorky A,B a C pro zastínění bodu P s normálou n. Vzorek A, ačkoliv je níž než bod P , přispěje k jeho zastínění díky srovnání úhlu mezi normálou v bodě P a úsečkou z P do A. Pokud je úhel ostrý, bod přispívá k zastínění. Proto body B a C, které jsou sice nad bodem P , ale úhly k normále nejsou ostré, nepřispějí k zastínění.
Obrázek 2.10: Použití normály pro redukci samo-zastínění
Nicméně tato metoda je dost náchylná na přesnost souřadnic bodu i normálových vektorů. Vede k chybám vznikajícím v šikmých rozích. Pro eliminaci je vhodné použít jako formát pro ukládání hodnot normál i souřadnic vrcholů GL_RGBA32F. Tím získáme dostatečnou přesnost souřadnic.
2.3.3
Použití
Jak již bylo řečeno v úvodu, metoda zastínění okolím je dnes velice populární ve většině odvětví počítačové grafiky. Díky její jednoduchosti a vysoké výkonnosti se dá použít pro simulaci osvětlení v reálném čase pro rozsáhlé a dynamické scény
2.4. PŘÍMÉ ZASTÍNĚNÍ V PROSTORU OBRÁZKU (SSDO)
11
bez potřeby předvýpočtů. Nezávislost na velikosti scény a počtu polygonů ve scéně je díky tomu, že metoda pracuje na grafickém akcelerátoru v prostoru obrázku. Zastínění se tak počítá pro každý pixel výsledného obrazu samostatně. Rychlost výpočtů je tak závislá pouze na výkonu grafického akcelerátoru a propustnosti datové sběrnice. To může znamenat problémy u starších grafických karet, ale v dnešní době to považuji za minimální problém. Dá se jednoduše doimplementovat do další metody pro simulaci globálního osvětlení a tak zajistit vyšší vizuální kvalitu. Problémy mohou nastat při velké vzdálenosti scény od kamery nebo při rovnoběžném pohledu na plochu. Další artefakty mohou vznikat, pokud vzorky ve směru zastínění nezasáhnou zastiňující objekt a vyhodnotí se tak chybně výsledný stín. Tento problém se dá vyřešit použitím více vzorků v jednom směru. To ale zároveň snižuje výsledný výkon.
2.4
Přímé zastínění v prostoru obrázku (SSDO)
Jak již bylo zmíněno v úvodu, tato metoda je postavena na základech metody SSAO[SA07] a využívá informace získané při jejím výpočetním procesu. Obě metody jsou výstupně závislé a nezáleží tak na složitosti a detailnosti geometrie ve scéně. SSAO je hrubou aproximací transportů světla ve scéně a neřeší směrovost světel nebo nepřímé odrazy. Tyto nedostatky řeší například metoda předpočítání přesunů radiance (precomputed radiance transfer - PRT)[LK03]. Tato metoda ovšem vyžaduje uložení velkého množství dat, a to závisle na velikosti a detailnosti scény. Pracuje dobře se statickou scénou a vzdálenými světly, ale přizpůsobení této metody na konkrétní scénu nemusí být jednoduché. Naopak metoda SSDO je velmi snadno použitelná pro jakoukoli scénu o libovolné velikosti a různé úrovni detailů. A navíc od původní metody SSAO počítá se směrovým zastíněním a zahrnuje jeden nepřímý odraz světla.
Obrázek 2.11: Ukázka výsledku metody [RGS09]
2.4.1
Směrové zastínění
Transport světla ve scéně se v základu dělí na přímé osvětlení a nepřímé odrazy. Metoda SSDO využívá dvou průchodů, a to jeden pro přímé osvětlení a druhý pro
12
KAPITOLA 2. EXISTUJÍCÍ METODY
nepřímé světelné odrazy. Klasická metoda SSAO vypočítává osvětlení jednoduchým počítáním průměrné viditelnosti z množiny okolních pixelů. Touto hodnotou je pak vynásobeno přímé osvětlení ze všech směrů. Technika přímého zastínění (DO) upravuje právě tuto vazbu následujícím způsobem. Pro každý pixel obrazu s trojrozměrnými souřadnicemi P a normálou N je příchozí záření Ldir vypočteno z N vzorků. Vzorkové paprsky mají směr ωi a jsou rovnoměrně rozložené na hemisféře orientované ve směru normály. Každý vzorek pokrývá oblast prostorového úhlu: ∆ω = 2π/N
(2.8)
Samotný výpočet Ldir vypadá následovně:
Ldir (P ) =
N X
ρ Lin (ωi )V (ωi ) cos θi ∆ω i=1 π
(2.9)
V každém vzorku se vypočítává příchozí radiance Lin z mapy prostředí, popřípadě světel ve scéně. Viditelnost V je počítána podobným způsobem jako v předchozí metodě. A položka πρ představuje difuzní BRDF (Bidirectional reflectance distribution function). Pro generování vzorků vezmeme krok náhodné délky λi ∈ [0. . . rmax ] směřující z P ve směru ωi . Kde rmax je uživatelem definovaný poloměr hemisféry. Takto vzniknou vzorkové body P + λi ωi umístěné v hemisféře. Takto vygenerované body s trojrozměrnými souřadnicemi v okolí bodu P se mohou nalézat nad povrchem nebo pod povrchem v daném obraze. Test viditelnosti tak všechny vzorky, které se naleznou pod povrchem, označí jako zastiňující. Obrázek 2.12 znázorňuje situaci pro zastínění bodu P se čtyřmi vzorkovacími body A, B, C a D. Bod C je dle testu viditelnosti nad povrchem a tak je klasifikován jako nezastiňující. Body A, B a D jsou pod povrchem a tak jsou ohodnoceny jako zastiňující. Zjištění zda je daný bod pod povrchem nebo ne, se provádí pomocí zpětné projekce do obrazu. Po této operaci jednoduše porovnáme původní bod a bod vzniklý zpětnou projekcí. Vyhodnotí se vzdálenost od pozorovatele, a pokud je projektovaný bod vzdálenější než původní, je ohodnocen jako zastiňující. Hlavní rozdíl od SSAO je, že nepočítáme osvětlení ze všech vzorků, ale pouze z viditelných směrů. V obrázku 2.12 je to pouze bod C. Díky této směrové informaci se může výsledný obraz výrazně vylepšit, a to hlavně v případech, kdy světlo přichází z různých směrů, a o různých barvách. Stíny tak mohou získávat i barevný nádech. Zatímco SSAO vytváří pouze šedé stíny bez jakékoliv směrové informace.
2.4. PŘÍMÉ ZASTÍNĚNÍ V PROSTORU OBRÁZKU (SSDO)
13
Obrázek 2.12: Vygenerované vzorky a jejich vyhodnocení
2.4.2
Nepřímé odrazy
Pro zahrnutí jednoho nepřímého odrazu světla se využívá informace z předchozího průchodu, ve kterém bylo vypočítáno přímé osvětlení. Pro každý vzorek, který je vyhodnocen jako zastiňující (2.12, body A, B a D), se vezme jeho barevná hodnota Lpixel , a ta je použita jako odchozí záření malé plochy orientované ve směru normály tohoto bodu. Normála v bodě také slouží k odstranění barevného odrazu z odvrácených ploch. Pro vyhodnocení příchozího záření v daném pixelu pak použijeme tento vzorec:
Lind (P ) =
N X
ρ As cos θsi cos θri Lpixel (1 − V (ωi )) d2i i=1 π
(2.10)
Kde di je vzdálenost z bodu P do dáného vzorku i (vzdálenost je ořezána na maximální hodnotu 1,pro vyhnutí se dalším problémům), si a ri jsou úhly odesílatele a příjemce záření. Tyto úhly jsou dány mezi normálou daného bodu a spojnicí mezi oběma body. As je hodnota velikosti plochy odesílatele. Jako základní hodnotu velikosti plochy bereme rovinnou oblast uvnitř polokoule. Kde základní koule je rozdělena do N oblastí: 2 As = πrmax /N
(2.11)
V závislosti na naklonění zdroje uvnitř hemisféry může být tato hodnota o něco vyšší. Ale většinou se tento parametr používá pro ruční ovládání síly odrazu.
14
KAPITOLA 2. EXISTUJÍCÍ METODY
Na obrázku 2.13 můžeme vidět, že bod A je odvrácen od bodu P , a tak nepřispívá k nepřímému světlu v bodě P . Bod C není zastiňující, a tak také nepřispívá. Body B a D již ale přispívají, a to dle předchozí funkce, tedy závisle na vzdálenosti, úhlům normál a počtu všech vzorků.
Obrázek 2.13: Nepřímé odrazy osvětlení
2.4.3
Nedostatky a jejich odstranění
Jako každá aproximační metoda i tato obsahuje řadu nedostatků a nesrovnalostí. Ty jsou způsobeny veškerými zjednodušujícími postupy, které používáme. Některé jsou takřka nepatrné a jiné naopak dosti viditelné. Proto si dále některé nedostatky vysvětlíme a uvedeme metody pro jejich možné odstranění. 2.4.3.1
Mnohonásobné vzorkování v jednom směru
Jelikož pracujeme v prostoru obrázku, tak test viditelnosti nemusí pokaždé správně označit bod zastínění. Jak je vidět na obrázku 2.14, Vzorek B může a nemusí být vyhodnocen jako zastiňující, podle toho, kde v daném směru umístíme vzorek. Pokud použijeme vzorek s1 nebo s2, bude směr vyhodnocen jako volný a použije se pro něj přímě osvětlení z mapy okolí. To je ovšem chyba, která se nestane, když použijeme vzorek s3. Vzorek je ale volen náhodně, a tak mohou nastat obě situace. Pro redukci počtu takovýchto chyb můžeme použít více vzorků pro jeden směr. Takto se dá počet chyb radikálně snížit, ale také se zvyšuje náročnost výpočtu. Pro volbu dvou vzorků namísto jednoho chyba radikálně klesá a výpočetní náročnost roste. Při zvyšujícím
2.4. PŘÍMÉ ZASTÍNĚNÍ V PROSTORU OBRÁZKU (SSDO)
15
Obrázek 2.14: Ukázka možných chyb výpočtu
se počtu vzorků na jeden směr již chybovost tak rapidně neklesá, ale náročnost roste rychle. Proto je velice důležité nastavení při použití této techniky. 2.4.3.2
Členěná paměť hloubky
Při použití jednoduché hloubkové paměti jsme limitovaní tím, že známe pouze hodnotu nejbližšího objektu ke kameře a tak může nastat situace, že špatně vyhodnotíme určitý směr jako zastíněný, ale ve skutečnosti bude volný. Tato situace je znázorněna na obrázku 2.12, vzorek A. Pokud použijeme jednoduchou paměť hloubky, při zpětné projekci vzorku A dostaneme bod h1 a tím označíme vzorek jako zastiňující. K řešení tohoto problému může výrazně pomoci technika členěné paměti hloubky. Paměť hloubky místo jedné hodnoty obsahuje n hodnot. Ty jsou získány po n průchodech a znázorňují po dvojicích vždy přední a zadní stranu objektu. Pokud zjistíme že se vzorek nalézá pod povrchem scény (obr.2.12 pro bod A hodnota h1), testujeme další hodnotu v paměti hloubek. Pokud se bod stále nachází pod touto hodnotou, víme, že se nachází pod objektem a není zastíněn. Pokud by se nacházel nad druhou hodnotou, ležel by v objektu a byl by správně vyhodnocen jako zastiňující. A tímto způsobem budeme testovat dále, pokud bude paměť hloubky obsahovat více vrstev. 2.4.3.3
Dodatečné pohledy
Použitím vice kamer pro výpočet zastínění můžeme odstranit stejný problém jako v předchozím případě. Navíc řeší další problém vznikající při výpočtu odrazu
16
KAPITOLA 2. EXISTUJÍCÍ METODY
nepřímého světla, jak ukazuje obrázek 2.15. Základní výpočet odrazu nepřímého osvětlení používající jednu kameru nedokáže správně vyhodnotit objekty, jejichž strany jsou rovnoběžné se směrem pohledu kamery. Pokud použijeme víc kamer, nejlépe s co nejodlišnějšími směry pohledu, dokážeme vypočítat odrazy i z objektů, které z původní kamery nejsou vidět. Tato technika byla použita v metodě [RGS09], a využívala 4 kamery vždy posunuté o 90 stupňů od středu scény. Tím se získaly i odrazy ze schovaných objektů a rovnoběžných stěn se směrem pohledu kamery. Ovšem i tato technika potřebuje navíc spoustu výpočetního výkonu a tak je potřeba zvážit její využití a nastavení pro konkrétní případy.
Obrázek 2.15: Porovnání jedné kamery (nalevo) a více kamer (napravo) pro vyhodnocení nepřímých odrazů světla v metodě [RGS09]
2.5
Stínové mapy
Mnohem starší technika vytváření stínu ve scéně, než je SSDO, je metoda stínových map. Tuto metodu představil v roce 1978 Lance Williams. Od této doby je velice využívaná ve všech odvětvích počítačové grafiky. Dnes existuje mnoho modifikací a dalších metod vylepšujících základní princip. Zde si uvedeme pouze jednoduchý princip, jak metoda pracuje. Podrobněji si o této technice můžeme přečíst například zde [WSP04].
2.5.1
Základní princip
Při pohledu na scénu z pozice světla můžeme říct, že všechny objekty, které vidíme, jsou nezastíněné a všechny objekty za nimi budou zastíněné. Tohle je základní myšlenka celé metody. Vykreslíme scénu z pohledu světla a uložíme hloubkovou mapu pro všechny viditelné objekty (vytvořili jsme stínovou mapu). Dále vykreslíme scénu z pohledu kamery a pro každý pixel porovnáváme jeho hloubku a hloubku uloženou ve stínové mapě. Tím získáme zastíněné a nezastíněné body.
2.5. STÍNOVÉ MAPY
17
Tato technika není tak přesná jako technika stínových objemů, je limitovaná rozlišením stínové mapy, ale může být mnohem rychlejší a tak více použitelná pro aplikace pracující v reálném čase. Technika stínových map navíc nepotřebuje stencil buffer a může být vylepšena pro vytváření měkkých stínů.
Obrázek 2.16: Scéna se stíny od světelného zdroje (vlevo) a bez stínů (vpravo)
2.5.2
Algoritmus
V závislosti na implementaci aplikace a počtu světel ve scéně použijeme daný počet vykreslovacích průchodů. Minimálně ale budou vždy dva, a to jeden pro generování stínové mapy a druhý pro její aplikaci na výslednou scénu. Pokud je ve scéně použito více zdrojů světla, může být použito pro získání stínové mapy i více průchodů. 2.5.2.1
Vytvoření stínové mapy
Začneme prvním krokem, vykreslením scény z pohledu světla. Pro jednoduchost budeme předpokládat ve scéně pouze jeden zdroj světla. Typů světel ve scéně může být několik, ale ve zjednodušené formě dva hlavní. První je směrové světlo, jako je například slunce. Pro tento zdroj světla použijeme ortografické promítání. A druhé je bodové světlo. Do tohoto typu světla můžou být zjednodušeně zahrnuty i menší plošné zdroje světel. Pro tento druh světla použijeme perspektivní promítání, které nastavíme na požadovaný úhel záběru světla. Pokud by scéna obsahovala více zdrojů světla, bude pro každý zdroj světla potřeba vykreslit znovu všechny osvětlované objekty. Proto s rostoucím počtem světel roste úměrně výpočetní náročnost celé metody. Jelikož z tohoto kroku potřebujeme pouze texturu hloubek, můžeme vypnout výpočty pro texturování a osvětlení, a tím výrazně urychlit vykreslování. Samotnou texturu hloubek můžeme uložit do připravené textury, nebo využít modernější a rychlejší FBO (frame buffer object).
18
KAPITOLA 2. EXISTUJÍCÍ METODY
Tento krok musíme opakovat pro jakoukoli změnu ve scéně, jak pro změnu libovolného objektu scény, který je zdrojem osvětlen, tak pro změnu pozice nebo směru zdroje světla. Krok můžeme vynechat pouze při změně pozice či směru kamery. Pro statické scény proto můžeme konstatovat, že je tento předvýpočet proveden pouze jednou. Pro velké scény můžeme použít více stínových map, do kterých budeme vykreslovat pouze některé podmnožiny objektů scény. Tím ušetříme čas překreslení stínové mapy pro změny jen v částech scény. Dalším možným zrychlením, a také zpřesněním výpočtu stínové mapy, je ořezání předních částí objektů a vykreslení pouze zadních částí. 2.5.2.2
Aplikace stínové mapy na scénu
V dalším kroku vykreslíme scénu z pohledu kamery a aplikujeme na ni vypočtenou stínovou mapu. Tento finální krok můžeme rozdělit na tři hlavní části. Výpočet souřadnic viditelných objektů z pohledu světla, porovnání hloubkových map a určení, zda je objekt osvětlen nebo zastíněn, a výsledné vykreslení objektu s aplikovaným osvětlením, nebo zastíněním. Pro druhý krok, porovnání hloubky vykresleného bodu s hloubkou ve stínové mapě, je potřeba souřadnice bodu transformovat tak, aby se souřadnice nacházely ve stejném prostoru pohledu. Známe souřadnice bodu v daném prostoru, ale potřebujeme tyto souřadnice transformovat do prostoru světla. To provádíme násobením transformačních matic. Transformační matici pro převod ze světových souřadnic do souřadnic z pohledu světla jsme již použili při generování stínové mapy. Tato matice převede souřadnice do normalizovaného tvaru po projekci.Tím všechny složky nabývají hodnot od −1 do 1. Potřebujeme ještě ale matici pro posun souřadnic do rozmezí od 0 do 1 tak, jak je uložena stínová mapa v textuře hloubek. Tato matice je jednoduchá, zmenší souřadnici na polovinu a posune ji o polovinu. Vypadá následovně:
0.5 0.0 0.0 0.0
0.0 0.5 0.0 0.0
0.0 0.0 0.5 0.0
0.5 0.5 0.5 1.0
(2.12)
Nyní máme souřadnice bodu ve shodném prostoru jako souřadnice bodu v hloubkové mapě a můžeme porovnávat hodnoty. Pokud je hodnota z aktuálního bodu větší než hodnota uložená ve stínové mapě, jde o objekt z pohledu světla schovaný za jiným objektem, a proto bude ve výsledku zastíněn. Jinak je bod klasifikován jako nezastíněný. Může nastat situace, kdy daná poloha bodu x, y není v hloubkové mapě definovaná. V tomto případě se můžeme rozhodnout, zda budeme bod klasifikovat jako zastíněný nebo ne. Většinou ale říkáme, že není zastíněn.
2.5. STÍNOVÉ MAPY
19
Touto technikou mohou vznikat na hranách stínu malé čtverce. Ty lze částečně redukovat vyšším rozlišením stínové mapy. Můžeme také ostré hrany vylepšit o jemnější přechod a to tak, že budeme brát v potaz více okolních hodnot. Výsledné vykreslení scény se stíny může být provedeno několika způsoby. Pokud použijeme programovatelný shader, můžeme po vyhodnocení zastínění aktuálního bodu ve fragment shaderu ihned vykreslit výsledný pixel. Pokud ovšem používáme fixní výpočetní řetězec, musíme využít některé hardwarové rozšíření (například GL_ARB_Shadow).
20
KAPITOLA 2. EXISTUJÍCÍ METODY
Kapitola 3 Analýza a návrh implementace Teoretické znalosti, jak metody pracují, již známe. To je stěžejní pro další část, ve které se budeme věnovat analýze a návrhu implementace. Samotné znalosti jak metody pracují, jsou důležité, ale v programování GPU narážíme na řadu omezení, a tak některé jednoduché teoretické předpoklady mohou vyústit při samotné implementaci ve velmi těžko řešitelný problém.
3.1
Implementační prostředí
Podle zadání práce budou metody implementovány do vizualizačního nástroje VRUT. Pro velkou složitost celého tohoto nástroje jsem se ale rozhodl, že vývoj shaderu pro přímé zastínění okolím provedu v samostatné aplikaci pro testování. K tomuto kroku jsem se rozhodl hlavně kvůli tomu, abych oddělil chyby v přepínání stavů OpenGL a chyby v samotném shaderu. Po úspěšném dokončení vývoje shaderu pro přímé zastínění bodu okolím bude v nástroji VRUT vytvořen vykreslovací modul s názvem ssdoRenderer, do kterého bude tato otestovaná metoda přenesena. Modul musí, tak jako celá aplikace VRUT, být spustitelný jak na operačním systému Windows, tak i Linux. A to jak v 32 tak i v 64 bitové verzi. Díky čemuž v něm nemůže být použita spousta pomocných knihoven specifikovaných pouze pro konkrétní operační systém. Požadavek zadavatele je také nepoužívat zbytečně mnoho externích knihoven a tak budeme vycházet z již použitých knihoven OpenGL, GLEW(The OpenGL Extension Wrangler Library) a wxWidgets. Samotné shadery budou psány v jazyce GLSL(OpenGL Shading Language). Tyto jsou načítány a kompilovány až při samotném spuštění aplikace. Vše si obstarávají ovladače dané grafické karty, a proto jsou také použitelné na všech platformách.
3.2
Podpora vykreslování v systému VRUT
Základní třída pro vykreslování scén v systému VRUT je RenderGlModule, na které je postaven i hlavní vykreslovací modul renderGl. Tato třída zajišťuje kom-
21
22
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
Obrázek 3.1: Ukázka systému VRUT
pletní vykreslování veškeré podporované geometrie a materiálů. Systém podporuje celou řadu materiálů, které mohou obsahovat i shadery. Jedním z požadavků zadavatele bylo, aby veškeré vykreslovací moduly používaly co možná nejvíce funkcí a definicí třídy RenderGlModule. Tedy každý vykreslovací modul dědí tuto třídu, a měl by co nejvíce využívat její funkce a procedury. Je to hlavně proto, aby bylo možné jakékoliv změny pro příkazy OpenGL provést pouze ve třídě RenderGlModule a ostatní vykreslovací moduly tyto změny jednoduše zdědily. Z tohoto důvodu si nejprve analyzujeme pro nás důležité části této třídy a navrhneme potřebné změny pro to, abychom mohli využít co nejvíce jejich částí.
3.2.1
RenderGlModule
Jako první je při vykreslení aktivní načtené scény volána funkce pro inicializaci. Zde se provádí nastavení OpenGL stavů, kontrola podpory hardwarových rozšíření, a pokud jsou podporovány FBO (Frame buffer object), tak jejich nastavení. Všechna tato volání budou potřebné i v modulu ssdoRenderer. Pouze je potřeba doplnit inicializaci knihovny GLEW a dalších použitých FBO. Funkce volaná pro vykreslování vždy kontroluje inicializaci, zda byla úspěšně provedena a případně ji znovu vyvolá. V další fázi je prováděna kontrola parametrů aktuální scény a jejich případná aktualizace. Pokud neexistuje aktivní scéna, nebo pokud nemá požadované parametry, jako například definovanou kameru, vykreslovací funkce končí. Dále se nastaví projekční a modelovací matice a je zavolána funkce scény, která dle aktuální kamery ve scéně rozdělí celou scénu na čtyři části.
3.2. PODPORA VYKRESLOVÁNÍ V SYSTÉMU VRUT
23
Obrázek 3.2: Rozdělení scény na vykreslované celky
3.2.1.1
Vykreslení scény
Uzly scény jsou rozděleny na uzly s neprůhlednými objekty, průhlednými objekty, a nebo objekty reflektujícími. Toto rozdělení je velice důležité pro samotné vykreslení, protože pro vykreslení každé skupiny je potřeba jiného nastavení OpenGL stavů. Je potřeba také dodržet správné pořadí při vykreslování. Ještě zbývá poslední čtvrtá skupina uzlů scény, kde jsou objekty neviditelné z aktuální kamery a ty není potřeba vykreslovat. Nyní nastává fáze samotného vykreslení viditelných objektů ve scéně. Jako první jsou vykreslovány reflektující objekty. Pro tyto speciální objekty je třeba vykreslit vždy pro každý objekt znovu celou scénu, a to z pohledu daného objektu. Výsledný obraz je pak potřeba v závislosti na poloze kamery správně namapovat na reflektující objekt. Vykreslení jednoho reflektujícího objektu je tak velice náročné. Ovšem v reálných scénách takových objektů není velké množství, a proto zásadněji neovlivňuje rychlost celého vykreslovacího modulu. V dalším kroku se vykreslí všechny uzly scény obsahující pouze neprůhledné materiály, a potom všechny uzly s průhlednými materiály. Na závěr vykreslíme pozadí, pokud existuje, a text vkládaný do scény. 3.2.1.2
Antialiasing
Třída RenderGlModule nabízí možnost spustit antialiasing (neboli vyhlazování hran), pokud hardware, na kterém je systém spuštěn, umožňuje použití frame buffer objects a zároveň podporuje hardwarové rozšíření (GL_EXT_packed_depth_stencil) pro uložení v jedné textuře jak pamět hloubky, tak i paměť šablony. Pokud tohle všechno hardware podporuje, můžeme zvolit jednu ze dvou technik pro antialiasing. Tyto techniky musí být opět podporovány hardwarem. První technika je použití vícenásobného vzorkování a druhá je testování pokrytí. Před samotným vykreslením geometrie scény se aktivuje patřičně nastavený FBO, do kterého je vše vykresleno. Poté se výsledný obraz, uložený v paměti barev jako textura, mapuje na obdélník, který je přes celé okno a tím se vykreslí výsledný obraz.
24
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
Obrázek 3.3: Vykreslení objektu bez antialiasingu (nalevo) a s antialiasingem (napravo)
3.2.2
RenderTarget
Jelikož jsou pro vykreslování v různých modulech hojně používány FBO, tak je pro ně v jádru systému vyvinuta třída pro jejich správu. Tou je právě třída RenderTarget. Jelikož třída podporuje vše potřebné i pro modul ssdoRenderer, bude ji také hojně využívat. Třída obstarává jak samotnou inicializaci dle specifikovaných parametrů, tak jednoduchou aktivaci a deaktivaci. Obstarává správu přiřazených textur, a to jak inicializaci, tak i při zrušení objektů jejich správné odstranění. Podporuje také přidání vykreslovací paměti (render buffer) a opět veškerou správu všech přiřazených textur. Při změně rozlišení okna lze snadno zavoláním patřičné funkce provést přenastavení rozlišení všech přiřazených textur.
3.2.3
Mapa okolí
Metoda přímého zastínění v obrázku vyžaduje pro správný výpočet mapu prostředí. V systému VRUT je nyní implementována pouze mapa okolí pro daný uzel scény. Tato mapa může být sférického typu, nebo typu okolní krychle. Pro druhý případ je ale nyní podporováno pouze načtení jedné textury, která je použita pro všechny stěny krychle. Tento stav je pro modul ssdoRenderer nevyhovující a bude třeba jej doplnit a rozšířit. V první řadě je třeba přidat nový typ uzlu scény, který bude definovat globální mapu okolí pro celou scénu. Bude to uzel BackgroundNode. Uzel nepotřebuje žádnou geometrii, bude obsahovat pouze odkaz na materiál. Třída Material, která obsahuje veškeré potřebné a podporované typy materiálu, bude muset být doplněna o správnou definici textur pro krychlovou mapu okolí. Nynější krychlová mapa okolí
3.3. VÝPOČET ZASTÍNĚNÍ
25
s jednou texturou pro všechny stěny bude doplněna o definici ostatních stěn samostatnými texturami. Pro tyto účely bude třeba doplnit i třídu Image pro samotné načítání textur. Další potřebnou změnou bude doplnění importérů scén. Systém VRUT nyní disponuje několika moduly pro načítání a ukládání různých formátů scén. Jako hlavní a nejvíce využívaný je brán modul pro načítání scén formátu FHS. Je to formát komerčního software Virtual Design 2 (VD2), který byl hojně využíván v automobilovém průmyslu. Dalším, a v dnešní době mnohem rozšířenějším formátem pro 3D scény, je formát pro virtuální realitu VRML (Virtual Reality Modeling Language). Tento formát sice nemá takové možnosti jako formát FHS, ale za to je velice rozšířený a ve spoustě komerčních nástrojů pro 3D modelování dostupný. V aktuální implementaci modulu pro import a export scén formátu VRML bohužel není podpora pro pozadí implementována. Samotný formát VRML však tuto vlastnost podporuje, a to definicí uzlu Background, ve kterém jsou odkazy na textury pro všech šest stěn krychle. Proto jsem se rozhodl o doplnění tohoto modulu o podporu načítání textur okolí. Ve scéně tak bude po těchto úpravách nově uzel BackgroundNode, který bude obsahovat materiál s krychlovou globální mapou okolí. Doplněna bude také třída RenderGlModule pro správné vykreslení pozadí definovaného v uzlu BackgroundNode, který bude obsahovat materiál s šesti texturami. Ty budou mapovány na vykreslenou krychli.
3.3
Výpočet zastínění
Výpočet stínů ve scéně pomocí metody přímého zastínění v prostoru obrázku se provádí na GPU, a to hlavně ve fragment shaderu. Díky potřebným parametrům pro výpočet, jako je textura hloubky a textura normál, je třeba výpočet zastínění rozdělit do několika dílčích kroků. V prvním kroku potřebujeme získat všechny potřebné parametry pro výpočet stínu. To jsou hlavně hloubková a normálová mapa. V dalším kroku s pomocí hodnot získaných v předchozím kroku vypočteme samotné zastínění bodů ve scéně. V posledním kroku aplikujeme výsledné textury a vykreslíme scénu včetně vypočtených stínů. Tento poslední krok by se mohl spojit s předchozím a vykreslit výsledný obraz rovnou v kroku dva, ale pro další důvody, jako například aplikace rozostření stínů, bude vhodnější kroky rozdělit.
3.3.1
Před-výpočet
Jak jsem již uvedl, pro samotný výpočet zastínění je potřeba znát hloubku všech vykreslených bodů v obraze a také normály v těchto bodech. Hloubkovou mapu lze získat jednoduše vykreslením scény a následným kopírováním hloubkové paměti. Stejný způsob bohužel nelze použít i pro mapu normál. Tu lze získat pouze ve vertex procesoru a neexistuje pro ni žádné hardwarové rozšíření. Proto musíme použít shader, ve kterém si pro každý bod obrazu zaznamenáme aktuální normálu.
26
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
Obrázek 3.4: Ukázka hloubkové a normálové mapy
V tomto bodě ale nastává kolizní situace s shadery použitými pro materiály. Veškeré shadery ve scéně musí být při aktivaci shaderu pro získání zmíněných textur vypnuty. Zároveň nastává problém kde a jak získat texturu s výsledným barevným obrazem celé scény. Výsledný obraz, pokud se ve scéně nenachází žádné materiály s shadery, by mohl být vypočítán v shaderu, ale pokud bude některý materiál shader obsahovat, už to nepůjde. Z tohoto důvodu bude potřeba udělat další vykreslovací krok navíc pro získání pouze barevného obrazu scény. Získání potřebných textur tak musíme rozdělit na dva kroky. Jeden pro získání barevného obrazu a druhý pro získání textury hloubky a normál. Pro správný výpočet stínu budeme také potřebovat znát hloubkovou a normálovou mapu zvlášť pro neprůhlednou geometrii a průhlednou. Je to z důvodu výpočtu stínu i za průhlednou geometrií. Pokud by se tyto textury nerozdělily, neměli bychom žádné informace o geometrii za průhledným objektem a tak by v těchto místech nemohly být vypočítány stíny. 3.3.1.1
Neprůhledné materiály
Pro zaznamenávání všech textur budeme používat frame buffer. Je to hlavně z důvodu rychlosti a možnosti jednoduše kopírovat více textur dohromady. Použití obyčejných textur by bylo velice pomalé, a zbytečně by zatěžovalo operační paměť. V prvním kroku si spustíme shader pro získání normál, vykreslíme neprůhlednou geometrii a uložíme výslednou normálovou a hloubkovou texturu. Další krok bude stejný, ale s tím rozdílem, že nepoužijeme žádný shader, ale vykreslíme neprůhlednou geometrii s použitím jejich materiálů (i materiálů s shadery). Nyní si uložíme pouze výsledný barevný obraz. 3.3.1.2
Průhledné materiály
Nyní máme uloženy tři textury pro neprůhledné materiály a můžeme přejít na průhledné. U průhledných materiálů začneme opačně než v předchozím kroku, a to od textury barev. Vykreslíme průhledné objekty a výsledný barevný obraz si opět uložíme do textury. Důležité je, abychom mezi předchozím a tímto krokem
3.3. VÝPOČET ZASTÍNĚNÍ
27
nevymazali paměť barev a hloubky. Tím získáme výsledné textury obsahující jak průhledné, tak i neprůhledné objekty. Hloubkovou a barevnou paměť nemažeme z toho důvodu, abychom měli informaci o barevném obraze i za průhlednými objekty. Kdybychom paměť vymazali a měli tak pouze informace o průhledných objektech, nedokázali bychom potom vygenerovat výsledný obraz obsahující všechny objekty správně. Vysvětlím na příkladu. Máme scénu, ve které jsou za sebou čtyři kostky v pořadí průhledná, neprůhledná, průhledná a neprůhledná. Máme dvě textury, pouze s průhlednými a pouze s neprůhlednými objekty. Podle hloubkové mapy poznáme, který objekt je první (průhledný) a tak použijeme barvu z této textury a dle alfa kanálu spojíme s texturou neprůhledných objektů. A problém je v tom, že máme obraz obou průhledných kostek před první neprůhlednou. Proto je potřeba mít barevnou texturu pro průhledné objekty i s objekty neprůhlednými. V dalším kroku již paměť vymazat musíme a znovu vykreslíme průhledné objekty, ale s aktivním shaderem pro získání normál a hloubky každého bodu obrazu. Opět vše uložím pro další použití. Tímto jsme získali všechny potřebné textury pro výpočet zastínění a můžeme tak přejít k jeho samotnému výpočtu.
3.3.2
Výpočet zastínění a odrazů barev
Zastínění budeme počítat opět hlavně na fragment procesoru a pro každý bod obrazu zvlášť. Jak je rozvedeno v úvodní části, pro výpočet potřebujeme znát hloubky a normály ve všech bodech obrazu. Ty jsme získali v předchozím kroku. Dále potřebujeme mapu okolí. Pokud ve scéně existuje uzel s pozadím, použijeme mapu okolí uloženou v tomto uzlu. Pokud uzel s pozadím ve scéně neexistuje, budeme předpokládat konstantní osvětlení z celého okolí scény. 3.3.2.1
Generování vzorků
Jako první pro samotný výpočet zastínění potřebujeme generovat vektory pro vzorkování okolí. Vzorky potřebujeme generovat na hemisféře ve směru normály v daném bodu. Můžeme zvolit jeden ze dvou způsobů rozložení vzorků na této hemisféře, a to vzorky s uniformním, nebo Gaussovým rozložením. Obojí má své výhody a nevýhody. Uniformní rozložení dokáže při minimálním počtu vzorků lépe pokrýt zkoumané okolí bodu. Můžeme ho provést tak, že dle počtu vzorků zvolíme určitý úhlový krok a tak postupujeme hemisférou. Pro malé počty vzorků ovšem hrozí, že nepokryjeme hlavní příchozí směr osvětlení, a to ve směru normály. Naopak zase pokryjeme lépe oblast blízkou kolmici k normále v bodě. Pro Gaussovo rozložení se rozhodneme, pokud chceme vzorky soustředit více ve směru normály. Tento způsob má nevýhodu špatného pokrytí oblastí blížících se kolmici k normále v bodě. Pro malý počet vzorků tak nemusíme poznat mírně
28
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
se vlnící geometrii. Výhodou takto generovaných vektorů je ovšem větší důraz na reálné putování světla ve scéně. Největší podíl na osvětlení bodu má směr normály. Proto, pokud budeme vektory soustřeďovat k normále v bodu, bude zastínění lépe simulovat reálné prostředí. Budeme tedy používat tento způsob generování vzorků.
Obrázek 3.5: Příklad Gaussova (vlevo) a uniformního (vpravo) rozložení vzorků na hemisféře Vygenerované vektory budou dále použity k testování zastínění z daného směru. 3.3.2.2
Převod mezi prostory
Pro testování generovaných bodů s hodnotami uleženými v texturách je třeba mít hodnoty vždy ve správném prostoru. Ve fragment shaderu se většinou počítá v prostoru obrázku, kde jsou hodnoty v rozsahu od 0 do 1. Ve vertex procesoru zase pracujeme s hodnotami ve světových souřadnicích. Pro přesnost výpočtu budeme většinu výpočtů a porovnání dělat právě ve světových souřadnicích. Ale hodnoty uložené v pomocných texturách jsou zase v prostoru obrázku. Proto bude třeba mezi těmito dvěma prostory převádět. Prostor obrázku je od světového prostoru odlišný tím, že je vynásoben projekční maticí a posunut do souřadnic prostoru obrázku. 3.3.2.3
Zastínění
Pro všechny vygenerované směry (vektory) nyní potřebujeme v určité vzdálenosti r otestovat, zda v tomto místě neexistuje nějaký objekt, který by daný bod zastiňoval. V shaderu máme k dispozici světové 3D souřadnice aktuálního bodu P . Když k nim přičteme vzorkovací vektor V o velikosti r, dostaneme souřadnice testovaného bodu S také ve světových souřadnicích. S = P + rV
(3.1)
Nyní máme bod, který je ve světových souřadnicích, a potřebujeme zjistit, zda leží uvnitř nějakého objektu. Proto jej potřebujeme převést do prostoru obrázku, abychom mohli porovnat hodnotu z vzorku a uloženou v hloubkové mapě. Po převodu jen stačí porovnat, zda je hodnota v hloubkové mapě větší (vzorkovací bod je nad povrchem), nebo menší (bod se nachází pod povrchem a tak zastiňuje bod
3.3. VÝPOČET ZASTÍNĚNÍ
29
P ). Tento krok provedeme pro všechny vygenerované vzorky, a poté vyhodnotíme míru zastínění okolím. Jak již bylo zmíněno v úvodu, může nastat situace, kdy vzorek se nachází nad povrchem, ale mezi vzorkem a aktuálním bodem se nachází objekt, který by jej měl zastiňovat. Pro redukci tohoto problému se používá vícenásobné vzorkování v jednom směru. Tuto techniku také použijeme. Vicenásobné vzorkování v jednom směru V jednom vygenerovaném směru (vektoru) budeme testovat ve více vzdálenostech. Vygenerovaný vektor otestujeme ve čtyřech vzdálenostech, a to uniformě rozložených. Zvolil jsem rozdělit vzdálenost na čtyři části. Určitě by bylo lepší oblastí víc (čím víc, tím menší pravděpodobnost chyby), ale každý test navíc stojí při součtu všech bodů obrazu hodně času, a tak jsem vybral kompromis mezi rychlostí a kvalitou. Vektor je tak nejprve vynásoben hodnotou rádius, kterou lze nastavit patřičnou šířku oblasti pro zastínění, a poté testován postupně v 1/4, 1/2, 3/4, 1/1, zda je pod povrchem. Pokud se nalezne pod povrchem, a tím pádem je vyhodnocen jako zastiňující, další testy se již přeskočí. Celkové příchozí osvětlení Jakmile je vektor vyhodnocen jako nezastiňující (nenarazil ve svém směru na žádný objekt), je pomocí vektoru načtena příchozí hodnota osvětlení z mapy okolí. Pokud scéna okolí neobsahuje, je hodnota rovna maximálnímu osvětlení 1. Pro škálovatelnost je tato hodnota ještě vynásobena určitou hodnotou zastínění. Na závěr, když známe hodnoty příchozího osvětlení pro všechny vzorky, jsou tyto hodnoty sečteny a vynásobeny velikostí plochy hemisféry, která je rozdělena dle počtu vzorků. Ldir∗ = (2.0 ∗ π/s)
(3.2)
Kde Ldir je součet příchozího osvětlení ze všech nezastíněných bodů a S je počet vygenerovaných vzorků. 3.3.2.4
Odrazy nepřímého osvětlení
Výpočet zastínění bodu jsem také doplnil o metodu odrazů barev. Samotný výpočet odrazů barev je doplněn k výpočtu zastínění. A to tak, že pokud je daný vygenerovaný směr vyhodnocen jako zastiňující, je proveden ještě výpočet barevného odrazu od zastiňujícího objektu. Když vzorek zastiňuje, je tudíž pod povrchem nějakého objektu. Pokud chci zjistit správnou barvu na povrchu tohoto objektu, potřebuji provést projekci tohoto bodu na povrch.
30
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
Obrázek 3.6: Příklad projekce bodu S na povrch
Ukažme si to na příkladu v obrázku 3.6. Máme bod S, který je vzorek zastiňující bod P . Ten je ve světových souřadnicích a musíme jej převést do prostoru obrázku. To provedeme vynásobením projekční maticí. Potom vezmeme jeho souřadnice x a y, ke kterým doplníme hodnotu z z hloubkové mapy právě v těchto souřadnicích x,y. Tyto tři souřadnice jsou bodem na povrchu objektu (bod Sp). Ten je nyní ovšem zase v prostoru obrázku a pro výpočet, zda bude na bod P odrážet svou barvu a v jaké intenzitě jej musíme převést zpět do světových souřadnic. K tomu použijeme inverzní projekční matici. Po převedení bodu Sp do světových souřadnic zbývá vypočítat úhel, jaký mezi sebou mají normála bodu P (N p) a bodu Sp (N s) a tyto hodnoty dát do vzorce 2.10 pro výpočet odraženého osvětlení z bodu Sp. V tomto vzorci se nalézá hodnota As, která opět určuje plochu hemisféry dělenou počtem vzorků. Tuto hodnotu násobíme konstantní hodnotou pro korekci síly odrazu nepřímého osvětlení.
3.3.2.5
Výstupní textury
Jelikož budu hodnoty zastínění a nepřímého osvětlení v dalším kroku dále upravovat (bude na ně aplikováno rozostření), je třeba je uložit zvlášť. Proto bude do jedné textury v paměti uložena hodnota zastínění bodu, a do druhé textury hodnota nepřímého osvětlení.
3.3.3
Finální obraz
Nyní máme vypočtené stíny (jedna textura), odrazy barev (druhá textura) a texturu s barevným obrazem celé scény. Textury se stíny a odrazy barev jsou ale se značným šumem. Protože dle počtu použitých vzorků pro výpočet je stínování více či méně rastrované, je třeba použít nějakou techniku filtrování. Jelikož potřebujeme ale rozostřit pouze stíny a odrazy, nemohli jsme spojit obrazy již dříve. Dalším úskalím při rozostření stínů nastane, pokud je rozostříme bez ohledu na geometrii. V tomto případě se ostré přechody konců stínů rozostří také a vedle objektu se silnými stíny vzniknou světlé mezery, které tam nesmí být. Proto je potřeba použít filtrování citlivé na geometrii.
3.3. VÝPOČET ZASTÍNĚNÍ
3.3.3.1
31
Gaussův filtr
Po několika pokusech s různými typy rozostření obrazu jsem zvolil asi nejefektvnější Gaussovo filtrování. To je aplikováno dvakrát, a to ve vertikálním směru, a poté v horizontálním. V prvním průchodu pracuji pouze s body ve vertikálním směru, pouze souřadnice y. A poté na takto filtrovaném obraze v druhém průchodu pracuji pouze v horizontálním směru, pouze souřadnice x. Výsledná hodnota každého bodu je složena z kombinace jeho okolí v daném směru. Vyhodnocují se vždy čtyři body na obě strany, takže výsledný bod má hodnotu složenou z devíti bodů. Hodnoty příspěvků bodů jsou následující: (0.05, 0.09, 0.12, 0.15, 0.18, 0.15, 0.12, 0.09, 0.05) Příklad výsledného použití můžeme vidět na obrázku 3.7. Nalevo je pouze jeden bod (bod znázorňuje jeden pixel) bez rozostření. Uprostřed je po průchodu vertikálním filtrováním. A napravo po průchodu horizontálním filtrováním (tento obraz je asi pětkrát tmavší než by měl být, aby bylo něco vidět). To by bylo ohledně techniky filtrování, ale ještě je třeba zajistit, aby bylo rozostření citlivé na geometrii, protože jakmile narazí na hranu objektu, tak přes ni nesmí rozostřovat. Jelikož máme uloženou mapu normál pro celý obraz, můžeme použít pro detekci hran právě ji. Budeme pro každý bod kontrolovat i jeho normálu, pokud bude stejná, nebo s určitou maximální výchylkou, můžeme bod použít k rozostření. Odchylku musíme povolit kvůli zakřivené geometrii. Tato musí být nastavena tak, aby dovolila rozostřit vše, co se rozostřit má, a zároveň, aby se rozostřilo co nejméně geometrie, co se rozostřit nemá.
Obrázek 3.7: Ukázka aplikace filtrování
Na závěr je ještě v tomto kroku při druhém průchodu, kde se provádí horizontální filtrování, složen celý výsledný obraz. K barevné textuře je přičtena textura s filtrovanými stíny a filtrovanými barevnými odrazy.
32
3.4
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
Stíny od lokálního světla
Pokud jsou aktivované stínové mapy, provede se ještě výpočet jedné hloubkové textury navíc před samotným výpočtem zastínění, protože pro správný výpočet stínů od lokálního světla potřebuji znát hloubku objektů z jeho pohledu. V tomto kroku navíc se vykreslí pouze neprůhledná geometrie, která vrhá stíny. V tomto kroku, kdy je kamera nastavena do pozice světla, se zároveň zaznamená projekční matice pro pozdější mapování stínu na scénu. Ta se vytvoří dle teorie výše jako součin matice posunu, modelovací matice a matice projekční.
3.4.1
Sebe-zastínění
Každá metoda stínových map má ovšem své nedostatky, a to hlavně chybu vrhání stínu sama na sebe. Tento problém se dá potlačit spoustou technik, ovšem opět roste náročnost celého výpočtu. Protože již samotná metoda SSDO s technikou výpočtu nepřímého osvětlení je velice výpočetně náročná, zvolil jsem techniku pro potlačení sebe-zastínění výpočetně jednodušší. A to jednoduché přizpůsobení posunutí povrchu stínové mapy o daný offset. Pro zaznamenání hloubkové mapy tak používám shader, ve kterém kromě aktuální hloubky v bodě (vzdálenost od světla) zaznamenávám také gradient v daném místě. Ten zaručí potřebnou toleranci pro posun stínové mapy tak, aby nedocházelo k sebe-zastínění, a zároveň minimální možnou toleranci pro korektnost stínů.
3.4.2
Kombinace s metodou SSDO
Samotný výpočet stínů, pokud je funkce zapnuta, probíhá ve stejném shaderu jako výpočet zastínění a nepřímých odrazů. Pomocí Chebyshevovy vzdálenosti. Pokud je objekt mimo záběr světelného zdroje, tak se stín nevytváří. Pokud by byly lokální světla hlavním zdrojem osvětlení ve scéně, bylo by lepší tuto podmínku zvolit obráceně, tedy, pokud není objekt v záběru světla, vyhodnotit jej jako zastíněný. Ale pokud používáme k výpočtu příchozího osvětlení v metodě SSDO globální mapu okolí, je tato volba nevhodná. Hodnota vypočteného stínu od lokálního světla je na závěr přičtena k zastínění vypočtenému metodou SSDO a uložena v paměti.
3.5
Nastavovací parametry a GUI
Jak jsem již několikrát zmínil, u některých výpočtů budou použity nastavující hodnoty. Jelikož každá scéna má jiné parametry, tak nelze docílit univerzálního nastavení všech výpočtů. Z tohoto důvodu bude grafické rozhraní rozšířeno o další volitelné parametry. Základní prvky jsou již děděny z třídy RenderGlRenderer. Tyto zděděné prvky jsou:
3.5. NASTAVOVACÍ PARAMETRY A GUI
33
Obrázek 3.8: Schéma vykreslovacích průchodů
• sceneID – ID aktuální vykreslované scény • cameraID – ID kamery, ze které je scéna vykreslovaná • useVBO – při vykreslování použít VBO(Vertex Buffer Object) • wireFrame – vykreslení pouze drátěných modelů • lighting – povoleno osvětlení • texturing – povoleno texturování • headlight – aktivní přední světlo • backFaceCull – povoleno ořezaní zadních stran objektů • alfaToCoverage – vyhlazování pomocí alfa testování • drawBVH – vykreslení BVH (bounding volume hierarchy) struktury • drawUsingFBO – vykreslení pomocí FBO • sortGeometries – seřazení geometrie podle materiálů (omezení přepínaní OpenGL stavů) • dualDVI20BitColors – aktivní podpora pro 30bitové barvy • antiAliasingColorSampleCount – počet vzorků barev pro výpočet antialiasingu • antiAliasingCoverageSampleCount – počet porovnávacích vzorků pro výpočet antialiasingu • fboInternalFormat – vnitřní formát FBO
34
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
• showStats – zobrazení statistiky ve vykreslovaném okně • messageString – zprávy zobrazené ve vykreslovaném okně • antiAliasingMethod – metoda výpočtu antialiasingu
Obrázek 3.9: Grafické rozhraní ovládání parametrů ssdoRendereru Parametry potřebné pro nastavení ssdoRendereru jsou: • numSamples – počet vzorků použitých pro výpočet zastínění a odrazů • radius – poloměr hemisféry použitý pro výpočet zastínění a odrazů • shadowAtt – nastavení síly zastínění • colorBounceAtt – nastavení síly barevných odrazů • blurOffset – nastavení kroku pro rozostření • enableShadowMap – aktivace stínových map • enableDoubleBlur – aktivace dvojitého rozostření • ssdoEnable – aktivace výpočtu zastínění a odrazů barev • Draw texture – vykreslovaná textura • Statistics – výpočet a zobrazení počtu trojúhelníků ve scéně Nastavení všech parametrů se provede při startu na základní hodnoty. Ty ovšem nejsou vždy ty nejlepší, a proto je třeba nastavení upravit dle aktuální scény. Jak který parametr ovlivňuje výpočty, si popíšeme v kapitole konfigurace.
Kapitola 4 Popis implementace Po důkladné analýze a návrhu jsem mohl přistoupit k implementaci. Jak jsem uvedl, první jsem začal pracovat na vývoji shaderu pro výpočet zastínění a odrazu barev. Ten byl vyvíjen v externí testovací aplikaci. Dále jsem pokračoval vytvořením nového modulu v systému VRUT, a postupně jsem implementoval všechny funkce. Celý postup implementace zde uvádět nebudu, pokusím se pouze zmínit o všech úskalích a problémech, které nastaly.
4.1
Nový modul
Začnu asi tou nejjednodušší věcí, a to vytvořením nového vykreslovacího modulu. Tento postup je dobře popsán v dokumentaci k systému VRUT. Pro nový vykreslovací modul je třeba pouze okopírovat celý renderGl, který je tou nejzákladnější verzí vykreslovacího modulu a který vše dědí z třídy RenderGlModule. Poté už jen stačí vytvářet potřebné nové funkce nebo rozšiřovat stávající. Pro vývoj systému jsou také udržovány aktuální soubory pro vývojové prostředí Microsoft Visual Studio. Já mám toto prostředí oblíbené a tak jsem také pro implementaci použil tento nástroj.
4.2
Správa shaderů
Ve třídě RenderGlModule je vytvořena funkce pro práci s shadery v materiálech. Funkci je předán ukazatel na materiál, kde jsou shadery, a ta provede veškeré nastavení parametrů, kompilaci shaderu i jeho spuštění. Byla snaha využít této funkce pro práci i v modulu ssdoRenderer, ale nakonec bylo potřeba si vytvořit vlastní podporu pro práci s shadery. Ve vykreslovacích průchodech je třeba často aktivovat a deaktivovat shadery a navíc jim přiřazovat aktuální parametry. Toto by bylo s již hotovou podporou zbytečně náročné. A tak jsem si vytvořil vlastní třídu Shader, ve které jsem vytvořil podporu jak pro jednoduchou aktivaci a deaktivaci, tak i nastavování všech parametrů, načtení, kompilaci i zrušení.
35
36
4.3
KAPITOLA 4. POPIS IMPLEMENTACE
Frame buffer objects
Hlavním a také jediným uložištěm pro všechny obrazy v mezikrocích jsou FBO. Těchto je v modulu použito několik jak pro uložení paměti hloubky, obrazu, tak i stínové mapy a všech potřebných mezikroků. Největší problém ovšem s těmito objekty nastal při pokusu o skloubení použité techniky pro antialiasing. Ten je prováděn fixně při vykreslování scény do daného FBO, kde využívá jak paměť hloubky, tak i paměť šablony. Bohužel řada výpočtů v ssdoRendereru probíhá pouze na vykresleném obdélníku přes celé okno. Tím ztrácíme informaci o hloubce a o šabloně. A tím také přestává metoda antialiasingu pracovat. Dlouze jsem zkoušel různé alternativy. Nakonec jsem se rozhodl aplikovat antialiasing před samotným výpočtem stínu, a to již při získávání textury výsledného obrazu. Pokud je antialiasing aktivován, je obraz první vykreslen do daného FBO. Z něj si potom kopíruji potřebné textury následujícím způsobem: glBindFramebufferEXT( GL_READ_FRAMEBUFFER_EXT, readFBO); glBindFramebufferEXT( GL_DRAW_FRAMEBUFFER_EXT, drawFBO); const GLsizei &w(windowWidth); const GLsizei &h(windowHeight); glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glBlitFramebufferEXT( 0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); Tímto způsobem již získám do svého FBO obraz po aplikaci antialiasingu. Tato technika byla jediná možná, aby byla pro výsledný obraz zachována funkce antialiasingu. Bohužel i tak jsem narazil dále na problém. Ten nastal při skládání výsledného obrazu z textury barev a stínů a odrazů. Tento krok se provádí na vykresleném obdélníku přes celý obraz a tak na něj nemůže být technika vyhlazování hran použita. A tím nastává problém. Pokud stín rozmazávám dle mapy normál, je dodržena geometrie, ale stín zůstane bez vyhlazených hran. Ale texturu s obrazem mám již vyhlazenou a tak zde vznikají drobné vady. Většinou jsou nepatrné, ale v některých specifických případech jsou viditelné. Snažil jsem se tento problém odstranit, ale s použitou technikou pro vyhlazování hran jsem na možný způsob nápravy nepřišel.
4.4
Implementace shaderů
Při implementaci shaderu pro výpočet zastínění a odrazů se vyskytlo asi nejvíce problémů a úskalí. Z části to byla vina malé zkušenosti s programováním na GPU, ale z větší části to byly nepředvídatelné chyby ovladačů grafické karty. Veškerou implementaci jsem prováděl u sebe na soukromém notebooku, který má grafickou kartu ATI. Často se ale stalo, že co jsem odladil na této kartě, tak na kartě nVidia nefungovalo, nebo fungovalo špatně. Bohužel detekcí těchto chyb jsem strávil spoustu času.
4.4. IMPLEMENTACE SHADERŮ
4.4.1
37
Náhodné číslo
První zajímavý problém při implementaci shaderu byla potřeba generování náhodného čísla. Tuto možnost nabízí v GLSL funkce noise(). Ovšem číslo generované touto funkcí je spíše stále stejné než náhodné. Proto jsem použil vlastní generátor pseudonáhodných čísel. Pracuje se vstupním dvojrozměrným vektorem, dle kterého vygeneruje pseudonáhodné číslo.
float rand(vec2 co) { return fract(sin(dot(co.xy , vec2(12.9898,78.233))) * 43758.5453); }
Jako vstup této funkce používám aktuální souřadnice bodu v okně. Navíc, pro každý vzorek ve stejném bodě dělím souřadnici okna číslem aktuálního vzorku. Tím dostanu mnohem kvalitněji generovaná pseudonáhodná čísla, než pomocí funkce noise().
4.4.2
Generování vzorků
Pro kvalitní výpočet zastínění je třeba správně generovat vektory pro vzorkování okolí. Po úvahách jsem se rozhodl pro generování vzorku s Gaussovým rozložením. Abychom mohli takový generátor vytvořit, je potřeba kvalitně generovat náhodné číslo. To jsme zajistili pomocí funkce uvedené výše. Nyní můžeme pomocí takto vygenerovaných hodnot sestavit náhodný vektor na hemisféře určené vektory N , U a V . Vektory U a V jsou doplňující vektory kolmé k normále N .
vec3 U = vec3 V = float r1 float r2
ArbitraryNormal(N); cross(N, U); = rand(fCoord.xy/float(i)); = rand(fCoord.yx/float(i));
float sin_theta = sqrt(1.0-r1); float cos_theta = sqrt(r1); float phi = 2.0*pi*r2; vec3 dir = vec3(cos(phi)*sin_theta,sin(phi)*sin_theta, cos_theta); sVect = dir.x * U + dir.y * V + dir.z * N;
Touto posloupností výpočtů dostaneme normalizovaný vektor sV ect, který má náhodný směr s normálním rozložením se střední hodnotou ve směru normály.
38
4.4.3
KAPITOLA 4. POPIS IMPLEMENTACE
Převod prostorů
Jak již bylo zmíněno, při výpočtu zastínění jsou potřeba převody mezi světovými souřadnicemi a souřadnicemi obrázku. Tyto převody se dějí pomocí projekční matice. Při převodu z prostoru světa do prostoru obrázku stačí vynásobit vektor projekční maticí a posunout souřadnice do souřadnic prostoru obrázku.
sVect = gl_ProjectionMatrix*sVect; sVect = sVect / sVect.w; sVect = (sVect + 1.0)/2.0; Pokud potřebujeme převést souřadnice z prostoru obrázku zpět do světových souřadnic, je třeba postup obrátit a použít inverzní matici.
sVect = 2.0* sVect - 1.0; sVect = gl_ProjectionMatrixInverse*sVect; sVect /= sVect.w; Vždy nesmíme zapomenout posunout souřadnice z prostoru od 0 do 1 do prostoru −1 až 1 a naopak.
4.5
Filtrování obrazu (Blur)
Po výpočtu zastínění i odrazů barev je třeba textury rozostřit, aby na nich nebyl patrný šum ze vzorkování. Proto je na závěr přidán krok s filtrováním, jak již bylo zmíněno. Po implementaci se ale při testování ukázalo, že pro nízkou hodnotu numSamples je použitý způsob filtrování nedostatečný a zanechává v obraze šum. Nejjednodušším způsobem, jak tento šum odstranit, je zvýšení počtu použitých vzorků pro výpočet. Ale to je pro každý vzorek navíc velice výpočetně náročné. A tak jsem implementoval další průchod filtrování. Je to dvakrát opakované vertikální a horizontální rozostření. Je pro něj vytvořen ovládací prvek v GUI tak, aby si uživatel mohl zvolit, kdy je potřeba obraz zbavit šumu a kdy ne. I tento krok navíc stojí nějaký výpočetní čas, ale v testech uvidíme, zda je výhodnější zvýšit počet vzorků, nebo aktivovat dvojnásobné filtrování.
4.6
Konfigurace
Na závěr této kapitoly je třeba ještě vysvětlit, jak je možné s modulem pracovat, jak je potřeba ho nastavit a jak je možné jej případně upravovat.
4.6. KONFIGURACE
4.6.1
39
Kompilace
Vývoj modulu probíhal v prostředí vývojového software Microsoft Visual Studio. Proto vedle zdrojových kódů je k dispozici i projektový soubor pro tento program. Zároveň je modul zařazen mezi vykreslovací moduly do projektového souboru pro celý systém VRUT. Pokud chceme do zdrojových kódů zasahovat, nebo jen modul zkompilovat, stačí otevřít soubor pro celý VRUT. Modul nemá zvláštní nároky na další knihovny, než které potřebuje celý systém VRUT. A proto je možné jej kompilovat bez jakýchkoli dalších zásahů.Více informací o kompilaci systému VRUT a instalaci potřebných knihoven najdete v diplomové práci Ing. Václava Kyby [Kyb09]
4.6.2
Instalace
Pokud máme modul zkompilovaný, výstupem je knihovna modulu a soubory s shadery. Tyto soubory je třeba uložit do složky se spustitelným souborem vrut.exe, do podsložky modules/render/. Důležité je, aby v této složce byly také všechny soubory pro vertex a fragment shadery. Po spuštění aplikace VRUT, si sama zjistí, zda je modul dostupný a při jeho spuštění vše potřebné načte.
4.6.3
Nastavení
Spuštení modulu je prováděno pomocí příkazu usemodulessdoRenderer. Tím zajistíme, aby VRUT při vykreslení scény použil náš modul. Ten se aktivuje při zadání příkazu pro vykreslení scény renderscenesceneID. Kde sceneID je ID vykreslované scény. Po výkreslení scény máme k dispozici GUI pro nastavování potřebných parametrů. Ty je potřeba nastavit dle parametrů dané scény.
4.6.3.1
Rádius
Hodnotu rádius je potřeba nastavit dle velikosti scény a požadované velikosti hemisféry pro testování všech bodů. Pokud máme scénu která má například rozsah hodnot od −10 do 10, a požadujeme, aby výpočet zastínění byl prováděn s desetinou scény, musíme hodnotu rádius nastavit na 2.
4.6.3.2
numSamples
Zde nastavujeme počet použitých vzorků pro výpočet zastínění a odrazy barev pro každý bod obrazu. Metoda dokáže počítat od dvou vzorků, ale dle testování je minimum alespoň pět vzorků. Samozřejmě, čím více vzorků, tím jsou stíny kvalitnější. Ale s počtem vzorků stoupá výpočetní náročnost a vykreslování se zpomaluje.
40
KAPITOLA 4. POPIS IMPLEMENTACE
4.6.3.3
shadowAtt
Nastavením hodnoty shadowAtt na nulu vypneme stíny. Čím více budeme tuto hodnotu zvyšovat, tím více budou stíny silnější, až od určité hranice začne tmavnout celá scéna. Při testování se ukázalo za vhodné používat rozmězí od 1 do 2. 4.6.3.4
colorBounceAtt
Tento parametr je stejný jako předchozí s tím rozdílem, že nenastavujeme sílu zastínění, ale barevných odrazů. Opět pokud hodnotu nastavíme na nulu, budou odrazy vypnuty. V testovacích scénách se ukázalo, že správný interval pro tuto hodnotu je od 0 do 1. 4.6.3.5
blurOffset
Hodnotou offset nastavujeme, který další bod se má při rozmazávání algoritmus brát. Pokud nastavíme hodnotu na 1, bude brát body vedle sebe. Pokud nastavíme na 2, bude brát body ob jeden. 4.6.3.6
drawTtexture
Tento přepínač je vhodný pro nastavování parametrů. Dovoluje totiž zobrazit buď výslednou texturu se stíny a odrazy, nebo jenom texturu se stíny, nebo jenom s odrazy. Umožní tak lépe ladit jednotlivé parametry. Jsou na výběr parametry: • Final texture – textura s výsledným obrazem se stíny i odrazy • Occlusion texture – textura pouze se stíny • Bounce texture – textura pouze s odrazy • Normal texture – textura normál
Kapitola 5 Testování Po úspěšné implementaci jsem přistoupil k závěrečnému testování. To mělo několik fází. První testy byly pouze pokusné a odstraňoval jsem u nich všechny objevené nedostatky. Po odladění výpočtu jsem přešel k testování na dalším stroji. Tím byl počítač s grafickou kartou nVidia. Změna grafické karty opět ukázala některé neshody a tak jsem znovu opravoval shadery tak, aby vše fungovalo korektně, jak na kartách ATI, tak i nVidia. V této fázi mi hodně pomáhal pan Míšek, který paralelně se mnou všechny změny testoval i v jejich centru a posílal své poznatky. Když byly odstraněny všechny objevené chyby, přešel jsem na předposlední fázi testování, a tou je rychlost modulu.
5.1
Scény pro testování
Pro testování jsem si vytvořil šest scén, které jsem buď vymodeloval sám, nebo upravil z několika scén z internetových portálů CGTechniques.com a 3DModelFree.com. Použil jsem také jednu scénu tratě ze simulátoru TORCS (The Open Racing Car Simulator). URL: http://hdri.cgtechniques.com/ URL: http://www.3dmodelfree.com/ URL: http://torcs.sourceforge.net/ Těmito scénami jsem se snažil pokrýt co možná nejširší oblast typů 3D scén a to, jak z pohledu mého, tak i z pohledu zadavatele. Níže si scény detailněji popíšeme a ukážeme, jak vypadají při klasickém vykreslení bez efektů pro výpočet stínu a odrazů barev, a jak vypadají s vypočteným zastíněním metodou SSDO v kombinaci s metodou stínových map a barevných odrazů.
41
42
5.1.1
KAPITOLA 5. TESTOVÁNÍ
Základní barevná scéna
Scénu colorT estScene.wrl jsem si vytvořil jako hlavní testovací scénu při implementaci. Obsahuje vhodně rozmístěnou geometrii tak, aby bylo patrné, zda správně funguje jak výpočet zastínění, tak i odrazů nepřímého osvětlení. Scéna obsahuje také mapu okolí a světlo. Vše, co je potřeba pro testování. Scéna je složena z 1004 trojúhelníků. Je ve formátu VRML.
Obrázek 5.1: Scéna colorTestScene.wrl bez efektů
Obrázek 5.2: Scéna colorTestScene.wrl se zapnutými efekty
5.1. SCÉNY PRO TESTOVÁNÍ
5.1.2
43
Scéna pro barevné odrazy
Scéna colorBounce.wrl obsahuje postavy lidí, tedy specifický objekt pro 3D grafiku. Zároveň jsem tuto variantu spojil s testem barevných odrazů a postavy umístil do prostředí mezi dva barevné kvádry. Tím, při vhodném nastavení parametrů, docílíme odrazů barev z těchto stěn na postavy lidí, v tomto případě sošku. Scéna je opět ve formátu VRML a skládá se z 50816 trojúhelníků.
Obrázek 5.3: Scéna colorBounce.wrl bez efektů
Obrázek 5.4: Scéna colorBounce.wrl se zapnutými efekty
44
5.1.3
KAPITOLA 5. TESTOVÁNÍ
Sponza
Tato scéna (sponza97.wrl)je v 3D grafice velice známá a dobře simuluje architekturu. Jde o objekt s vnitřním nádvořím, které je obklopeno terasami. Scéna je složena z 66454 trojúhelníků.
Obrázek 5.5: Scéna sponza97.wrl bez efektů
Obrázek 5.6: Scéna sponza97.wrl se zapnutými efekty
5.1. SCÉNY PRO TESTOVÁNÍ
5.1.4
45
Scéna chrám
Scénu temple.wrl jsem již měl ze starších projektů, a tak jsem ji zapojil i do tohoto testování. Obsahuje vymodelovaný chrám s mnoha sloupy. Scéna má 104724 trojúhelníků.
Obrázek 5.7: Scéna temple.wrl bez efektů
Obrázek 5.8: Scéna temple.wrl se zapnutými efekty
46
5.1.5
KAPITOLA 5. TESTOVÁNÍ
Scéna město
Tuto scénu (city.wrl) jsem našel na portálu 3DModelFree.com. Zaujala mě scéna kompletního města, kde se nachází různé typy staveb. Scéna je bez materiálů, ale to pro testování zastínění není problém. Scéna se skládá z 141064 trojúhelníků.
Obrázek 5.9: Scéna city.wrl bez efektů
Obrázek 5.10: Scéna city.wrl se zapnutými efekty
5.1. SCÉNY PRO TESTOVÁNÍ
5.1.6
47
Závodní trať Forza a model Fábie
V aplikaci VRUT je možné simulovat jízdu automobilem, proto jsem jako poslední scénu zvolil trať Forza ze simulátoru TORCS a do ní umístil model Fábie. Zobrazovaní 3D modelů automobilů je také časté pro tuto aplikaci a tak jsem pokryl i tento typ scény. Trať Forza se skládá z 72082 trojúhelníků a automobil Fábia z 5855169 trojúhelníků.
Obrázek 5.11: Scéna forza.acc + fabia2.fhs bez efektů
Obrázek 5.12: Scéna forza.acc + fabia2.fhs se zapnutými efekty
48
KAPITOLA 5. TESTOVÁNÍ
5.2
Rychlost
Jedním z důležitých parametrů pro programy vykreslující v reálném čase je jejich rychlost. Ta by v ideálním případě měla dosahovat alespoň 30 obrázků za vteřinu. Této hranice je ale pro rozsáhlé scény v univerzálních nástrojích, jako je i VRUT, stále těžké dosáhnout i bez rozšiřujících technik, jako je metoda SSDO. Proto jsem se snažil provést implementaci metody co možná nejefektivněji, aby výsledná rychlost byla co nejvyšší.
5.2.1
Testovací sestavy
V tomto testování mi opět pomohl pan Míšek a dle mých požadavků provedl test i u sebe. Tím mně poskytl dobré výsledky na mnohem výkonnějším stroji, než jakým sám disponuji. Testy jsem také provedl na počítači s grafickou kartou nVidia, který jsem již využíval při předchozích testech. A ještě jsem celý test provedl také u sebe. 5.2.1.1
Intel Xeon X5260
CPU:Intel Xeon X5260 (3,33GHz) RAM: 4GB GPU: NVIDIA QUADRO FX 5600 5.2.1.2
Intel Core 2 Duo E8400
CPU: Intel Core 2 Duo T8300 (2,4GHz) RAM: 3GB GPU: ATI Mobility Radeon HD 3650 5.2.1.3
Intel Core 2 Duo T8300
CPU: Intel Core 2 Duo E8400 (3,0GHz) RAM: 2GB GPU: NVIDIA GEFORCE 8500GT
5.2. RYCHLOST
5.2.2
49
Závislost rychlosti na rozlišení obrazu
Jelikož metoda pracuje v prostoru obrázku, očekával jsem, že bude rychlost klesat úměrně s počtem bodů obrazu. Tento parametr jsem testoval pro všechny scény. Průběh klesání rychlosti byl u všech scén podobný, a tak pro lepší přehlednost ukazuji výsledky pouze pro scénu colorTestScene. Parametry byly nastaveny vždy stejné a aktivní byl výpočet zastínění, barevných odrazů a stínových map. FPS Intel Xeon Intel E8400 Intel T8300 640x480 64 9.8 9.6 800x600 40 6.9 6.2 1024x768 24 4.3 3.3 1280x960 15.5 2 1440x900 0.5 1680x1050 1.6 1680x 1200 9.8 Tabulka 5.1: FPS v závislosti na rozlišení obrazu
Obrázek 5.13: Graf poklesu rychlosti vykreslování v závislosti na rozlišení obrazu
Očekávání klesající funkce se při testech naplnilo, ale bohužel místo lineárního klesání měla funkce spíše klesání exponenciální.
50
5.2.3
KAPITOLA 5. TESTOVÁNÍ
Závislost rychlosti na aktivovaném efektu
V implementaci je zahrnuto více různých efektů, a tak jsem chtěl porovnat, který je na výpočet nejnáročnější, a který naopak příliš výpočetního času nestojí. Opět jsem test provedl pro všechny scény a pro znázornění výsledků vybral pouze jednu. Průběh byl opět podobný a tak jsem zvolil scénu s nejvyšším počtem polygonů. Scénu tratě forza s fábií. Parametry byly nastaveny opět vždy stejné a rozlišení obrazu bylo 800x600 bodů. FPS Intel Xeon Intel E8400 Intel T8300 render 16 2,4 13 SSDO 4,3 0,7 1,3 SSDO+SM 3,9 0,6 1,3 SSDO+SM+DB 3,8 0,5 1,2 Tabulka 5.2: FPS v závislosti na zvoleném efektu
Obrázek 5.14: Graf poklesu rychlosti vykreslování v závislosti na zvoleném efektu První hodnota je pouze normální vykreslení bez jakéhokoliv efektu, druhá je zastínění a odrazy barev. V třetí je přidán výpočet stínu pomocí stínových map a u poslední je ještě aktivováno dvojité rozmazání. Největší pokles je zaznamenán při aktivaci výpočtu zastínění a odrazů barev. Tím se aktivují tři vykreslovací průchody namísto jednoho a navíc je shader hodně výpočetně náročný. Aktivace stínových map a dvojitého rozmazání již tak razantní pokles nečiní. Je to proto, že stínové mapy jsou počítány při výpočtu zastínění, dvojité rozostření se počítá pouze na obdélníku a složitá geometrie se již nevykresluje.
5.2. RYCHLOST
5.2.4
51
Závislost rychlosti na počtu vzorků pro výpočet zastínění
Dalším parametrem ovlivňujícím rychlost vykreslování je nastavený počet vzorků pro výpočet zastínění a odrazů barev. Pro každý vzorek navíc je třeba provádět znovu všechny výpočty zastínění a odrazů z daného směru, a tak je tento parametr potřeba nastavovat velice pečlivě. FPS 5 10 20 50 100
Intel Xeon Intel E8400 Intel T8300 36 8,7 8,9 24 5,1 6,2 14,6 3,2 4,1 6,4 1,5 2 3,5 0,8 1,1
Tabulka 5.3: FPS v závislosti na počtu vzorků pro výpočet zastínění
Obrázek 5.15: Graf poklesu rychlosti vykreslování v závislosti na počtu vzorků pro výpočet zastínění
Dle mých předpokladů je rychlost velice závislá na počtu použitých vzorků. Opět rychlost klesá exponenciálně a tak musíme nastavovat parametr velice opatrně.
52
5.2.5
KAPITOLA 5. TESTOVÁNÍ
Závislost rychlosti na velikosti scény
Posledním parametrem testování byla velikost scény. Pro tuto hodnotu jsem si vytvořil pomocnou funkci, která vypočítala celkový počet trojúhelníků ve vykreslované scéně. FPS colorTestScene colorBounce sponza97 temple city forza+fabie
Intel Xeon Intel E8400 Intel T8300 počet trojúh.[tis.] 40 6.9 6.2 1.0 32 3.8 2.8 50.8 13.2 1.0 1.9 66.5 7.5 4.7 6 104.7 12.8 1.9 2.2 141.1 3.9 0.6 1.3 5855.2
Tabulka 5.4: FPS v závislosti na velikosti scény
Obrázek 5.16: Graf poklesu rychlosti vykreslování v závislosti na velikosti scény
Testovací scény jsem zvolil od jednoho tisíce až do skoro šesti miliónů trojúhelníků. Předpoklad metody je nezávislost na velikosti scény, ale pouze na rozlišení obrazu. Toto tvrzení se víceméně prokázalo a slabá lineární závislost to dokazuje. Jak lze vidět v grafu, osa pro počet trojúhelníků není úměrná jejich hodnotě, protože by tím hodnota poslední scény znepřehlednila celý graf.
5.3. KVALITA VÝPOČTŮ
5.3
53
Kvalita výpočtů
Tento parametr je velice těžko výpočetně posuzovatelný. Jelikož nemám implementovanou jinou exaktní metodu výpočtu osvětlení ve scéně, nemám dle čeho přesně hodnotit. Ale mohu posuzovat jevy, které byly v úvodu zmíněny jako nedostatky této metody. Nedostatkem výpočtu zastínění je, že nepracuje se vzdáleností objektu. Tím vrhá stín i na velice vzdálené objekty, na které by již stín vrhán být neměl. To by bylo možné redukovat výpočtem vzdáleností bodů, ale opět by to jen přidalo výpočetní operace a tak výrazně zpomalilo vykreslování. Chybou u výpočtů odrazu barev je problém odvrácených stran. Pokud vidím stranu objektu, od které se nepřímé osvětlení odráží, je vše v pořádku. Pokud ale natočím scénu tak že už strana vidět nejde, odraz se ztratí.
Obrázek 5.17: Chyba výpočtu odrazů na odvrácených stranách
Tomuto problému se dá předejít použitím více pohledů, jak je zmíněno v úvodu. Ale zase zde narazíme na problém zvyšování výpočetního nároku. Přeci jen jde o rychlou aproximaci výpočtu osvětlení ve scéně a při všech mých pokusech se tento problém příliš viditelně neprojevoval.
54
KAPITOLA 5. TESTOVÁNÍ
Kapitola 6 Závěr Cílem práce bylo prozkoumat metodu přímého zastínění v prostoru obrázku a poté ji implemetovat do vizualizačního nástroje VRUT. Tento nástroj je v aktuální verzi velice komplexní a dobře řešená aplikace, která už zdaleka nepřipomíná studentský projekt, ale spíše profesionální aplikaci. Mnoho lidí, co pracovalo a pracuje na vývoji jak samotné aplikace, tak i modulů, odvedlo výbornou práci a jsem rád, že jsem mohl do tohoto kolektivu vstoupit. Samotná metoda přímého zastínění v prostoru obrázku není příliš stará [RGS09], a tak jsem mohl implementovat metodu, o které mnoho lidí ještě neslyšelo. A díky tomu jsem většinu problémů s implementací také musel sám řešit. Byla to práce těžší, ale o to zajímavější. Metoda má velice zajímavý princip, díky kterému rozšiřuje kvality metody SSAO o kus dále. Je sice výpočetně náročnější, ale s roustoucími výkony grafických procesorů by mohla velice oblíbenou metodu SSAO časem zcela vystřídat. Implementace byla doprovázena řadou problémů, kdy jejich řešení zabralo mnohem více času než bych očekával. Spousta problémů ale vznikala z neznalosti všech možností jak knihovny OpenGL, tak i GLSL. Ale vše jsem nakonec překonal a uznal, že díky těmto problémům jsou mé znalosti o mnoho lepší a hlubší než před zahájením práce. Určitě, když se nyní zpětně podívám na celou práci, našel bych spoustu míst, kde by se dalo na vývoji pokračovat a pokusit se dostat modul o kousek blíž k dokonalosti. Celkově jsem s implementací spokojen. Důležitý faktor, a to kvalita stínů, se povedla doladit do velmi dobrých výsledků, jak je vidět na testech. Co se ovšem nepovedlo úplně podle původních představ, je rychlost modulu. Zde by se mohlo zkusit najít řešení pro eliminaci velkého množství výpočtů v samotném shaderu, který je zatím velice výpočetně náročný.
55
56
KAPITOLA 6. ZÁVĚR
Literatura [KL05]
Janne Kontkanen and Samuli Laine. Ambient occlusion fields. In Proceedings of the 2005 symposium on Interactive 3D graphics and games, I3D ’05, pages 41–48, New York, NY, USA, 2005. ACM.
[Kyb09]
Václav Kyba. Diplomová práce Modulární 3D prohlížeč, 2009. https://dip.felk.cvut.cz/browse/pdfcache/kybav1_2009dipl.pdf, stav z 31. 12. 2010.
[LK03]
Jaakko Lehtinen and Jan Kautz. Matrix radiance transfer. In Proceedings of the 2003 symposium on Interactive 3D graphics, I3D ’03, pages 59–64, New York, NY, USA, 2003. ACM.
[M.05]
Bunnell M. Dynamic ambient occlusion and indirect lighting. In GPU Gem2, pages 223–234. NVidia Corporation, 2005.
[Mil94]
Gavin S. P. Miller. Efficient algorithms for local and global accessibility shading. In SIGGRAPH, pages 319–326, 1994.
[RGS09]
Tobias Ritschel, Thorsten Grosch, and Hans-Peter Seidel. Approximating dynamic global illumination in image space. In Proceedings of the 2009 symposium on Interactive 3D graphics and games, I3D ’09, pages 75–82, New York, NY, USA, 2009. ACM.
[RWS+ 06] Zhong Ren, Rui Wang, John Snyder, Kun Zhou, Xinguo Liu, Bo Sun, Peter-Pike Sloan, Hujun Bao, Qunsheng Peng, and Baining Guo. Realtime soft shadows in dynamic scenes using spherical harmonic exponentiation. ACM Trans. Graph., 25:977–986, July 2006. [SA07]
Perumaal Shanmugam and Okan Arikan. Hardware accelerated ambient occlusion techniques on gpus. In Proceedings of the 2007 symposium on Interactive 3D graphics and games, I3D ’07, pages 73–80, New York, NY, USA, 2007. ACM.
[WSP04]
Michael Wimmer, Daniel Scherzer, and Werner Purgathofer. Light space perspective shadow maps, June 2004.
57
58
LITERATURA
Příloha A Seznam použitých zkratek 3D Three-Dimensional AO Ambiente Occlusion BRDF Bidirectional reflectance distribution function BVH Bounding volume hierarchy CPU Central Processing Unit DO Direct Occlusion FBO Frame Buffer Object FHS Files with scene hierarchy and geometry data FPS Frames Per Second GLEW OpenGL Extension Wrangler library GLSL GL Shading Language GPU Graphics Processing Unit GUI Graphical User Interface ID Identification ISAO Image Space Ambient Occlucion Mpx Megapixel OpenGL Open Graphics Library PRT Precomputed Radiance Transfer RAM Random-Access Memory SSAO Screen Space Ambient Occlucion
59
60
PŘÍLOHA A. SEZNAM POUŽITÝCH ZKRATEK
SSDO Screen Space Directional Occlucion TORCS The Open Racing Car Simulator VD2 Virtual Design 2 VRML Virtual Reality Modeling Language VRUT Virtual Reality Universal Toolkit
Příloha B Obsah přiloženého DVD /text - text diplomové práce v různých formátech /bin - soubory pro spuštení aplikace /data - testovací scény /testing - veškeré výsledky testování, tabulky i obrázky /src - zdrojové soubory celé aplikace včetně všech potřebných modulů READM E.txt - soubor popisující strukturu DVD a kroky pro spuštění aplikace
61