játékfejlesztés.hu
FórumGarázsprojectekCikkekSegédletekJf.hu versenyekKapcsolatokEgyebek
Legaktívabb fórumozók:
Asylum:    5448
FZoli:    4892
Kuz:    4455
gaborlabor:    4449
kicsy:    4304
TPG:    3402
monostoria:    3284
DMG:    3172
HomeGnome:    2919
Matzi:    2520

Pretender:    2498
szeki:    2440
Seeting:    2306
Geri:    2188
Orphy:    1893
Joga:    1791
Bacce:    1783
MaNiAc:    1735
ddbwo:    1625
syam:    1491
(C++) DirectX programozás 12. - Direct3D 1. (bevezetés, alapok, képszintézis) 2006.05.19 13:11


Direct3D - Bevezetés

Ebben a részben a három dimenziós grafikával fogunk foglalkozni, persze a cél, hogy mindenki megértse, hogyan is működik, ne csak másolgassa a programokat. Előrebocsájtom, hogy a három dimenziós grafika nem nehéz, de sok-sok időt és tanulást, de főleg gyakorlást és kedvet igényel. Mindezt azért mondom, mert tudom, hogy sokan nem veszik komolyan a matek cikkeket, mert ugyan, a DirectX mindent elintéz! Pedig ez nem így van: tény, hogy segít, de nem alkot…
Ezért hangsúlyozom azt, hogy legyen kedvünk a matematikához is, és ha valamit nem érthető, nyugodtan meg lehet írni, megbeszéljük.

Azért is mondtam ezt, mert nem a DirectX-szet tanuljuk, hanem a három dimenziós grafikát. Azaz programozhatnánk akár Turbo C-ben is, de nem tesszük, mert például a textúrázás megtanulása nem célunk. Csupán olyan dolgokat kell megértenünk, amit muszáj lesz nekünk megírni, mert a DirectX már nem intézi el helyettünk. És cseppet sem elhanyagolandó, hogy a DirectX kihasználja a videókártya erőforrásait is.

Aki pedig megérti a grafikát magát, annak mindegy lesz, hogy OpenGL vagy DirectX, hiszen mindkettő azonos elven működik.

Tehát első lépésben olvassuk el az első öt matek cikket, majd térjünk vissza a Direct3D-hez, miután megértettük azokat. A matektudást(már ami a matematika cikkek között van) pedig ismertnek tekintem ezután.

Sok-sok kedvet és sikert kívánok!


A háromdimenziós képszintézis alapjai

Mielőtt elkezdenénk konkrétan foglalkozni a programozással, előtte foglalkoznunk kell azzal, hogy hogyan is jön létre a három dimenziós térben adott ponthalmazból egy két dimenziós kép. Hangsúlyozom, nem közvetlenül a DirectX által követett utat követjük, hiszen az jóval bonyolúltabb, illetve a projektív geometriára épít, azt pedig bonyolúltsága miatt nem tárgyaltuk. Viszont az is igaz, hogy gyakorlatilag az általunk és a DirectX által követett út lényegében megegyezik, kivéve a vetítést. De erről később.

Először megtárgyaljuk, hogyan is épül fel a jelentenek nevezett tér.

A jelenet geometriája

A jelenet három dimenziós testekből álló tér. Alapvetően minden testet a pontjaival(vertex) adunk meg. Hogy a megadás módja egyértelmű legyen, ezért egy nagyon egyszerű módszert használunk: minden testet háromszögekre bontunk, ez lesz egy primitív, hiszen tényleg a legegyszerűbb síkidom, aminek területe van. Ezeket a háromszögeket a pontjaival adunk meg, ami egyértelmű hiszen a három pont akármelyik sorrendben megadva egyértelműen jellemzi a háromszöget. A háromszög pontjainak van egy jellegzetes sorrendje: ha ránézünk a háromszögre, és úgy a pontjait olyan sorrendben adtuk meg, hogy jobbirányban haladnak, akkor pozitívan irányított (DirectX-ben). Azaz pl.:


