Direct 3D - Základy 3D grafiky
Doteraz sme sa zaoberali iba 2D grafikou. Nemalo by pre vás byť problém urobiť jednoduchú 2D hru. Doterajšie vedomosti vám však poslúžia pri prechode k 3D. Preto pre tých, ktorí ešte nemajú žiadne skúsenosti s D3D odporúčam prečítať si predchádzajúce časti.
Teraz sa dostávame k zaujímavejšej časti grafiky DirectX, ktorou je 3D. Bohužiaľ, nie ľahšej. Treba si uvedomiť, že nám pribudol tretí rozmer Z, čo výpočty dosť značne sťažuje. Pre transformáciu objektov v 3D priestore budeme používať matice. Je to najrýchlejší a zároveň najprehľadnejší spôsob, ktorý využil aj Microsoft v Direct3D.
Teória
Matice (anglicky: Matrix, plural: Matrices) - Je to matematický postup, ktorý využíva Direct3D pri 3D operáciách. Pochopenie princípu počítania s maticami bude pre vás veľkou výhodou. I keď nie je to nutné, pretože Direct3D ponúka množstvo funkcií, ktoré všetko urobia za vás.
Poznáme 3 typy matíc: Priestoru, Pohľadu a Projekcie
Priestoru - (world matrix) určuje presnú polohu vertexov v priestore. Tu je potrebné si ujasniť pojem priestor: Je to množina všetkých bodov v scéne.

