DirectX (21.)

V dneÜnφ lekci ji₧ vytvo°φme 3d prostor, do kterΘho vykreslφme rotujφcφ kostku. Povφme si n∞co o transformacφch a o praktickΘm vyu₧itφ matic. V dalÜφ Φßsti lekce si povφme n∞co mßlo o texturovßnφ a v p°φkladu na naÜφ kostku naneseme texturu.

21.1. 3D prostor

Dote∩ jsme pou₧φvali tzv. transformovanΘ vrcholy. Tyto vrcholy v∙bec neprochßzφ transformaΦnφ pipeline Direct3D. Nap°φklad jsme m∞li vertex o sou°adnicφch (200.0f, 200.0f, 0.5f). Tyto hodnoty jsou p°φmo pozice na monitoru! Z-tovß sou°adnice je zde pou₧ita v rozmezφ od 0.0 - 1.0, kde 1.0 je bod nejvzdßlen∞jÜφ od pozorovatele (nap°φklad si p°edstavte okna, kterΘ se ΦßsteΦn∞ p°ekr²vajφ, vrchnφ okno mß z = 0.0, zatφmco spodnφ 1.0).

V dneÜnφ lekci ovÜem budeme pracovat v²hradn∞ s netransformovan²mi vrcholy! Tyto vrcholy majφ sou°adnice v tzv. modelovΘm prostoru, kde jednotlivΘ body jsou vzta₧eny k pomyslnΘmu st°edu objektu (nap°φklad krychle).

M∞jme nap°φklad kostku, kterß mß 8 vrchol∙:

VERTEX arCube[] = {
    { 2.0f,  2.0f,  2.0f, 0xFF00FF00},
    { 2.0f, -2.0f,  2.0f, 0xFFFF00FF},
    {-2.0f, -2.0f,  2.0f, 0xFFFF0000},
    {-2.0f,  2.0f,  2.0f, 0xFFFFFF00},
    { 2.0f,  2.0f, -2.0f, 0xFF00FFFF},
    { 2.0f, -2.0f, -2.0f, 0xFF0000FF},
    {-2.0f, -2.0f, -2.0f, 0xFFFF0F0F},
    {-2.0f,  2.0f, -2.0f, 0xFFFF0FFF}
};

Tato kostka je umφst∞na ve st°edu sou°adnΘho systΘmu. Nynφ je pot°eba tyto body transformovat tak, aby Üla kostka zobrazit na monitor.

Mßme t°i zßkladnφ transformaΦnφ matice, kter²mi je transformovßn ka₧d² vrchol objektu:
1) Sv∞tovß matice - tato matice transformuje vrcholy z modelovΘho prostoru do sv∞tovΘho! V modelovΘm prostoru mß ka₧d² objekt sv∙j st°ed sou°adnΘho systΘmu. Transformacφ do sv∞tov²ch sou°adnic zφskajφ vÜechny objekty spoleΦn² poΦßtek.
2) Matice pohledu - pomocφ tΘto matice nastavφme pohled kamery v prostoru (nynφ u₧ se pohybujeme ve sv∞tovΘm prostoru). Tento prostor se vytvß°φ pomocφ dvou bod∙: tzv. eye point (bod odkud pozorujeme, oko) a look at point (bod, kter² pozorujeme, objekt).
3) ProjekΦnφ matice - pomocφ tΘto matice vlastn∞ nastavφme ΦoΦku kamery, kterou jsme definovali pomocφ matice pohledu. Pomocφ tΘto matice nastavφme perspektivu (vzdßlen∞jÜφ objekty jsou menÜφ ne₧ objekty bli₧Üφ), zorn² ·hel a pom∞r stran pozorovanΘho prostoru (to je obecn∞ n∞jak² Φty°st∞n).

21.1.1. Sv∞tovß matice

V naÜem p°φkladu budeme pomocφ tΘto matice otßΦet krychlφ kolem vÜech os souΦasn∞. Ukß₧eme si, jak slo₧φme vφce operacφ pomocφ nßsobenφ matic. Pomocφ tΘto matice m∙₧ete aplikovat zßkladnφ transformace na objekty. M∙₧ete tuto matici nastavit pro ka₧d² objekt zvlßÜ¥.

