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 15. - Direct3D 4. (Textúrázás alapjai) 2006.06.09 01:46


Textúrázás

Ez a téma a három dimenziós grafika alapjaihoz tartozik, ugyanis viszonylag könnyen tudunk részleteket megjeleníteni testeken komolyabb telejsítménycsökkenés nélkül. A textúrázás azt jelenti, hogy a megjelenítendő test felszínére egy képet rakunk, így például könnyen készíthetünk egy egyszerű kockából egy fakockának kinéző tárgyat anélkül, hogy túlságosan elbonyolítanánk a geometriáját.

Tudnunk kell, hogy a textűrázás egy sokkal komplexebb téma az itt leírtaknál, bár bizonyos dolgokra még későbbi cikkben visszatérünk.

Remélem többet nem kell írnom arról, mi is az a textúrázás, hiszen számítógépes játékokból már mindenki jól ismeri őket. Inkább beszéljünk mégegyszer a texturakoordinátákról! Alapvető esetben képzeljünk el egy síkot, és jelöljünk ki ezen egy origót. Ekkor rakjuk az origóba a textúra bal felső sarkát, majd minden irányban végtelen sokszor ismételjük meg a textúrát(ami nyilván egy kép)! Ekkor a síkon két bázisvektort mérhetünk fel: az egyik az origóból a kép jobb felső sarkába mutat, a másik az origóból a bal alsó sarokba. Ekkor már értelmeztük is a textúrakoordinátákat. Ekkor például a képen látható piros pont a (1.5,1.0) koordinátájú pont:


Mint látjuk, a kép tényleg ismétlődik minden irányban, most az origó ténylegesen is a kép bal felső sarka. Gondolom eddig nem bonyolúlt. Természetesen a DirectX támogatja azt is, hogy a síkban a textúrákat nem csupán megismétli, hanem egyes irányokban mindig a textúra tükörképét rakja, így például az első sor első eleme az igazi textúra, a második tükörkép, a harmadik megint igazi, stb.

Most már csak az a kérdés, hogy hogyan rendeljük hozzá ezt a két dimenziós testet egy három dimenziós testhez? Egyszerűen, csupán egy háromszög minden csúcsához, vertexéhez megmondjuk, hogy a textúratér melyik koordinátája tartozik. Ekkor a textúrát akármilyen pózban rárakhatjuk a háromszögre, a közbülső pontokra a megfelelő koordinátákat a DirectX kiszámolja. Ez így lehet, hogy bonyolúlt, de az első cikkben már néztünk rá példát, a programot variálva pedig majd megvilágosodik.

Akkor nézzük is a programozási részt! A textúrát mindenféle effekt nélkül fogjuk kifeszíteni, az effektekről majd később. Mindenekelőtt kell egy vertexformátum, ugyebár, mint mindig:

#define CUSTOM_VERTEX (D3DFVF_XYZ|D3DFVF_TEX1)

Ez azt jelenti, hogy a vertexeink természetesen transzformálatlanok, és egyetlen textúrát akarunk rá kifeszíteni(nincs jelenleg multitextúrázás). Több textúra használatáról majd később. Ekkor kell egy ehhez szükséges vertexstruktúra:

struct CUSTOMVERTEX {
      FLOAT x,y,z;
      FLOAT tu,tv;
};

, ahol ugye a textúra két textúratérbeli koordinátája van megadva. Ha több textúránk lenne, akkor még lenne ugyanannyi textúrakkordinátapár, ahány textúra. Ha nem adunk meg koordinátát, alapértelmezében mind a tu, mind a tv nulla, így az egész testre a textúra(azaz kép) első pixelje vetül, magyarul egyszínű lesz a test. Ekkor adjuk meg a négyzetünket, amire egyszer fogjuk a teljes textúrát, azaz képet kifeszíteni:

CUSTOMVERTEX vertices[]=
{
      { -1.0f, -1.0f, 0.0f,  0.0f, 1.0f},
      { -1.0f,  1.0f, 0.0f,  0.0f, 0.0f },
      {  1.0f, -1.0f, 0.0f,  1.0f, 1.0f},
      {  1.0f,  1.0f, 0.0f,  1.0f, 0.0f },
};

Itt minden pixelhez megadtuk a hozzá tartozó textúra egy pontját a textúratérbeli koordinátákkal. Ez most jól láthatóan egyszer lesz kifeszítve(természetesen TRIANGLE_STRIP-et használunk). Ez teljesen olyan, mintha magát a képet jelenítenénk meg, de ezt ne gondoljuk így, hiszen egy testet jelenítünk meg(négyzetet), csak csupán nem szinezzük, hanem a test pontjait egy kép pontjai szerint szinezzük, és ez a kép a textúra. Ha a textúrakkoordinátákat nem a sima ismétléses textúratérben értjük, hanem például tükrözöttbe(erről írtam az előbb), akkor azt meg kell adnunk:

lpD3D_Device->SetSamplerState(0,D3DSAMP_ADDRESSU, D3DADDRESS_MIRROR);

