Technologie Doom 3 část 1.

[ Draza ] [ 15.07.2004 ]
Úvod

Doom 3 engine byl poprvé představen 21. února 2001 na prezentaci Apple s grafickou kartou GeForce3. Zhruba od té doby se na mainstreamových internetových serverech objevují správy typu jakou verziu pixel shaderů bude Carmackův nový engine potřebovat, nebo že použítý bump-mapping navyšuje počet zobrazených polygonů na desetinásobek. Protože ne každý čtenář stránek doom3.cz a idoom.cz má čas a nervy pátrat po správnych informacích na cizojazyčných webech, požádal mě FatalDooM o napravení najčastěji vyskytovaných fám na pravou míru. 50% následujího článku představují internetové zdroje, 50% jsou zkušenosti s alphou a 50% spekulace, což znamená, že se jedná o 150% pravdu :) Ale vážně, nedisponuju žádnými speciálními znalostmi 3D programovaní (vlastně žádného programování) a tento článeček byl napsaný jen za účelem vyvracení fám o potřebe podpory pixel shaderů na kartě a podobně, a k vysvětlení některých princípů, které mi připadají důležité. Protože nemám neomezenou pamětovou kapacitu, mohou se vyskytnout nepřesnosti, za které se předem omlouvám a doufám, že mne někdo opraví nebo si to se mnou probere ve fóru.

Jako nepoučitelný grafoman jsem se do psaní dosti zažral. Abych byl vůbec schopný fatalovi něco doručit, shodli jsme se, že bude vhodné článek rozdělit na dvě časti. V této první je popsaný základ Carmackových enginů - OpenGL, úvod do problematiky světla v hrách a bump-mapping. Do druhé části se dostane specular-mapping, dynamická světla, stencil shadows a případně co mne ješte napadne. Protože tyto techniky nejsou tolik populární a generické jako bump-mapping, je možné očekávat menší přesnost informácí v druhé části článku.


OpenGL

Známé je, že zhruba od vydání hry Quake přestala mít význam jakákoliv grafická karta bez 3D akcelerace. Akcelerátory existovaly pro domácí prostředí i v době před Quakem, avšak jednotlivá hardwarová řešení byla nekompatibilní s ostatními a tak bylo potřebné každou aplikaci naprogramovat pro každý akcelerátor zvlášt. Přitom řešení existovalo už asi 10 let předtím - open-source aplikační rozhraní OpenGL od SGI, používané do té doby pouze pro profesionální grafické aplikace jako CAD. Programátorům stačilo naprogramovat aplikaci na jedno rozhraní a výrobcům grafických karet skončila najvětší práce vypuštením driverů, které podporují OpenGL na jejich kartě. Využít toto rozhraní pro pohon Quake enginu byl nápad firmy 3Dfx, Carmackovi se to líbilo a hru údajně naportoval na OpenGL během jednoho víkendu.

Pro vysvětlení: aplikační rozhraní (API, application programming interface), když se bavíme o OpenGL, má v zásadě tři strany: a) programátorovi ulehčuje práci a umožňuje přípravu projektu na různý hardware tím, že postačuje jedna verze programu; b) vývojářům hardwaru stačí poznat specifikace OpenGL a navrhnout hardware a drivery podle něho a ne podle každé aplikace samostatně; c) domácímu užívateli stačí mít nainstalovanou verzi OpenGL, tzv. runtime. Při přechodu na novou verzi API je potřebný update na všech třech stranách.

Microsoft vyvinul vlastní grafické API, Direct3D, které je součástí runtime balíčku DirectX. Jak víme, DirectX sa postupem času vyvíjelo, takže asi každý někdy slyšel o verzích 6, 7, 8 a 9 a jejich opravných variantách (např. 9.0b). Každá z uvedených verzií DirectX přinesla i novou verzi Direct3D s novými funkcemi, např. s DX8 byly představené tolik diskutované pixel shadery. Přibližně až do verze 5 bylo D3D v porovnání s OpenGL v podstatě pro smích, ale Microsoft vytrval, přidával do svého API nové schopnosti, marketingově ho prosazoval, zjednodušovalo se v něm programovani a dnes už drtivá většina her používá jako grafické rozhraní právě D3D. Na OpenGL sa zapomnělo i z důvodu, že běžný užívatel s ním nepřichází viditelně do kontaktu. Zatímco Direct3D vyžaduje intalaci zhruba několika-deseti-megového rutime, OpenGL se v tichosti nainstaluje s drivery grafické karty.