Itt például a,b,c pozitívan irányított, viszont a,c,b nem. Tehát sikerült megadni egy háromszöget, megismerve az irányítását is. Már csak az a kérdés, hogy egy pontsorozatból hogyan alkothatunk egy testet? Erre többféle módszer van:
  1. hármasával csoportosítjuk a vertexeket, majd minden csoport ad egy háromszöget(TRIANGLELIST)
  2. az első három egy háromszög, majd minden következő pont az utolsó kettővel egy új háromszöget ad(TRIANGLESTRIP)
  3. az első három pont ad egy háromszöget, majd minden következő pont az utolsóval és az első ponttal alkot egy háromszöget(TRIANGLEFAN)


Az első kép pedig példa a TRIANGLESTRIP-re, a második kép pedig a TRIANGLEFAN-re, ha a vertexsorozat a,b,c,d,e,f. Ezzel tisztáztuk is a testek megadásának módjait.

DirectX-ben egy pontot három koordinátájával adjuk meg, tehát ismernünk kell a Direct3D-ben használt koordinátarendszert. Mi most a balkezes koordinátarendszert fogjuk használni, ami azt jelenti, hogy az x-tengely jobbra mutat, az y tengely felfele, a z pedig a képernyőbe befelé:


Ebben a koordinátarendszerben adjuk meg a pontokat egyszeres pontosságú(float) számokkal.

Ekkor már csak egy kérdés maradt: hogyan tudjuk ezt a három dimenziót leképezni két dimenzióra?

Képszintézis

A képszintézis alapvető célja, hogy a modelltérben, azaz a jelenetben levő testeket leképezzük egy kamera síkjára. Ez a kamera a térben bárhol lehet, és bármerre nézhet.


Tehát ebből a kamerából látható két dimenziós képre vagyunk kiváncsiak, azaz a csúcspontban lévő megfigyelő milyen képet lát a kamera síkján. A DirectX a kamerát három jellemzővel adja meg. Ez a három jellemző egy-egy vektor a modelltérben: a kamera helyzete(Eye), az a pont, amire a kamera néz(LookAt) és a felfele irány(Up). Ebből természetesen ki tudjuk számolni a kamera nézési irányát: Dir=LookAt-Eye, ami egy egyszerű kivonás vektorok közt. Ezek ismeretében már tudunk egy koordinátarendszert illeszteni a kamerára is. Ennek a koordinátarendszernek az origója az Eye, és három egység-bázisvektora:


Ezekkel a bázisvektorokkal már definiáltuk is az új koordinátarendszert(ami persze nem feltétlenül derékszögű, de normált). Ez azért fontos, mert a képszintézis első lépéseként át kell térnünk erre a koordinátarendszerre.

Az áttéréshez először az origóba kell rakni a kamerát, ami sajnos nem lineáris transzformáció, de egy egyszerű vektorművelettel megoldható, azaz az egész modelltért –eye vektorral el kell tolni, ami alatt azt értjük, hogy minden vertexet el kell tolni. Tehát így minden pont vektorából ki kell vonni az eye vektort. Ezt megoldhatjuk négyszer-négyes mátrix szorzással is, ahogy a DirectX, de ez most nem fontos.

A következő tennivaló ezután, hogy bázist váltunk, azaz megkeressük minden vertex a,b,c, azaz kamerabázisbeli koordinátáit. Ez nyilván lineáris transzformáció, tehát kereshető hozzá egy lineáris transzformáció, aminek a mátrix reprezentációja ezt teszi. Most nem részletezem a módszert, de több-kevesebb átalakítás után azt kapjuk, hogy egy pont a,b,c bázisbeli koordinátája(d1,d2,d3) és az eredeti bázisbeli(modelltér koordinátarendszer) koordinátái(v1,v2,v3) között az alábbi összefüggés áll fenn:


Itt ai az a bázisvektor modelltér koordinátarendszerbeli koordinátái, bi b-jé és ci c-jé. Derékszögű koordinátarendszer esetén a bázisváltás természetesen három forgatással(egyes tengelyek körül) megoldható. Ekkor már megoldható egy alapszintű takarási feladat(konvex testekre), mely közel felére csökkenti a vizsgálandó háromszögek számát, hiszen a pozitív z koordinátájú háromszög normálisok(normálvektor, ami ugye merőleges a háromszög síkjára) azt jelentik, hogy az a háromszög a test túloldalán van, azaz nem látszik. Ezért is beszéltem a pozitív körüljárásról, hiszen csak azok a háromszögek fognak látszani, melyek az aktuális nézőpontból pozitív körüljárásuak. Tehát ez a takarási munka egyszerű, pl.(oldalról nézve a testet):