Nap°φklad pokud nastavφte tuto matici jednotkovou, nedojde k ₧ßdnΘ zm∞n∞ vrchol∙ objektu, tak₧e pokud mßme naÜi kostku umφst∞nou ve st°edu modelovΘho prostoru, bude i ve st°edu  sv∞tovΘho prostoru.

Nynφ si ukß₧eme jak nastavit sv∞tovou matici:

D3DXMATRIX matWorldOld, matWorldNewX, matWorldNewY, matWorldNewZ;

g_lpD3DDevice->GetTransform(D3DTS_WORLD, &matWorldOld);

D3DXMatrixRotationX(&matWorldNewX, -D3DX_PI/1000);
D3DXMatrixRotationY(&matWorldNewY, -D3DX_PI/2000);
D3DXMatrixRotationZ(&matWorldNewZ, D3DX_PI/500);

D3DXMatrixMultiply(&matWorldNewX, &matWorldNewX, &matWorldNewY);
D3DXMatrixMultiply(&matWorldNewX, &matWorldNewX, &matWorldNewZ);
D3DXMatrixMultiply(&matWorldNewX, &matWorldNewX, &matWorldOld);

g_lpD3DDevice->SetTransform(D3DTS_WORLD, &matWorldNewX);

Toto je kousek k≤du naÜeho p°φkladu. JednotlivΘ kroky nynφ podrobn∞ji popφÜu. Nejprve zφskßme p°edchozφ sv∞tovou matici. Tento krok bychom mohli vynechat, ale museli bychom naÜφ matici definovat jako globßlnφ objekt. PotΘ vytvo°φme t°i matice, kterΘ provßd∞jφ rotaci kolem vÜech t°φ os pomocφ funkce D3DXMatrixRotationX/Y/Z(). Tato funkce mß dva parametry. Prvnφ je ukazatel na v²slednou matici a druh² je ·hel otoΦenφ v radißnech! Zde pou₧φvßm definovanou konstantu D3DX_PI (3,14). Dßle musφme vÜechny matice vynßsobit (a tφm spojit efekty vÜech matic do jednΘ) pomocφ funkce D3DXMatrixMultiply(). Tato funkce mß t°i parametry. Prvnφ je ukazatel na v²slednou matici, druh² je ukazatel na prvnφ zdrojovou matici a t°etφ ukazuje na druhou zdrojovou matici. Meziv²sledek v₧dy ulo₧φme do matice matWorldNewX. Nakonec zp∞tn∞ nastavφme transformaci pomocφ metody SetTransform(), kde pomocφ prvnφho parametru nastavφme sv∞tovou matici a ve druhΘm je ukazatel na naÜφ matici.

Tyto kroky budeme provßd∞t v ka₧dΘm cyklu aplikace!

21.1.2. Matice pohledu

Tuto matici nastavφme pouze po inicializaci Direct3D, proto₧e p°i rotaci kostky se budeme dφvat na scΘnu stßle ze stejnΘho mφsta. Jak bylo uvedeno v²Üe, tuto matici definujeme pomocφ dvou bod∙:

// Create view matrix
D3DXVECTOR3 vUpDir, vEyePt, vLookAtPoint;
//
vUpDir = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
vLookAtPoint = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
vEyePt = D3DXVECTOR3(10.0f, 10.0f, 0.0f);
//
D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookAtPoint, &vUpDir);
g_lpD3DDevice->SetTransform(D3DTS_VIEW, &matView);

LookAtPoint
mßme ve st°edu sou°adnicovΘho systΘmu, tak₧e se dφvßme p°φmo do st°edu vesmφru. Dφvßme se v rovin∞ xy pod ·hlem 45 stup≥∙:

Dßle je t°eba definovat sm∞r os pomocφ vektoru vUpDir. I kdy₧ se Φasto definuje jako svislß osa osa Y, p°ijde mi logiΦt∞jÜφ takto definovat osu Z. Nakonec pomocφ funkce D3DXMatrixLookAtLH() vytvo°φme matici pohledu. Funkce mß 4 parametry:

Nakonec op∞t nastavφme transformaci pomocφ metody  SetTransform(), nynφ s parametrem D3DTS_VIEW.

21.1.3. ProjekΦnφ matice

Tato poslednφ matice definovßna Φty°mi parametry:

V naÜem p°φkladu vytvo°φme projekΦnφ matici takto:

D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 4.0f/3.0f, 1.0f, 100.0f);
g_lpD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj);

Pomocφ D3DXMatrixPerspectiveFovLH() vytvo°φme projekΦnφ matici. Tato funkce mß 5 parametr∙:

Nakonec op∞t nastavφme transformaΦnφ matici pomocφ metody SetTransform(), nynφ s parametrem D3DTS_PROJECTION.

Zde vßm doporuΦuji, abyste si vyzkouÜeli jak² vliv majφ jednotlivΘ parametry na "vzhled" scΘny. Nap°φklad zjistφte, ₧e pokud zadßte jin² pom∞r stran, stane se z kostky kvßdr, proto₧e rozliÜenφ je v pom∞ru 4/3.

21.1.4. Krychle

Nejprve je d∙le₧itΘ si uv∞domit, ₧e ji₧ pracujeme s transformovan²mi vrcholy (tyto vrcholy ji₧ nemajφ slo₧ku rhw):

struct VERTEX {
    float x, y, z;
    DWORD dwColor;
};

A dßle je t°eba nastavit typ shaderu:

#define VERTEXFORMAT D3DFVF_XYZ|D3DFVF_DIFFUSE

Tak jako ka₧dß krychle i naÜe bude mφt 8 vrchol∙:

VERTEX arCube[] = {
    { 2.0f,  2.0f,  2.0f, 0xFF00FF00},
    { 2.0f, -2.0f,  2.0f, 0xFFFF00FF},
    {-2.0f, -2.0f,  2.0f, 0xFFFF0000},
    {-2.0f,  2.0f,  2.0f, 0xFFFFFF00},
    { 2.0f,  2.0f, -2.0f, 0xFF00FFFF},
    { 2.0f, -2.0f, -2.0f, 0xFF0000FF},
    {-2.0f, -2.0f, -2.0f, 0xFFFF0F0F},
    {-2.0f,  2.0f, -2.0f, 0xFFFF0FFF}
};

Krychle je umφst∞na uprost°ed a dΘlka hrany je rovna 4. Takto vypadajφ indexy naÜφ krychle

WORD arCubeIndices[] = {
    // top
    0,3,1, 1,3,2,
    // bottom
    4,5,7, 5,6,7,
    // right
    0,4,7, 0,7,3,
    // left
    1,6,5, 1,2,6,
    // back
    0,1,5, 0,5,4,
   
// front
    3,6,2, 3,7,6
};

P°i definovßnφ index∙ je t°eba dßt pozor na to, aby jednotlivΘ troj·helnφky byly definovßny po sm∞ru hodinov²ch ruΦiΦek, aby normßlovΘ vektory byly obrßceny sm∞rem k pozorovatelovi, jinak by troj·helnφk nebyl vid∞t.

Osv∞tlenφ

Proto₧e nedefinujeme normßlovΘ vektory jednotliv²ch vertex∙, nemß systΘm D3D jak spoΦφtat osv∞tlenφ. Tudφ₧ je t°eba, abychom sv∞tlo zcela vypnuli pomocφ metody SetRenderState(). Tato metoda je velmi d∙le₧itß, proto₧e s jejφ pomocφ nastavujeme v∞tÜinu parametr∙ chovßnφ aplikace. Podφvßte-li se do dokumentace zjistφte, ₧e mß spoustu mo₧n²ch parametr∙. V naÜem p°φpad∞ chceme pouze vypnout osv∞tlenφ:

g_lpD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

Toto je  velmi d∙le₧itΘ, proto₧e jinak bychom krychli vid∞li zcela Φernou (to je zp∙sobeno tφm, ₧e nejsou definovßny normßlovΘ vektory). Kdybychom je definovali, museli bychom navφc vytvo°it a nastavit n∞jakΘ sv∞tlo.