Na priestor môžeme aplikovať transformácie ako sú: presúvanie, zmena veľkosti a rotácia. Všetko sa to deje pomocou matíc. Tzn., že keď chceme rotovať všetky vertexy v priestore aplikujeme naň maticu rotácie. Červená kocka v obrázku predstavuje výrez z priestoru, ktorý obsahuje 1 vertex. Po použití matice rotácie sa otáčajú všetky body v priestore podľa osi y, o uhol alfa.
Je dôležité zachovať postupnosť transformácií. Je rozdiel rotovať okolo osi X a potom Z, ako keď najprv rotujete okolo Z a potom X.
Keď chcete použiť viacero typov transformácií naraz (rotáciu a zároveň presúvanie), dajú sa pomocou funkcie D3DXMatrixMultiply skombinovať. Je efektívnejšie skombinovať 5 transformácií (transformačných matíc) do jednej ako aplikovať každú samostatne.
Pohľadu - (view matrix) si môžete predstaviť ako kameru, ktorá sa nachádza na nejakom bode so súradnicami X,Y,Z a pozerá sa na iný bod v priestore. U hier typu Doom je to práve postava, za ktorú hráte a zameriavač vašej zbrane je miesto, kam sa kamera pozerá. Tu si treba uvedomiť jednu vec: pokiaľ sa vám na obrazovke nič nezobrazí može to byť tým, že ste urobili chybu v kóde alebo zle nastavili kameru (resp. v jej zornom poli nie je žiadny objekt). Takéto chyby sa dosť ťažko odlaďujú, preto buďte opatrný a svoj program priebežne
testujte.
Projekcie - (projection matrix alebo aj field of view (FOV)) určuje spôsob ako bude 3D priestor zobrazený na 2D obrazovku. Môžete si nadefinovať úplne iný tvar objektov ako v skutočnosti vyzerajú, t.j. roztiahnuť, predĺžiť. Môžete určiť do akej vzdialenosti od kamery budú objekty zobrazené. Ako keby ste sa hrali s objektívom kamery.
Použitie v praxi
Direct3D obsahuje mnoho vstavaných funkcií pre prácu s maticami. V závere tejto lekcie si podrobne ukážeme ako tieto funkcie pracujú.
Postup je rovnaký ako v predchádzajúcich lekciách: Deklarujeme vertex, naplníme štruktúru vertexu potrebnými údajmi. Nezabúdajte, že teraz zadávame aj Z súradnicu.
'Vypnutie osvetlenia D3DDevice.SetRenderState D3DRS_LIGHTING, False 'Vypnutie vykreslovania objektov iba z jednej strany D3DDevice.SetRenderState D3DRS_CULLMODE, D3DCULL_NONE
Skôr než niečo zobrazíme, musíme si správne nakonfigurovať renderovacie zariadenie (D3DDevice) pomocou SetRenderState. Keďže v projekte ešte nepoužívame žiadne svetlá musíme vypnúť globálne svetlo v celom projekte. Defaultne je svetlo zapnuté, a tak by sa stalo, že na obrazovke nič neuvidíme (objekt by nemal byť čím osvetlený).
Taktiež je potrebné nastaviť resp. vypnúť CULLING. Každý trojuholník má dve strany, ale D3D štandardne zobrazuje iba jednu. Skúste zapoznámkovať tento riadok kódu a uvidíte, čo sa stane.
Poslednou fázou je nastavenie a použitie matíc:
Dim matWorld As D3DMATRIXDim matView As D3DMATRIX Dim matProj As D3DMATRIX
Aj matice je potrebné deklarovať.
D3DXMatrixLookAtLH matView, _ VytvorVektor (0, 5, 9), _ VytvorVektor (0, 0, 0), _ VytvorVektor (0, 1, 0) D3DDevice.SetTransform D3DTS_VIEW, matView
D3DXMatrixLookAtLH
Maticu pohľadu vytvoríme funkciou D3DXMatrixLookAtLH.
Mout = matView - matica pohľadu
VEye = VytvorVektor (0, 5, 9) - 3Dvektor (so súradnicami XYZ), ktorý udáva polohu kamery
VAt = VytvorVektor (0, 0, 0) - 3Dvektor, ktorý udáva kam sa kamera pozerá
VUp = VytvorVektor (0, 1, 0) - 3Dvektor, ktorý udáva ,,kde je hore”. Obyčajne býva (0,1,0)
Takto vytvorenú maticu použijeme príkazom SetTransform. Prvý parameter udáva o aký typ matice ide (priestoru, pohľadu, projekcie). Druhý je nami vytvorená matica.
D3DXMatrixPerspectiveFovLH matProj, pi / 4, 1, 0.1, 500 D3DDevice.SetTransform D3DTS_PROJECTION, matProj
Takto jednoducho sa dá vytvoriť matica projekcie:
D3DXMatrixPerspectiveFovLH
MOut = matProj - matica projekcie
fovy = pi / 4 - uhol pohľadu (v radiánoch)
aspect = 1 - pomer výšky a šírky obrazu. Jednotka znamená pomer 1:1
zn = 0.1 - najbližší bod
zf = 500 - najvzdialenejší bod
Zn a zf určujú rozsah viditeľnosti bodu. Ak je vzdialenosť bodu (alebo celého objektu) väčšia ako zf, potom nebude zobrazený. Obidva údaje sú v metroch . Nastavením malého Zf sa vzdialenejšie objekty nevykreslia, čím sa značne zníži zaťaženie systému. Toto využíva mnoho hier, kde na konci viditeľnosti sa použije hmla (fog).
Ako posledné som si nechal maticu priestoru, ktorá nám otáča objekt:
Dim matWorld2 As D3DMATRIX uhol = uhol + 0.1 If uhol >= 360 Then uhol = 0 D3DXMatrixIdentity matWorld D3DXMatrixIdentity matWorld2 D3DXMatrixRotationX matWorld, uhol * (pi / 180) D3DXMatrixRotationZ matWorld2, uhol * (pi / 180) D3DXMatrixMultiply matWorld, matWorld, matWorld2 D3DDevice.SetTransform D3DTS_WORLD, matWorld
Úlohou tohto kódu je rotovať objekt okolo osi X a Z. To zabezpečujú dve funkcie D3DXMatrixRotationX a D3DXMatrixRotationZ. Prvá nastaví maticu matWorld, tak aby rotovala objekt okolo osi X a druhá nastaví matWorld2, tak aby rotovala objekt okolo osi Z. Uhol rotácie sa pri každom novom frame mení o 0,1 stupňa. Avšak D3D nepracuje so stupňami, preto všetko treba konvertovať na radiány. Potom pomocou D3DXMatrixMultiply vynásobí tieto matice, a tak dostane 1 výslednú, ktorá bude robiť presne to, čo tie dve dohromady.
Syntax je nasledovná: D3DXMatrixMultiply (cieľová matica, zdroj1, zdroj2)
Príkaz D3DXMatrixIdentity je v tomto kóde zbytočný. Jeho úlohou je obnoviť maticu na základnú hodnotu, a tým nastaviť uhol otáčania na 0. Podrobnosti sa dozviete, keď budete čítať ďalej.
To je všetko k základom 3D. Pomocou vstavaných funkcií je to rýchle a jednoduché. Na záver ešte uvediem zoznam často používaných funkcií na transformáciu priestoru:
D3DXMatrixRotationX - rotácia okolo osi X
D3DXMatrixRotationY - rotácia okolo osi Y
D3DXMatrixRotationZ - rotácia okolo osi Z
D3DXMatrixRotationAxis - rotácia okolo definovanej osi
D3DXMatrixRotationYawPitchRoll - špeciálny typ rotácie. Efekt: podobný letu lietadla
D3DXMatrixScaling - zväčšovanie/zmenšovanie
D3DXMatrixTranslation - posúvanie v smere X,Y,Z
D3DXMatrixTranspose - prepis pomocou inej matice
Počítanie s maticami
Teraz si bližšie vysvetlíme ako to celé funguje. Na začiatku vás upozorňujem, že pochopenie nasledujúcich riadkov nie je nevyhnutné. Direct3D obsahuje množstvo pomocných funkcií (pozri vyššie), ktoré stačia na väčšinu transformácií. Každopádne trocha matematiky nikomu nezaškodí.
Direct3D používa matice 4×4. Všeobecný predpis matice sa nachádza medzi červenými hranatými zátvorkami. Pomocou nej môžeme transformovať každý bod v priestore so súradnicami X,Y,Z, čím dostaneme nový bod X’ Y’ Z’. Presnejšie povedané, keď vynásobíme akýkoľvek bod s maticou, dostaneme nový bod. Z pohľadu VB je matica dvojrozmerné pole.

