V minulé lekci jsme zakončili ukázkový příklad DirectDraw, DirectInput a DirectMusic. V dnešní lekci opustíme všechna tato témata a vrhneme se na zcela novou látku. Dnes a v několika (v mnoha) příštích lekcích se budeme zabývat komponentou Direct3D.
Je tomu skutečně tak! Přesuneme se od 2D zobrazování do 3D světa. V dnešní lekci ještě nebudeme nic programovat, ale povíme si některé základy, která dále využijeme.
Narozdíl od DirectDraw má Direct3D mnohem rozsáhlejší hardwarovou i softwarovou podporu. DirectDraw zaniklo, ale Direct3D má svojí cestu před sebou (dnešní hry jsou pěkné, ale k dokonalosti mají opravdu daleko).
Možná jste si na internetu všimli, že již vyšla nová verze DirectX a s ní i nové DirectX SDK 9.0. Bohužel toto SDK nemůžeme zahrnout na ChipCD, protože je několikanásobně větší než SDK předchozí verze. Ve svých lekcích tedy budu používat "staré" SDK 8.0 či 8.1. Pokud by se to někomu nelíbilo, tak vězte, že verze 9.0 má pro nás několik kosmetických změn. DirectX SDK 8.0 bylo uvedeno na ChipCD v listopadu roku 2001. Nové SDK si můžete stáhnout přímo z Microsoftu, ale velikost 100MB je pro vytáčené připojení opravdu hodně (i když znám takové šílence).
Nejprve si něco povíme o struktuře Direct3D.
18.1.1. Pipeline Direct3D
Na následujícím obrázku vidíte architekturu systému Direct3D. Je to vlastně cesta vstupních dat (vertexů - viz. dále) až po vykreslení do zobrazované paměti grafické karty.
Co dělají jednotlivé bloky zatím není třeba znát, ale postupně se k nim dostaneme dostatečně podrobněji. Obrázek zde uvádím, abyste si udělali celkovou představu o systému a pak aby si někdo nemyslel, že nejprve nanese texturu a poté transformuje vertexy. O čem to tu vlastně hovořím? Nechte se překvapit (teda pokud o tom skutečně nic nevíte a jste jen pasivním uživatelem Direct3D).
V další části si něco povíme o 3D prostoru, který máme k dispozici.
18.1.2. 3D prostor v Direct3D
Direct3D využívá klasický kartézský (pravoúhlý) systém se třemi osami x, y a z. Existují dva typy těchto souřadnicových systémů, které se liší ve směru osy z. K určení směru osy si pomáháme rukou. Všechny prsty kromě palce mají vždy směr osy y, ruka míří po směru osy x a palec pak určuje kladný směr osy z. Teď jde o to jakou ruku použijete a podle toho dělíme systémy na systém levé a pravé ruky. Direct3D používá systém s levou rukou (obrázek vlevo). Směr os ale můžete proházet, takže například můžete prohodit y a z (což osobně používám já).
Vše je vidět na dalším obrázku:
Poznámka: Kdo používá nápovědu MSDN, tak tyto obrázky jsem použil z ní.
18.1.3. Vertex
Již několikrát zde padlo toto slovo. Vertex je do češtiny přeložený vrchol. Budu zde ovšem převážně užívat anglického tvaru, protože se mi líbí víc. Každý objekt ve světě Direct3D je tvořen polygony. Konkrétně jsou použity trojúhelníky, protože jsou tzv. koplanární (jsou rovinné). Tři vrcholy tedy tvoří dohromady jeden trojúhelník. Později však zjistíte, že vertexy mohou být společné pro více trojúhelníků. Kdybychom měli 4 vertexy, vytvořili bychom obdélník, tím by ale nebyla jednoznačně definovaná rovina, protože tento obdélník by šel "zlomit" (vznikly by tak dvě roviny). Takže z trojúhelníků můžeme složit libovolný tvar, i když se to možná na první pohled nezdá. Ukažme si několik příkladů 3D těles. Jednoduchá kostka má 6 stran a každá obsahuje dva trojúhelníky:
Dále vidíme kouli složenou z mnoha trojúhelníků:
Abychom docílili dokonale kulaté koule, museli bychom ji sestavit z nekonečného množství trojúhelníků. Takové množství polygonů by se ovšem nelíbilo vaší grafické kartě. V praxi docílíme kulatosti pomocí pár trojúhelníků.
Každý vertex má svou pozici v prostoru určenou polohovým vektorem r. Tento vektor má tři souřadnice x, y a z. Vertex dále může obsahovat barvu, texturové souřadnice, normálový vektor atd. Vertexová data jsou převážně načítána z externích souborů s příponou .x nebo .3ds. Soubory 3DS vytváří 3D Studio MAX, takže není problém nakreslit objekt v tomto prostředí a pak ho přenést do vašeho programu. Je však třeba rozluštit 3DS soubor, což ale není takový problém. Myslím, že existuje nějaký plugin do 3D Studia na export do .x souborů.
18.1.4. Zpracování vertexů
Nyní si povíme, co s vertexy provede vaše grafická karta, případně procesor před zobrazením na monitoru. Pozice vertexu je totiž v souřadnicích vašeho 3D prostoru a je třeba ji transformovat, aby bylo možné vertex zobrazit na monitoru. Podíváte-li se ještě jednou na obrázek pipeline, tak se nyní bavíme o částech Fixed Function pipeline a Programmable pipeline. Dá se říci, že v Direct3D máme tři způsoby zpracování vertexů (vertex proccessing). Za prvé můžeme pracovat s tzv. transformovanými vertexy (transformed vertices), které výše uvedenými bloky vůbec neprojdou. Tyto vertexy mají danou pozici jako kdyby to byly sprity s DirectDraw a také na tyto účely se dají použít (kurzor myši, tlačítka menu, okna apod.). V další části se již budeme zabývat jen netransformovanými vertexy (untransformed vertices). Příště si vytvoříme první program Direct3D, kde si ukážeme práci s transformovanými vertexy.
Dalším druhem zpracování je uvedena Fixed function pipeline. Na každý vertex je provedena transformace tří matic - světové, matice pohledu a projekční matice. O transformacích pomocí matic se zmíním podrobně později. Nyní vám stačí vědět, že tento způsob byl používán nejčastěji v minulosti v DirectX 7.0. V dnešní době již máte možnost volby, i když se tento způsob samozřejmě používá stále. Fixed function se říká proto, že vy jakožto programátor nemůžete ovlivnit průběh transformace - prostě na začátku programu nastavíte výše uvedené matice a o vše ostatní se postará Direct3D (pro někoho to může být výhoda). Ze začátku tento systém budeme hodně používat a vlastně se ho nikdy úplně nevzdáme.
S DirectX 8.0 ovšem přišel v tomto ohledu zlom. Stejný zlom samozřejmě zaznamenal i hardware. Jedná se o programovatelné zpracování vertexů. Blok ve kterém se tyto operace provádějí se nazývá vertex shader a časem se k němu také dostaneme. Pomocí tohoto prostředku napíšete krátký (max. 128 instrukcí u nVidia GeForce, 192 u ATI Radeon) kód assembleru. Nejedná se o klasický assembler, ale o assembler speciálně určený pro vertex shadery. Tento krátký program je pak "spuštěn" na každý vertex vašeho objektu. Vertex shader narozdíl od pixel shaderu lze nahradit softwarovou emulací, tzn. že lze použít vertex shadery i na systémech se starším železem. Tento systém budeme používat, jen bude-li to potřeba.
18.1.5. Matice
Dále si něco povíme o maticích a je třeba abyste tuto část dobře pochopili. Pomocí matic provádíme v Direct3D transformace, tedy nejen ty, o kterých byla řeč před chvilkou. Později se dozvíte, že to není jediný způsob transformace.
Matematická vložka
Předpokládám, že každý ví, co je to vektor, ale pro úplnost zde uvedu několik poznámek z analytické geometrie a z lineární algebry.
Vektor
Vektor je obecně n-tice čísel např. vektor r = (r1, r2,
..., rn). My ale budeme používat vektory 2-4 rozměrné. Polohovým
vektorem je popsána poloha bodu v prostoru či v rovině. Například u
normálového vektoru nás zajímá především směr a nikoliv koncový bod (navíc
se většinou pracuje s jednotkovým vektorem, jehož velikost je rovna 1).
Mimochodem velikost vektoru můžeme spočítat pomocí následujícího vzorce:
Důkaz vztahu zde vynechám. V praxi ale budeme moci používat funkce D3DX knihovny, která je součástí SDK. Struktury 2-4 rozměrných vektorů jsou tedy D3DXVECTOR2, D3DXVECTOR3 nebo D3DXVECTOR4. Funkce, které vrací velikost vektorů se nazývají D3DXVec2Length(), D3DXVec3Length() nebo D3DXVec4Length().
Matice
Matice je tedy opět nějaká uspořádaná skupina čísel. Budeme výhradně používat matice 4x4, kterou vidíte na dalším obrázku:
Nyní si ukážeme, jak probíhá transformace pomocí této matice. Transformovat vektor znamená vynásobit ho touto maticí:
Původní vektor (x, y, z) transformujeme pomocí matice M na čárkovaný vektor (x, y, z) následovně:
Maticemi můžete provádět posuvný pohyb (translaci), otáčivý pohyb (rotaci) nebo změnu měřítka (scaling).
Nyní si proberme jednotlivé transformace:
Translace
Pokud chceme bod v prostoru posunout, stačí ho vynásobit následující maticí:
Kde Tx, Ty a Tz jsou relativní úseky v prostoru, o které se bod posune. V knihovně je opět funkce D3DXMatrixTranslation(), pomocí které vytvoříme příslušnou translační matici.
Rotace
Rotovat lze objektem kolem všech tří os a pro každou z těchto rotací musí být zvlášť matice:
Kolem osy x, kde θ úhel otočení v radiánech:
Kolem osy y:
Kolem osy z:
A opět je tu trojice funkcí, které vytvoří příslušné rotační matice: D3DXMatrixRotationX(), D3DXMatrixRotationY() a D3DXMatrixRotationZ().
Změna měřítka - scaling
Scaling může být buď uniformní či nikoliv. Uniformní znamená, že změna měřítka je podle všech os ekvivalentní, ale můžete těleso protáhnout třeba jen v jednom směru pomocí neuniformního scalingu. Scaling provádíme pomocí následující matice:
Kde sx, sy a sz jsou hodnoty, o které se těleso protáhne (smrští) ve směrech jednotlivých os. Pokud je hodnota větší než 1, těleso se v tomto směru zvětšuje, jeli hodnota menší než 1, těleso se smršťuje. Zadáte-li například hodnoty sx, sy rovno 1, docílíte neuniformního scalingu ve směru osy z. I pro tuto transformaci existuje funkce D3DXMatrixScaling(), která vytvoří výše uvedenou matici.
Skládání matic
Další výhodou matic je, že můžete jednotlivé "efekty" složit do jedné matice. Prostě je stačí mezi sebou vynásobit a tím spojíte efekty v nich uložené. Vynásobíte-li například matici translace a rotace, bod, který touto výslednou maticí transformujete se posune a otočí se kolem jedné z os.
K násobení můžete využít funkci D3DXMatrixMultiply(). U násobení matic je důležité, že záleží na pořadí v jakém násobení provádíte - neplatí zde komutativní zákon. Transformace se provádí zleva doprava, takže nejprve se provede transformace uvedená na prvním místě. Například:
C = R * T
C je složená matice, R je rotační matice a T je translační matice. Nejprve se tedy provede rotace a posléze translace.
A je tu opět konec další lekce. Dnes jsme nakousli rozsáhlé téma Direct3D: nejprve jsme si pověděli něco architektuře Direct3D, dále jsem popsal prostor a elementární objekt - trojúhelník, také jsme se zabývali zpracováním vertexů a nakonec jsme probrali všechny možné transformace.
V příští lekci již vytvoříme první Direct3D aplikaci. Zjistíte, že začátky jsou podobné jako v DirectDraw.
Těším se příště nashledanou.