Proto když se dnes mluví o hře, že "minimum bude GeForce3", tak se implicitně předpokladá, že hra vyžaduje pixel shadery, protože GF3 byla první karta plně odpovídající požadavkům D3D8. Jenže toto je nesprávná interpretace, protože Carmack zůstává věrný svéjmu drahému API a Doom3 grafika bude spoléhat na OpenGL. Aby bylo jasno, pod Windows bude hra pravděpodobně potřebovat nainstalované DirectX, protože jeho součástí je i API na použití input zařizeení, sítě a zvuku. DirectDraw, dalšia součást DirectX je taktéž vyžadovaná pokud má OpenGL aplikace běžet v okně. (Všimli jste si, že někdy bývají hry stabilnější, když běží ve full-screenu? Možná proto, že se používá méně komponentů DirectX.)

Proč vlastně Carmack zůstávý u OpenGL a nepřejde na Direct3D? Jeden z důvodů je zajisté přenositelnost kódu. Zatímco grafický engine spoléhající na Direct3D bude fungovat jen tam kde to povolí Microsoft (v zásadě Windows a Xbox), kód napsaný pro OpenGL je možné bez větších změn použit na Win, Linux, Mac, PS2, Dreamcast, Xbox nebo například na specializovaném zařízení používaném na generovaní designových návrhů v automobilce. Takový Unreal engine 2 je schopný fungovat na různých platformách protože obsahuje renderer pro D3D i OpenGL.

Stejně jako DirectX, spolu s hardwarem se vyvíjí i OpenGL. V současné době existují verze 1.0 až 1.5 a najnovější 2.0, zatím bez 100% podpory ze strany OpenGL fóra. Ve verzi 1.3 se do OpenGL dostala podpora technologií na bázi per-pixel lightningu a bump-mappingu. První běžně dostupná grafická karta umožňující tyto funkce využit byla GeForce256, ale k tomu se vrátíme později. Pokud chcete vidět jak si stojí vaša grafická karta v souvislosti s OpenGL, nejlepší spůsob je stáhnout si drobnou utilitku OpenGL Extension Viewer. Základní přehlad o možnostech umožní OpenGL benchmark GL Excess. Starším kartám od nVidie umožní emulovat vyšší verze OpenGL například nástroj RivaTuner, a to bez větších nároků na výkon procesoru.


Budiž světlo

Z fyziky víme, že obraz který vidíme očima vzniká odrazem světla od povrchu. Tam kde není světlo, nevidíme nic, respektive je tam stín. V 3D enginech umožňuje věrná emulace světla, jeho odrazů a stínů vyšší realističnost zobrazení. V běžných enginech se používají rozdílné techniky pro světla statická a dynamická, stejně tak pro statické a pohyblivé povrchy. Jako ilustračný příklad použití použijeme Quake 3.

Základní nástroj napodobení statických stínů od doby Quaka jsou lightmapy. Lightmapa je textura automaticky vygenerovaná v průběhu procesu tvorby levelu, která se ve hře projeví jako tmavší místa tam, kde je stín od statických světel. Na screenshotech vidíme mapu Q3DM7 a odpovídající lighmapu; třetí screen ukazuje co se dá dosáhnout při větším úsilí:

Screenshot Q3DM7 Lightmapa Q3DM7
Lepší lightmapa