Násobenie je trocha odlišné od bežného spôsobu. Tak ako ukazuje obrázok: transformovanú prvú súradnicu (X’)dostaneme tak, že najprv sa vynásobíme každú súradnicu príslušným členom matice v prvom stĺpci a následne tieto násobky spočítame. Podobne je to aj pre druhú a tretiu transformovanú súradnicu, pričom násobenie prebieha s členmi v druhom a treťom stĺpci. Posledný štvrtý prvok matice sa dopĺňa jednotkou.

Deklarácia matice vo VB je nasledovná:
Type D3DMATRIXm11 As Single m12 As Single m13 As Single m14 As Single m21 As Single m22 As Single m23 As Single m24 As Single m31 As Single m32 As Single m33 As Single m34 As Single m41 As Single m42 As Single m43 As Single m44 As Single End Type
Translácia
Najjednoduchší typ transformácie. Je to posúvanie bodov po priamke určenej vektorom. Na každý typ transformácie sa používa špecifická matica. Translačná matica má na spodku vektor daný Tx, Ty, Tz a jednotky po diagonále.

Výsledkom násobenia je rovnica: transformovaný bod (X’,Y’,Z’) = bod (X,Y,Z) + vektor (X,Y,Z). Príklad: Máme bod A (2,0,5) a chceme ho premiestniť do bodu B(0,3,2). Riešenie: Využijeme translačnú maticu s vektorom u(-2, 3, -3). Potom to už len stačí prepísať do VB kódu:
Sub TranslaciaMatice (matica As D3DMATRIX, v As D3DVECTOR) D3DXMatrixIdentity matica 'reset matice matica.m41 = v.x 'X komponent vektora matica.m42 = v.y 'Y komponent matica.m43 = v.z 'Z komponent D3DDevice.SetTransform D3DTS_WORLD, matica End Sub
Rotácia
Rotovať môžeme okolo osi X, Y alebo Z. Nezabudnite, že uhol rotácie je v radiánoch, nie v stupňoch. Prevod medzi nimi je nasledovný:
Rad = stupen * (pi /180). Aj tu použijeme špeciálny typ matice:

Uvediem už iba kód vo VB pre rotáciu okolo osi X:
Sub RotaciaMatice (matica As D3DMATRIX, uhol As Single) D3DXMatrixIdentity matica 'reset matice Dim Radian as Single Radian = uhol * pi /180 'Prevod na radiány matica.m22 = Cos (Radian) matica.m23 = Sin (Radian) matica.m32 = -Sin (Radian) matica.m33 = Cos (Radian) D3DDevice.SetTransform D3DTS_WORLD, matica End Sub
Scaling
Predstavuje zmenu veľkosti objektu. Ten môžeme zväčšiť, zmenšiť alebo roztiahnuť v závislosti na tzv. scaling faktor s(X,Y,Z). Ak je rovný 1 (default), potom objekt si zachováva pôvodnú veľkosť.