21.2. Textury

21.2.1. TexturovΘ sou°adnice

V dalÜφ Φßsti lekce si povφme n∞co o texturßch a texturovßnφ. V knihovn∞ D3DX je spousta funkcφ jak vytvo°it texturu ze souboru Φi pam∞ti, tak₧e prßce s texturami je celkem jednoduchß. O trochu slo₧it∞jÜφ je systΘm texturovßnφ. To se provßdφ pomocφ tzv. texturov²ch sou°adnic. Tyto sou°adnice jsou slo₧kami ka₧dΘho vertexu u objektu, kter² chceme otexturovat:

struct VERTEX {
    float x, y, z;
    float tu, tv;
};

#define VERTEXFORMAT D3DFVF_XYZ|D3DFVF_TEX1
 

Slo₧ky tu a tv jsou texturovΘ sou°adnice. Nynφ si vysv∞tlφme, jak se s t∞mito sou°adnicemi pracuje:

Tak₧e pomocφ t∞chto sou°adnic urΦφme pozice odkud se Φte zdrojovß textura. VÜe je vid∞t na obrßzku. V prvnφm p°φpad∞ naneseme celou texturu, proto₧e sou°adnice majφ maximßlnφ hodnotu 1.0. Ve druhΘm p°φpad∞ nanßÜφme pouze jednu Φtvrtinu, proto₧e maximßlnφ hodnota je pouze 0.5. Pokud byste zadali hodnotu v∞tÜφ jak 1.0, dosßhli byste opakovßnφ textury (pokud nap°φklad zadßte 2.0, textura se zopakuje 2x).

Nynφ se vrßtφme k naÜφ krychli. Kdy₧ se nad problΘmem trochu zamyslφte, zjistφte, ₧e nynφ u₧ to nebude tak jednoduchΘ jako v p°φpad∞ prvnφ krychle (pro lepÜφ p°edstavivost je dobrΘ si kostku nakreslit na papφr). Potφ₧ je v tom, ₧e ka₧d² vertex mß jedny texturovΘ sou°adnice, jen₧e abychom mohli nanΘst texturu na kostku je nutnΘ definovat pro ka₧dou stranu vlastnφ texturovΘ sou°adnice. Z toho plyne, ₧e nynφ si ji₧ nevystaΦφme s osmi vertexy! Budeme jich definovat rovnou 24 (pro ka₧dou stranu 4, tak₧e 6 x 4)! Zde se bohu₧el ztrßcφ v²znam indexace.

Vertexy definujeme nßsledovn∞:

VERTEX arCube[] = {
   
// top
   
{ 2.0f,  2.0f, 2.0f, 0.0f, 0.0f},
    { 2.0f, -2.0f, 2.0f, 0.0f, 1.0f},
    {-2.0f,  2.0f, 2.0f, 1.0f, 0.0f},
    {-2.0f, -2.0f, 2.0f, 1.0f, 1.0f},

   
// bottom
   
{ 2.0f,  2.0f, -2.0f, 0.0f, 0.0f},
    { 2.0f, -2.0f, -2.0f, 0.0f, 1.0f},
    {-2.0f,  2.0f, -2.0f, 1.0f, 0.0f},
    {-2.0f, -2.0f, -2.0f, 1.0f, 1.0f},

   
// left
   
{-2.0f, -2.0f,  2.0f, 0.0f, 0.0f},
    { 2.0f, -2.0f,  2.0f, 0.0f, 1.0f},
    {-2.0f, -2.0f, -2.0f, 1.0f, 0.0f},
    { 2.0f, -2.0f, -2.0f, 1.0f, 1.0f},

   
// right
   
{-2.0f, 2.0f,  2.0f, 0.0f, 0.0f},
    { 2.0f, 2.0f,  2.0f, 0.0f, 1.0f},
    {-2.0f, 2.0f, -2.0f, 1.0f, 0.0f},
    { 2.0f, 2.0f, -2.0f, 1.0f, 1.0f},

   
// front
   
{-2.0f, -2.0f,  2.0f, 0.0f, 0.0f},
    {-2.0f,  2.0f,  2.0f, 0.0f, 1.0f},
    {-2.0f, -2.0f, -2.0f, 1.0f, 0.0f},
    {-2.0f,  2.0f, -2.0f, 1.0f, 1.0f},

   
// back
   
{2.0f, -2.0f,  2.0f, 0.0f, 0.0f},
    {2.0f,  2.0f,  2.0f, 0.0f, 1.0f},
    {2.0f, -2.0f, -2.0f, 1.0f, 0.0f},
    {2.0f,  2.0f, -2.0f, 1.0f, 1.0f},
};