Kvalita lighmapy je standardně mizerná (například Quake 3 používá rozměr 256*256, který pokrývá značnou plochu v levelu). Její generovaní trvá večnost (například při tvorbě levelů pro Max Payne i několik dní) a když je už hotová, není možné v levelu dělat změny bez toho aby začal proces znovu. Na třetím obrázku je "alpha verze" mého levelu kde jsem se pokusil z lighmapy vytlačit maximum jejím násobením - výsledek je podle mne slušný, ale toto embryo levelu s dvěma místnostmi dosáhlo velikost 3MB, a to jsem kvalitu lighmapy zkresal asi na čtvrtinu - původně měl level asi 12MB (celá mapa Q3DM7 má něco přes 5MB). Zvyšování kvality osvětlení tímto způsobem tedy nemá význam, a navíc je princip lightmapy použitelný jen pro nastínování statických objektů statickými světly.

S pohyblivými objekty to je komplikovanější. Podívejme se jak vypadá bežná postavička v Quake 3:

Model Doom v Quake 3

Model má na sobě pár stínů a "zářivých zón", výsledek je z uměleckého hlediska výborný, problém však nastane když začne být důležité, aby byl model osvětlený správně. Když nepočítám specifický průzor přilby této postavy, pro kterou je použit enviromental mapping (na základní textuře je nanesená další, která je enginem deformovaná a hýbe se v závislosti na pohledu kamery a ne rotaci modelu, na kterém je nanesená), jsou všechny změny v osvětlení postavy obsažené přímo v textuře, vytvořené designérem.

Textura postavy Doom v Quake 3

Zajímavé je, že tyto změny v jasnosti nebývají vytvořené ručně, ale jsou off-line vyrenderované přímo v 3D programu. Pro programátora je tedy výzvou vytvořit engine který tento proces zvládá v reálném čase podle aktuálních podmínek - engine musí podporovat nějaký šikovný způsob real-time nasvětlovaní (alias těžko přeložitelný anglický výraz shading). 3D objekty se skladají z polygonů - trojuhelníků, pro nasvětlení objektu je tedy třeba vytvořit nasvětlení každého polygonu zvlášt. Pro názorný příklad, dva bežné způsoby jsou flat shading a Gouraud shading:

Flat shading a Gouraud shading

Oba fungují na bázi per-vertex, takže úroveň nasvětlení je vytvořená pro každý jednotlivý vrchol každého polygonu zvlášt - polygon samotný je potom zabarvený zprůměrovanou barvou jeho vrcholů. Při použití gouraudova způsobu se ješte lineárně interpolují barvy mezi najbližšími vrcholy, takže výsledek je jednolitý a pro většinu aplikací vyhovující, zůstává však matematicky nekorektní.

Priblížim jak je vlastně možné takového nasvětlovaní dosáhnout. Když jsme už rýpli do fyziky, další poučka říká, že odraz světla od povrchu závisí na normálovém vektora kolmého na povrch: (úhel mezi dopadajícím světlem a normálovým vektorem roviny dopadu se rovná úhlu medzi světlem odraženým a daným normálovým vektorem - díky Thomass za přesné znění).

Normálový vektor

Například v implementaci flat shading to znamená, že když je vrchol polygonu postavený kolmo k světelnému zdroji, stejně jako bod pozorování, barva polygonu se nezmění, avšak s rostoucím úhlem dopadu světla se jas vrcholu polygonu lineárně snižuje, až do 90 stupňů. (Matematici kroutí hlavou, že vrchol polygonu je přece bod a bod nemůže mít normálový vektor. Tak teda, normálový vektor vrcholu je matematickým vyjádřením průměru normálových vektorů polygonů, které mají společný daný vrchol.)


Per-pixel lightning a bump-mapping

Nyní přichází na scénu per-pixel lightning, což v zásadě znamená schopnost grafické karty ovlivňovat nasvětlení každého jednotlivého pixelu. Základem je Phong shading, způsob který nepracuje s polygony, ale přimo s pixely. V případě modelu, který má být zaoblený, jako příklad s kuličkami výše, engine používajíci Phong shading vytvoří normálové vektory pixelů (v tomto případe se pixel chová jako plocha, takže má vlastní normálový vektor), které chybějí do "zaoblení" a potom provede nasvětlení každého pixelu samostatně (změní se pouze nasvětlení, objekt samotný zůstává hranatý). Protože Phong shading umožňuje navigovat světlo na každý jednotlivý pixel, zpřístupňují se zajímavé možnosti, například bump-mapping, v případě Doom 3 je to DOT3 normal-mapping.

