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:

Textúrázva


Közösfeladatok

* Töltsünk be még két textúrát, és a különböző oldalakon ezek jelenjenek meg!

(Ehhez képek: 1., 2.)

* 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!