Nynφ mßme pro ka₧dou stranu nadefinovanΘ 4 vrcholy. VÜimn∞te si, jak²m zp∙sobem nastavujeme texturovΘ sou°adnice. Proto₧e stranu definujeme pomocφ 4 vrchol∙, je t°eba ka₧dou stranu indexovat:

WORD arCubeIndices[] = {
   
// top
   
1,0,2, 1,2,3,
   
// bottom
   
4,7,6, 4,5,7,
   
// left
   
9,8,10, 9,10,11,
   
// right
   
13,14,12, 13,15,14,
   
// front
   
17,18,16, 17,19,18,
   
// back
   
21,22,23, 21,20,22
};

Nynφ je samoz°ejm∞ t°eba zm∞nit velikost vertex bufferu na 24. Kdy₧ se te∩ kostku pokusφte vykreslit, uvidφte pouze bφl² obrys, proto₧e jste nenastavili ₧ßdnou texturu!

21.2.2. Nahrßvßnφ textury nejen ze souboru

Jak bylo zmφn∞no d°φve, knihovna D3DX dob°e podporuje sprßvu textur. Mßme zde hned n∞kolik funkcφ:

VÜechny tyto funkce pracujφ s objektem typu IDirect3DTexture8, ale Φast∞ji se setkßte s ukazatelem LPDIRECT3DTEXTURE8. KonkrΘtnφ vyu₧itφ t∞chto funkcφ si postupn∞ ukß₧eme v p°φÜtφch lekcφch. Dnes si vystaΦφme s prvnφ jmenovanou D3DXCreateTextureFromFile(). Nejprve tedy definujeme objekt textury:

LPDIRECT3DTEXTURE8 g_lpTexture = NULL;

V dalÜφm kroku vytvo°φme texturu z bitmapy:

// load texture from the file
D3DXCreateTextureFromFile(g_lpD3DDevice, "texture.bmp", &g_lpTexture);

Aby se danß textura aplikovala, musφme jφ nastavit pomocφ metody SetTexture().

// set texture
g_lpD3DDevice->SetTexture(0, g_lpTexture);

Toto volßnφ provedeme t∞sn∞ p°ed vykreslenφm krychle. Pokud bychom cht∞li mφt na ka₧dΘ stran∞ jinou texturu, museli bychom strany vykreslovat postupn∞ (6 volßnφ metody DrawIndexedPrimitive() a mezi ka₧d²m volßnφm nastavovat jinou texturu). VÜimn∞te si, ₧e metoda mß dva parametry. Prvnφ parametr urΦuje tzv. texture stage. Tento parametr je vyu₧φvßn u mφchßnφ textur (texture blending), ale o tom si povφme n∞kdy p°φÜt∞. Druh² parametr je ukazatel na naÜφ texturu.

Tak toto byl lehk² ·vod do texturovßnφ objekt∙ v Direct3D. Texturovßnφ je ovÜem obsßhlß kapitola, tak₧e dalÜφ vlastnosti a nastavenφ si ukß₧eme v dalÜφch lekcφch.
 

21.3. Zßv∞r

Dnes jsme se koneΦn∞ pono°ili do pravΘho 3D sv∞ta Direct3D. Snad se vßm dneÜnφ lekce lφbila.

Co budeme probφrat p°φÜt∞? Snad ji₧ koneΦn∞ zaΦneme budovat nßÜ mal² 3D engine. Vytvo°φme pßr knihoven podobn∞ jako tomu bylo u DirectDraw.

T∞Üφm se p°φÜt∞ nashledanou.

Ji°φ Formßnek