Bump-mapping je souhrnný název pro technologie navozující dojem nerovného povrchu bez navýšení počtu polygonů. Nejznámější enviromental bump-mapping je použitelný pouze na povrchy, které ovlivňují samotné osvětlení (t.j. zdroje světla, průhledné a odrazové povrchy, nejlepší efekt se dosáhne na vodní hladině), DOT3 BM emuluje běžné materiály.

Na první pohled to nemusí být evidentní, ale podle zraku můžeme povrch rozeznat jako kostrbatý jenom podle rozdílů v nasvětlení. Lidské oko je totiž zvyklé, že světlo přichází z jednoho směru (od slunce), a povrch který je tomuto světlu natočený bude světlejší (viz předešlý příklad s flat shading). Grafik tento fakt zná odjakživa, příkladem může být taskbar ve Windows:

3D tlačítko taskbaru

Tlačítko je ploché, nicméně díky lokálním změnám v jasnosti vypadá, že vystupuje z povrchu a světlo na něj dopadá zvrchu zleva. Zajímavý efekt se dosáhne otočením obrázku o 180 stupňů:

3D tlačítko otočené o 180°

Prostá výměna světlých a tmavých ploch způsobila, že tlačítko vypadá duté, protože stále trvá pocit, že zdroj světla je vlevo nahoře. V případe vizuálního důkazu, že světlo je umístěné jinde, je potřebné upravit nasvětlení.

Když by game designer chtěl použít tento prvek ve hře, má několik možností: 1) vyrobit pro něj 3D model - tlačítko bude správně osvětlené i vyformované, ale počet polygonů se tímto přístupem zvyšuje geometrickou radou; 2) použit texturu se světlými a tmavými sekcemi - šikovný výtvarník dokáže navodit pocit 3D (viz příklad postavy v Q3), ale takováto textura neodráží skutečný stav nasvětlení; 3) použit DOT3 BM, který emuluje správně nasvětlený povrch, ale ne samotnou geometrii (takže objekt zůstává fyzicky tak plochý jako jeho polygony - tuto nevýhodu odstraňuje technika displacement mapping, součást vertex shader 3.0 / Direct3D9, v dnešní době príliš náročná na výkon).

Na použití DOT3 BM jsou potřebné dvě textury: jedna obsahuje barevnou složku (diffuse map) zbavenou "předsvětlených" zón, a druhá výškovou (height map):

Diffuse map Height map

Poznámka: Možná to není vidět, tato height mapa obsahuje 4 odstíny šedé. Textury byly upravené na rozměr 256 x 64, aby fungovali správne v prohližeči, proto ty černé okraje.

Height map je textura, v které je zakodovaná informace o výšce pixelu nad povrchem. Neutrální šedá (127 červená, 127 zelená a 127 modrá) znamená, že výška se nemění, černá (0,0,0), že pixel je propadnutý do hloubky a bílá (255,255,255), že vystupuje nejvíc nad povrch. Dva zjevné problémy s height mapou jsou, že umožňuje "jen" 256 různých výšek pixelů, a neobsahuje informaci o normálových vektoroch jednotlivých pixelů, které jsou důležité pro výpočet nasvětlení. Tuto úlohu je možné přenechat procesoru v reálném čase, ale víc možností vzniká, když se height mapa upraví na normálovou mapu. Z názvu "normal map" je zjevné, že tato textura neobsahuje informaci o výšce pixelů, ale o normálových vektorech, jinak řečeno relatívní polohu sousedících pixelů. Táto informace je zakodovaná do barev pomocí tohoto klíče:

Normálové vektory

Tento proces se samozřejmě nedělá ručně, ale pomocí utilitky, například nVidia Normal Map Filter, což je plug-in pro Photoshop. S pomocí něho vznikne výsledek:

Normal map

Plug-in obsahuje i real-time prohlížeč, který ukáže jak se výsledná textura chová při měnící se poloze světla:

Preview Preview

Až při pohledu pod nízkým úhlem je zjevné, že efekt je stále jen "2D":