Sub ScalingMatice (matica As D3DMATRIX, s As D3DVECTOR) D3DXMatrixIdentity matica 'reset matice matica.m11 = s.x matica.m22 = s.y matica.m33 = s.z matica.m44 = 1 D3DDevice.SetTransform D3DTS_WORLD, matica End Sub
Ide skôr o zhusťovanie alebo naopak rozptýlenie bodov k originu.
Príklad: Máme úsečku AB tvorenú bodom A(2,0,0) a B(5,0,0). Chceme ju dvojnásobne roztiahnuť v smere osi X. Potom scaling faktor bude s(2,1,1). Výsledok: Bod A bude mať súradnice A(4, 0, 0) a B(10,0,0). Úsečka s pôvodnou dĺžkou X = 5 - 2 = 3 teraz meria X’ = 10 - 4 = 6. Určite ste si všimli, že okrem toho, že zmenila veľkosť sa presunula o 2 doprava. Z toho vyplýva, že pri scalingu mení objekt veľkosť, ale aj polohu.
Kombinovanie matíc
Určite sa stretnete s prípadom, kedy budete potrebovať objekt najprv napríklad zväčšiť a zároveň rotovať. Z toho, čo sme si doteraz ukázali by ste najprv aplikovali maticu zväčšenia a potom rotácie. Efektívnejšie a rýchlejšie (hlavne pre procesor) je zlúčiť obidve matice dohromady a aplikovať už iba výslednú.
To, čo teraz nasleduje vyzerá dosť zložito. Preto nenechajte sa odradiť. Je to to isté, čo sme robili doteraz, len vo väčšom množstve.
Najprv zlúčime všetky matice do jednej. Budeme zlučovať 5 matíc: translácie, rotácieX, rotácie Y, rotácie Z a scalingu.


Nebudem to tu celé rozpisovať. Toto je výsledok. Dopracujete sa k nemu násobením všetkých 5 matíc. Ako násobíme (zlučujeme) dve matice ? Pozrite sa na obrázok: Prvý stĺpec druhej matice s každým riadkom prvej matice. Potom nasleduje druhý, tretí a štvrtý stĺpec.

Výsledný násobok vynásobíte s 3, 4 a nakoniec 5 maticou.
VB kód:
Private Function CreateMatrix(Rx As Single, Ry As Single, Rz As Single, Sx As Single, _ Sy As Single, Sz As Single, Tx As Single, Ty As Single, Tz As Single) As D3DMATRIX Dim CosRx As Single, CosRy As Single, CosRz As Single Dim SinRx As Single, SinRy As Single, SinRz As Single CosRx = Cos(Rx) 'pouzite 6x CosRy = Cos(Ry) 'pouzite 4x CosRz = Cos(Rz) 'pouzite 4x SinRx = Sin(Rx) 'pouzite 5x SinRy = Sin(Ry) 'pouzite 5x SinRz = Sin(Rz) 'pouzite 5x With CreateMatrix .m11 = (Sx * CosRy * CosRz) .m12 = (Sx * CosRy * SinRz) .m13 = -(Sx * SinRy) .m21 = -(Sy * CosRx * SinRz) + (Sy * SinRx * SinRy * CosRz) .m22 = (Sy * CosRx * CosRz) + (Sy * SinRx * SinRy * SinRz) .m23 = (Sy * SinRx * CosRy) .m31 = (Sz * SinRx * SinRz) + (Sz * CosRx * SinRy * CosRz) .m32 = -(Sz * SinRx * CosRx) + (Sz * CosRx * SinRy * SinRz) .m33 = (Sz * CosRx * CosRy) .m41 = Tx .m42 = Ty .m43 = Tz .m44 = 1# End With End Function
Táto funkcia je dokonca rýchlejšia ako vstavané D3Dx funkcie. Sínus a kosínus sú dosť náročné na procesorový čas, preto je výhodnejšie vypočítať ich iba raz a uložiť do premennej. Pri každom daľšom použití sa nemusí znova prepočítavať.
Matrix Identity
Doteraz som komentoval tieto dve slová ako reset matice. Čo to pre nás znamená ? Vychádzajme z matice pre zmenu veľkosti. Dosaďte za Sx, Sy a Sz jednotku. Znamená to, že veľkosť ostala identická (z toho ten názov). Potom matica bude vyzerať takto:

Keď ktorýkoľvek bod vynásobíme touto maticou dostaneme ten istý bod. Napriek tomu má veľký význam: Možno ste sa už počas čítania zamýšľali nad tým, ako dosiahnuť to, aby jeden objekt napr. rotoval a druhý ostal v pôvodnej polohe.
Postup:
1. Zobrazíte objekt1 a použijete rotačnú maticu.
2. Použijete Matrix Identity, čím resetujete maticu a potom zobrazíte objekt2.
Keby sme nepoužili Matrix Identity rotovali by obidva objekty.
Na záver už len dodám, že tieto poznatky môžete využiť aj v 2D prostredí. Samozrejme vynecháte Z rozmer a použijete maticu 3 x 3.