Itt az első paraméter nulla, ezt most nem tárgyaljuk miért, egy későbbi cikkben majd kiderül, a második paraméter pedig azt jelenti, hogy a textúra u irányban, azaz vízszintesen tükrözve legyen(a harmadik paraméter jelenti a tükrözést). De mi most az alapbeállítást használjuk, azaz azt, hogy a textúratérben a textúra csupán ismétlődjön:

lpD3D_Device->SetSamplerState(0,D3DSAMP_ADDRESSU, D3DADDRESS_WRAP);

Ezt természetesen nem kell beállítani, mert ez az alapértelmezés. Mindkettőt meg lehet csinálni a v koordinátára is. Igaz, most mindegy, hogy tükrözünk, vagy nem, mert az első textúra úgyis simán lesz kirajzolva… További textúratérbeli beállítások az SDK-ban vannak leírva.

Következő lépésben kell egy textúra típus:

LPDIRECT3DTEXTURE9                 lpD3D_Texture=NULL;

majd ebbe bele kell tölteni egy képet, amit textúrának szeretnénk használni:

D3DXCreateTextureFromFile(lpD3D_Device,"texture.bmp",&lpD3D_Texture);

Itt gondolom mindegyik paraméter egyértelmű, csupán azt írnám le, hogy nem csupán bmp kép tölthető be, hanem többek közt jpeg és targa képformátumok is. Az ismert formátumok ugyancsak az SDK dokumentációjában megtalálhatóak. Megjegyzem, hogy létezik egy D3DXCreateTextureFromFileEx(…) függvény is, ezzel sokkal több beállítással tudjuk betölteni a textúránkat, úgymint colorkey, stb.

Ha a textúraazonosítónk ezután NULL értékű lesz, akkor hiba történt a betöltésnél(pl. nem található a fájl).

Ezután már csak renderelésnél mielőtt kirajzoljuk a primitívet, be kell állítanunk az aktuális textúrát, amit minden DrawPrimitive(…) függvény rá fog feszíteni az általa kirajzolt primitívekre. Természetesen ha több primitívünk van, és mindegyik más más textúrát használ, akkor mindegyik kirajzolása után be kell állítanunk az aktuális textúrát. Ezt így tudjuk:

lpD3D_Device->SetTexture(0,lpD3D_Texture);

Ezután már rajzolhatjuk is ki a primitívünket, rá fog kerülni a textúra, természetesen a vertexek textúrakoordinátáinak megfelelően. Előkerült ismét ez a nulla szám a paramétereknél, de erről majd máskor fogunk beszélni.

De beszélünk inkább a textúraszűrésről. Mindenki emlékszik például a DukeNukem pixeles grafikájára, ahol a képek jól látható pixelekre estek szét. Ezt szűnteti meg a textúraszűrés.

Alapvetően két eset létezik: a textúra nagyobb, mint az a primitív, amire kifeszítjük, illetve a textúra kisebb, mint amire ráfeszítjük. Ugyebár az előbbinél a textúrát össze kell nyomni, utóbbinál pedig szét kell húzni. Mindkét esetre tudunk szűrést beállítani.

Abban az esetben, ha a textúrát nagyítani kell, akkor a szűrést a

lpD3D_Device->SetSamplerState(0,D3DSAMP_MAGFILTER, D3DTEXF_NONE);

ha kicsinyíteni kell, akkor a

lpD3D_Device->SetSamplerState(0,D3DSAMP_MINFILTER, D3DTEXF_NONE);

paranccsal tudjuk beállítani a szűrést(MAG-magnification, MIN-minification). Többféle textúraszűrés létezik, az előbbi példákban nem állítottunk be szűrést, a textúra pixeles lesz.

A legegyszerűbb szűrés, ha mindig a testen a pont színét a textúrára vetülő ponthoz legközelebbi egész számhoz tartozó pixelből vesszük. Ezt hívjuk Nearest Point Texture Filtering-nek. Ennek a flagje D3DTEXF_POINT. A gyakorlatban leginkább a Bilinear Texture Filtering-et használják. Ez azt jelenti, hogy a vetülő pont körüli négy pixel színének átlagát kapja a pont. A flag D3DTEXF_LINEAR. Létezik továbbá mip-mapping is, ami sok memóriát fogyaszt, ugyanis a testhez több textúrát rendel, más-más méretűt, így pl. kicsinyítésnél nem egy nagy textúrát kicsinyít, hanem egyből egy kis textúrát rak a testre. Belátható, hogy ez sok memóriát igényel, hiszen több textúrát kell eltárolni.

A példaprogramban az F1 billentyű esetén nincs textúraszűrés, F2 esetén bilinear szűrést alkalmaz. Az előrenyíllal közelíthetjük a forgó négyzetet, a hátra nyíllal távolíthatjuk(ehhez a kamera pozicíóját változtatjuk). Direkt kicsi textúrát használtam, hogy jól lehessen látni a szűrést.

d3d3.exe


2006. február 14.

Crusader


Kapcsolódó linkek:

A cikksorozat további részei:

Értékelés: 0

Új hozzászólás
Nincs megjegyzés