Az ábrából jól látható, hogy a hátrafelé mutató normálissal rendelkező háromszögek kiesnek. A további takarásról később.

A megmaradt feladat a vetítés. Ez lehet vagy középpontos(ez egyszerű, de nem túl hasznos). Amit mi használunk, azt részletezzük, mert bonyolúlt projektív geometriát igényel. Csupán egy-két dolgot említünk meg. Lényege a dimenziócsökkentés, azaz 3D-s képből 2D-s képet alkot. A vetítés több paraméterrel jellemezhető:
  1. látószög
  2. aspektus arány(aspect ratio), azaz a vetítősík oldalainak aránya
  3. elülső és hátulsó vágósík, ez előtt ill. mögött levágjuk a képet
Ez a vetítés ugyancsak leírható 4x4-es mátrixszal, DirectX is ezt alkalmazza. Tehát vetítjük a kamera koordinátarendszerbeli pontokat, majd összekötjük őket, hiszen mindegyik eddigi transzformáció szakasztartó volt. Ekkor megkapjuk a jelenet drótvázas képét, ami a legegyszerűbb képszintézis módszer. Ezzel készen is lennénk, a textúrázással kapcsolatban pedig csupán pár apróságot emelünk ki, ugyanis azt teljes egészében átvállalja a DirectX. A textúra pontjainak leképezése a képszintézis folyamata alatt a vetítésnél történik.

A textúrakoordináták

Egy textúrázott test azt jelenti, hogy a felszínének pontjait kölcsönös kapcsolatba hozzuk egy kép pontjaival, azaz a test pontjainak színét egy képből kapjuk. A testet, mint megbeszéltük, felbonthatjuk háromszögekre. Ezek a háromszögek és egy kép pontjai között kell leképezési módszert találnunk. Ez DirectX-ben nagyon egyszerű: a háromszög minden pontjához megmondjuk, hogy a textúra melyik pontja esik rá. Ehhez csupán a textúrakoordinátarendszert kell ismerni.

A textúra egy kép, azaz egy téglalap. A téglalap bal felső sarka az origó, a két, ebből a pontból kiinduló oldalak pedig a bázisvektorok. Azaz a jobbfelső sarok az (1,0), a balalsó sarok pedig a (0,1) pont. Tehát pl.:


Egy egyszerű textúrázási példához nézzük az alábbi háromszöget, és minden pontja mellet zárójelben a hozzárendelt textúra koordinátát:


Ebben az esetben a háromszög c pontjában van a textúra balfelső sarka, és ez a textúra függőlegesen kétszer, vizszintesen félszer van kifeszítve. Remélem érthető, ha nem, majd a textúrázás programozásánál világos lesz.

Végső takarás megoldása

A DirectX a végső takarási feladatot nagyon egyszerűen, pixelekre oldja meg a z-buffer algoritmussal. Lényege, hogy a képernyő minden pixeléhez létrehoz egy buffert, amiben tárolja a pixelre vetülő pont z koodinátáját. Ha talál még egy pontot, ami erre a pixelre vetül, akkor a z értékét összehasonlítja a már beírt z értékkel. Ha az új z érték kisebb, mint a bennt lévő, akkor pixelt csrél, ha nem, akkor marad minden a régiben. Belátható, hogy ez így tényleg megoldja a takarást.

Ennyit átfogóan a DirectX-ről, akkor neki is állhatunk programozni.


2006. február 6.

Crusader


Kapcsolódó linkek:

A cikksorozat további részei:

Értékelés: 0

Új hozzászólás
Hacker          2006.05.20 00:49
Az ütközésvizsgálati cikke nagyon jó! Remélem itt is debütálni fog!
HomeGnome          2006.05.19 23:26
A cikket februárban írta Crusader, miért is ne olvashattad volna. Nálunk viszont most jelenik meg, és a sorozat többi tagját is közöljük hamarosan.
kicsy          2006.05.19 15:30
Nem friss cikk, csak most került ki.
szeki          2006.05.19 14:45
én ezt mindtha már olvastam volna valahol.. Vagy csak képzelődök?