Preview

Tento příklad s tlačíkem přibližuje jeden postřeh: když má normálová mapa ostré linie, výsledný objekt je zaoblený; křivky zase budou budit dojem zubatosti. To je při texturách bežná věc (stačí se trochu bliže podívat na stěny v Q3), avšak normálová mapa obsahuje víc informací, a tedy potřebuje více detailů. Protože se tyto artefakty objevují hlavně u povrchů viditelnými z nižšího uhlu, situaci vylepší anizotropické filtrovaní, ani to však nepridá textuře detaily. Ztratová komprese je pro normálové mapy nepoužitelná, řešením je tedy použit menší textury jako dlaždice (to samozřejme nejde aplikovat na povrchy s nepravidelným vzorkem), nebo použit větší texturu. V hře jako Doom 3 mohou příliš komplikované normálové mapy představovat problém, protože s trochou neopatrnosti by bezpochyby dokázali umrtvit už tak značně zatěžovaný hardware. Zatímco klasické textuře stačí jak si ji grafická karta prečte a aplikuje do scény pouze jednou, při DOT3 BM musí načítat každou texturu (diffuse map, normal map atd) a například takovou normálovou mapu přepočítat několikrát pro každý světelný zdroj, a to ješte pro každý viditelný pixel samostatne :) Dá sa tedy předpokladat, že v Doom 3 se nebudou objevovat příliš detailní bump-mapy, ale s postupně se vyvíjejícim hardwarem se bude situace určitě vylepšovat. Někde jsem četl, že Quake 4 (založený na Doom 3 enginu, vyvíjaný Raven Software) bude bežně používat textury 1024 x 1024, a na Unreal 3 engine se plánuje rozměr 2048 x 2048. To už bude ale vyžadovat trochu lepší grafické karty.

Zajímavá nevýhoda normal mapy je, že neumožňuje zobrazit 90 stupňový spád. Pro tyto specifické účely, například vygravírované logo na zbrani, poslouží klasická height mapa, kterou engine dokáže taktéž zpracovat.

Normal-mapping zabezpečuje vyšší detailnost oproti bežné texturovací technice a umožní přidat kvanta detailů i nevýrazné diffuse mapě, která, pokud je dostatečně generická, se dá použit na více povrchů v levelu.

Diffuse map Normal map Normal map Preview Preview

Na tvorbu normálové mapy pro 3D modely s větším počtem polygonů se používá jiný způsob. Tvůrce vyrobí dvě verze modelu; hi-poly a low-poly:

3D modely

Potom se pomocí utility (obvykle ve formě plug-inu pro modelovací program: ATi, nVidia) vytvoří normálová mapa, která obsahuje rozdily mezi dvěma modely vyjadřené přes normálové vektory. Tomuto procesu se říká renderbump nebo polybump. Funguje způsobem zakřivení normálových vektorů vycházejících z low-poly modelu v místech, kde se střetnou z hi-poly verzí:

Polybump


Výsledkem je tedy běžná normálová mapa zobrazující rozdíly mezi dvěma modely, která se natáhne na model s menším počtem polygonů a následně zobrazí v engine. Takže se nejedná o zpracovaní 250 000-polygonového modelu v reálném čase ale o natáhnutí výsledku na 5000-polygonový. Všechny drobné detaily jsou obsažené v normálovej mape (proto se tomuto způsobu vylepšení vzhledu modelu také říká "detail preservation"). Nemám k dispozici vhodnou texturu pro příklad, ale výsledek je nám už známý:

3D model

A tímto končí první část článku o revoluci, který představuje Doom 3 engine, těším se na feedback a uvidíme se příště.

goodoldalex


Zdroje obrázků:
Flat a Gouraud shading: http://computer.howstuffworks.com/question484.png
Renderbump: http://www.delphi3d.net/articles/viewarticle.php?article=bumpmapping.png
Zombie: http://www.gamestar.de
Barevný klíč k normálovým vektorem - autor neznámy
Textura modelu "Doom" pre Quake 3: Arena - id Software
Ostatní obrázky - goodoldalex