Textúrázás
1. Folytassuk az előző órai projekt bővített változatát!
2. A textúrázás egy kép pontjait rendeli a modell térbeli háromszögeinek pontjaihoz.
Ehhez az egyes csúcspontokra meg kell adni, hogy a kép - a textúra - melyik pontja tartozik hozzá. Az egyes háromszögeken belül a csúcsokhoz megadott textúra-koordinátákat lineárisan interpolálja a videókártya, és ezek alapján olvas a textúrából.
A textúrázáshoz meg kell adnunk a textúra-koordinátákat mindent csúcsponthoz. Ehhez bővíteni kell az FVF-et:
enum {FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)};
A D3DFVF_TEX1 adja meg, hogy a csúcshoz egyetlen textúra-koordináta vektor tartozik (tartozhat hozzá akár nyolc is), és a D3DFVF_TEXCOORDSIZE2(0) adja meg, hogy a 0. textúra-koordináta vektor kétdimenziós.
Ennek megfelelően a VERTEXFORMAT-ba is újabb adattagot kell felvennünk:
struct VERTEXFORMAT { D3DXVECTOR3 v; D3DXVECTOR3 n; D3DXVECTOR2 tex; // textura-koordnatak };
3. A textúrákat a IDirect3DTexture9 interface-en keresztül tudjuk majd használni. Vegyünk fel egy ilyen mutatót az osztályunkba:
IDirect3DTexture9* _texture;
Ezt a szokásos módon inicializáljuk a konstruktorban, és szabadítsuk fel az onDestroyDevice-ban!
4. A négyzetrács létrehozásakor adjuk meg a textúra-koordinátákat is:
HRESULT Textures::onCreateDevice() { VERTEXFORMAT vs[N*N]; for (int i=0; i<N; ++i) for (int j=0; j<N; ++j) { vs[N*i+j].v = D3DXVECTOR3(1.0f*j/(N-1)-0.5f, 0, 0.5f-1.0f*i/(N-1)); vs[N*i+j].n = D3DXVECTOR3(0, 1, 0); // Itt adjuk meg a textura-koordinatakat vs[N*i+j].tex = D3DXVECTOR2(1.0f*j/(N-1), 1.0f*i/(N-1)); }
5. Töltsük be a textúrába a checker.png kép tartalmát a D3DXCreateTextureFromFile függvénnyel még az onCreateDevice-ban:
D3DXCreateTextureFromFile(_device, L"checker.png", &_texture);
(A képfile legyen a projekt főkönyvtárában!)
6. Rajzolás előtt meg kell adni a DirectX-nek, hogy melyik textúra, és milyen sorszámmal legyen aktív a IDirect3DDevice9::SetTexture hívással:
_device->SetTexture(0, _texture);7. Hibátlan fordítás esetén, bekapcsolt fényekkel ilyen képet kell kapnunk:
Közösfeladatok
Töltsünk be még két textúrát, és a különböző oldalakon ezek jelenjenek meg!
Az onCreateDevice-ban állítsuk át a textúrakoordinátákat, hogy ne [0, 1] hanem [0, 2] intervallumon menjenek!
Most az egyes textúrák négyszer szerepelnek az oldalakon.
Ismét állítsuk át a textúrakoordinátákat, hogy most a [-0.5, 1.5] intervallumon menjenek!
A [0, 1] intervallumon kívül eső koordináták értelmezése a IDirect3DDevice9::SetSamplerState hívással adható meg. A Type paraméter D3DSAMP_ADDRESSU, D3DSAMP_ADDRESSV ill. D3DSAMP_ADDRESSW adja meg külön tengelyenként az értelmezés módját. Az ezekhez tartozó lehetséges Value paraméter értékeket a D3DTEXTUREADDRESS adja meg (alapértlemzett a D3DTADDRESS_WRAP).
Próbáljunk ki ezeket! A SetSamplerState-et az onCreateDevice-ban hívjuk meg!
D3DTADDRESS_BORDER esetén meg kell adni a keret színét, ami a [0, 1] intervallumon kívül jelenjen meg. Ez a SetSamplerState segítségével, D3DSAMP_BORDERCOLOR Type-pal adható meg. Ekkor a Value a kívánt szín kell legyen.
A textúrák valamilyen NxM-es diszkrét rácsnak tekinthetők. A használt lebegőpontos textúra-koordináták a legritkábban felelnek meg pontosan pixeleknek, ez mintavételezési és minta-szűrési problémákat okoz.
Ezek állíthatók a SetSamplerState D3DSAMP_MAGFILTER, D3DSAMP_MINFILTER és D3DSAMP_MIPFILTER paraméterén keresztül. A hozzájuk tartozó lehetséges Value értékeket a D3DTEXTUREFILTERTYPE adja meg, alapértelmezett értékeik D3DTEXF_POINT, D3DTEXF_POINT illetve D3DTEXF_NONE.
Figyeljük meg a hatását a "sakktáblán", ha a D3DSAMP_MAGFILTER és D3DSAMP_MINFILTER értékét D3DTEXF_LINEAR-ra rakjuk!