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.
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).
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!
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:
ukazatel na v²slednou matici
ukazatel na EyePoint
ukazatel na LookAtPoint
ukazatel na vektor urΦujφcφ sm∞r os
Nakonec op∞t nastavφme transformaci pomocφ metody SetTransform(), nynφ s parametrem D3DTS_VIEW.
Tato poslednφ matice definovßna Φty°mi parametry:
zorn² ·hel
pom∞r stran pozorovanΘho prostoru ve tvaru kvßdru
vzdßlenost bli₧Üφ st∞ny (vÜe co je blφ₧e se nevykresluje)
vzdßlenost vzdßlenΘ st∞ny (vÜechno co je ve v∞tÜφ vzdßlenosti se nevykresluje)
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∙:
ukazatel na v²slednou matici
zorn² ·hel v radißnech
pom∞r stran
vzdßlenost bli₧Üφ st∞ny (vÜe co je blφ₧e se nevykresluje)
vzdßlenost vzdßlenΘ st∞ny (vÜechno co je ve v∞tÜφ vzdßlenosti se nevykresluje)
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.
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.
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!
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.
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.