DirectX (20.)

V minulΘ lekci jsem Φasto odkazoval na dneÜnφ dφl. Dnes si tedy vÜechny uvedenΘ body podrobn∞ji probereme. V²sledkem dneÜnφ aplikace bude p°φklad, kter² pracuje s tzv. index bufferem. Z toho plyne, ₧e v dalÜφ Φßsti Φlßnku si n∞co povφme o index bufferu.

20.1. Struktura D3DPRESENT_PARAMETERS

Minule jsme pomocφ tΘto struktury vytvo°ili objekt za°φzenφ (IDirect3DDevice8). V tΘto struktu°e jsou ulo₧eny vlastnosti budoucφho za°φzenφ. Je t°eba, aby tyto parametry byly zadßny sprßvn∞, jinak dojde p°i volßnφ metody CreateDevice() k chyb∞. Dnes si tedy povφme jakΘ parametry je t°eba zadat a jak²m zp∙sobem zjistφme, co je sprßvnΘ a co ne. Tato problematika je velice d∙le₧itß, pokud mß vaÜe aplikace pracovat na vφce systΘmech. Ka₧d² se toti₧ chovß trochu jinak a pokud natvrdo nastavφte n∞jakΘ hodnoty, nemusφ se to vÜem lφbit. P°esn∞ tuto chybu jsme ud∞lali v p°φkladu z minulΘ lekce. Nap°φklad formßt zadnφho bufferu jsme nastavili na n∞jakou konstantnφ hodnotu, kterß se zrovna lφbφ mΘmu systΘmu, ale je vφce ne₧ pravd∞podobnΘ, ₧e jinde aplikace nep∙jde spustit, proto₧e cφlovß grafickß karta dan² formßt v∙bec nepodporuje. Proto je nejprve velice d∙le₧itΘ zjistit, jak² formßt karta podporuje a podle nastavenφ aplikace nastavit bu∩ formßt, kter² 16-bitov² nebo 32-bitov².

V dneÜnφ lekci jeÜt∞ nebudeme vytvß°et konkrΘtnφ aplikaci na zjiÜt∞nφ a nastavenφ D3D prost°edφ, proto₧e musφme probrat jeÜt∞ dalÜφ d∙le₧itΘ v∞ci ne₧ zaΦneme op∞t v∞tÜφ projekt, kter² se bude sklßdat z vφce knihoven. Jednou z  Φßsti tohoto projektu bude aplikace Setup, pomocφ kterΘ zjistφme a nastavφme vlastnosti hlavnφ aplikace. Povφme si tedy jen o funkcφch, kterΘ jsou pro zjiÜ¥ovßnφ parametr∙ hardwaru pot°eba, abyste mohli p°em²Ület nad vlastnφm systΘmem nastavenφ aplikace.

1. Nejprve je t°eba zjistit kolik grafick²ch karet vßÜ systΘm obsahuje. K tomu slou₧φ metoda rozhranφ IDirect3D8 GetAdapterCount(), kterß p°φmo vracφ poΦet adaptΘru v systΘmu. V nastavenφ aplikace byste toti₧ m∞li u₧ivateli dßt na v²b∞r, pokud mß v PC vφce grafick²ch karet.

2. Dßle bychom se asi rßdi dozv∞d∞li o konkrΘtnφm adaptΘru n∞jakΘ dalÜφ informace nap°φklad jmΘno. K tomu pou₧ijte metodu GetAdapterIdentifier(). Zde u₧ jsou parametry trochu slo₧it∞jÜφ. Prvnφ parametr je tzv. ordinßlnφ Φφslo adaptΘru. Je to b∞₧n² integer, kter²m je jednoznaΦn∞ urΦen po₧adovan² adaptΘr. Toto Φφslo je v rozmezφ 0 - (GetAdapterCount()-1). Druh² parametr budeme v₧dy nastavovat na hodnotu 0. A koneΦn∞ do t°etφho parametru jsou ulo₧eny informace o po₧adovanΘm adaptΘru ve struktu°e D3DADAPTER_IDENTIFIER8. V tΘto struktu°e je n∞kolik zajφmav²ch atribut∙:

3. V dalÜφm kroku ji₧ poΦφtßme s tφm, ₧e vφme jak² adaptΘr chce u₧ivatel pou₧φt. Tak₧e jakΘkoliv dalÜφ informace se vztahujφ pouze k vybranΘmu adaptΘru. Nap°φklad jist∞ budete chtφt v∞d∞t jakΘ rozliÜenφ dan² adaptΘr m∙₧e pou₧φt. K tomu pot°ebujete metody GetAdapterModeCount() a EnumAdapterModes(). Prvnφ metodou zjistφte, kolik zvolen² adaptΘr (je urΦen ordinßlnφm Φφslem) je schopen pou₧φt rozliÜenφ. RozliÜenφm rozumφme strukturu D3DDISPLAYMODE, kterß obsahuje tyto atributy:

Z toho ovÜem plyne, ₧e za dv∞ r∙znß rozliÜenφ se pova₧ujφ i polo₧ky, kterΘ se liÜφ pouze obnovovacφ frekvencφ (na to je pot°eba si dßt pozor). Podle pot°eby vyfiltrujete po₧adovanß rozliÜenφ, kterΘ pak nabφdnete u₧ivateli k v²b∞ru.

Formßty:

JmΘno formßtu - konstanta Bit∙ na pixel Komentß°
D3DFMT_A8R8G8B8 32 ARGB formßt z alphou (kanßl pro pr∙hlednost)
D3DFMT_X8R8G8B8 32 RGB bez alphou, 8-bit∙ pro ka₧dou barvu RGB
D3DFMT_R5G6B5 16 RGB formßt
D3DFMT_X1R5G5B5 16 RGB s 5-ti bity na barvu
D3DFMT_A1R5G5B5 16 RGB formßt s 5-ti bity na barvu + 1 bit na alphu
D3DFMT_A4R4G4B4 16 4 bity pro ka₧dou barvu s 4 bitovou alphou
D3DFMT_A8R3G3B2 16 RGB formßt s 8-mi bitovou alphou
D3DFMT_X4R4G4B4 16 4 bity pro ka₧dou barvu bez alphy
D3DFMT_A2B10G10R10 32 10 bit∙ pro ka₧dou barvu + 2 bity pro alphu

 Toto samoz°ejm∞ nejsou vÜechny formßty, m∙₧ete pou₧φt i 8-mi bitovΘ, kterΘ se ovÜem pou₧φvajφ spφÜe pro textury. Formßty, kterΘ jsem zde uvedl jsou vhodnΘ pro zadnφ buffery. OvÜem v∞tÜinou to b²vß tak, ₧e grafickß karta podporuje jen jeden 32-ti bitov² a jeden 16-ti bitov² formßt. Formßty s alphou jsou velice d∙le₧itΘ u textur, pokud pracujete s pr∙hlednostφ.

Poznßmka: V kanßlu alpha je ulo₧ena informace o pr∙hlednosti pixelu. Pozd∞ji si ukß₧eme, jak tuto mo₧nost vyu₧ijeme p°i texturovßnφ slo₧it∞jÜφch objekt∙.

Nakonec tΘto Φßsti si jeÜt∞ podrobn∞ji probereme atributy struktury D3DPRESENT_PARAMETERS:

20.2. Typ vykreslovan²ch dat

Minule jsme si v rychlosti uvedli, jak²m zp∙sobem mohou b²t reprezentovßna data ve vertex bufferu. Dnes se k tomu jeÜt∞ vrßtφme a ukß₧eme si to trochu podrobn∞ji na obrßzcφch. Jednß se o prvnφ parametr vÜech funkcφ typu DrawPrimitives(). Samoz°ejm∞ abyste mohli pou₧it dan² typ, musφte s tφm poΦφtat u₧ kdy₧ vytvß°φte a plnφte zdrojov² vertex buffer. Nap°φklad t∞₧ko m∙₧ete vykreslovat troj·helnφky z bufferu, kter² neobsahuje ani t°i vrcholy.

1. Point List - seznam bod∙ - D3DPT_POINTLIST

V tomto nejjednoduÜÜφm p°φpad∞ je ve vertex bufferu ulo₧en seznam bod∙. P°edstavte si, ₧e mßte ve vertex bufferu ulo₧eny tyto body:

CUSTOMVERTEX Vertices[] =
{
    {-5.0, -5.0, 0.0},
    { 0.0,  5.0, 0.0},
    { 5.0, -5.0, 0.0},
    {10.0,  5.0, 0.0},
    {15.0, -5.0, 0.0},
    {20.0,  5.0, 0.0}
};


Pak je mohu vykreslit pomocφ p°φkazu:

d3dDevice->DrawPrimitive( D3DPT_POINTLIST, 0, 6 ); // d3dDevice je platn² ukazatel na objekt za°φzenφ

V²sledkem bude toto:

2. Line list - seznam Φar - D3DPT_LINELIST

V druhΘm p°φpad∞ jsou ve vertex bufferu ulo₧eny dvojice bod∙, kterΘ se pak p°i renderovßnφ spojujφ Φarami. Op∞t si p°edstavte stejn² seznam bod∙ jako v p°edchozφm p°φpad∞. Pokud je tedy budete vykreslovat pomocφ p°φkazu:

d3dDevice->DrawPrimitive( D3DPT_LINELIST, 0, 3 );

VÜimn∞te si, ₧e poΦet primitiv u₧ je jen 3 (3 pßry bod∙). Zobrazφ se toto:



V₧dy se spojφ dva sousednφ body.

3. Line strip - pßs z Φar - D3DPT_LINESTRIP

Dßle budeme vykreslovat op∞t Φßry, nynφ ovÜem spojφme ka₧dΘ dva sousednφ body. M∞jme op∞t stejnΘ pole, pak pomocφ p°φkazu:

d3dDevice->DrawPrimitive( D3DPT_LINESTRIP, 0, 5 );

vykreslφme toto:

 

Jako primitivum se zde poΦφtß spojnice dvou bod∙ a t∞ch je dohromady 5.

4. Triangle list - seznam troj·helnφk∙ - D3DPT_TRIANGLELIST

Nynφ se koneΦn∞ p°esuneme k opravdov²m (uzav°en²m) polygon∙m. Jako prvnφ je zde seznam troj·helnφk∙. Budeme pracovat se stejn²m vertex bufferem, tak₧e pomocφ p°φkazu:

d3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );

Vykreslφme dva odd∞lenΘ troj·helnφky:

 


Pracuje to tak, ₧e se vezmou t°i vrcholy a vytvo°φ se z nich troj·helnφk. PotΘ se vezmou dalÜφ t°i vrcholy a operace se opakuje.


5. Triangle strip - pßs troj·helnφk∙ - D3DPT_TRIANGLESTRIP

Tento pracuje podobn∞ jako p°edchozφ, jen se p°i dalÜφm vykreslovßnφ nep°esouvß na t°i novΘ vrcholy, ale p°esune se jen o jeden vrchol a vytvo°φ troj·helnφk z p°edchozφch dvou:


d3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 4);


Vytvo°φme toto:



Jsou to 4 troj·helnφky, tak₧e poΦet primitiv je 4.

6. Triangle fan - v∞jφ° - D3DPT_TRIANGLEFAN

Nakonec tu mßme poslednφ zp∙sob, kde se troj·helnφky vytvß°ejφ v∙Φi prvnφmu bodu ve vertex bufferu. Zde nadefinujeme jinou posloupnost bod∙:

CUSTOMVERTEX Vertices[] = {
       { 0.0, 0.0, 0.0},
       {-5.0, 5.0, 0.0},
       {-3.0, 7.0, 0.0},
       { 0.0, 10.0, 0.0},
       { 3.0, 7.0, 0.0},
       { 5.0, 5.0, 0.0},
};


Pomocφ tohoto p°φkazu:

d3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 4);


Vykreslφme toto:


 
 

Troj·helnφk se v₧dy vytvß°φ z prvnφho bodu posloupnosti a dvou nßsledujφcφch bod∙. DalÜφ troj·helnφk se vytvo°φ z prvnφho, t°etφho a ΦtvrtΘho vrcholu atd.

20.3. Index buffer

Tento buffer slou₧φ k uchovßnφ index∙ vertex∙ ve vertex bufferu. Zkrßtka je v n∞m ulo₧enΘ po°adφ vertex∙, kterΘ se pak vykreslujφ pomocφ metody DrawIndexedPrimitives(). Minule jsem zmφnil p°φpad Φtverce jako₧to typickΘ pou₧itφ index bufferu. V praxi se ale index buffer pou₧φvß prakticky poka₧dΘ. V tΘto Φßsti vytvo°φme krßtk² p°φklad. Navß₧eme na p°φklad z minule.

Princip vytvo°enφ a napln∞nφ index bufferu je stejn² jako v p°φpad∞ vertex bufferu, jen neinicializujeme vertexy, ale indexy, kterΘ jsou typu WORD.

Vytvo°me prom∞nnou typu:

IDirect3DIndexBuffer8* g_lpD3DIB = NULL;

Dßle trochu upravφme pole vertex∙, aby z n∞j Üel nakreslit Φtverec, kter² mß 4 vrcholy:

TLVERTEX arVertices[] = {
{200.0f, 200.0f, 0.5f, 1.0f, 0xFFFF0000},
{600.0f, 200.0f, 0.5f, 1.0f, 0xFF0000FF},
{200.0f, 600.0f, 0.5f, 1.0f, 0xFFFFFF00}
{600.0f, 600.0f, 0.5f, 1.0f, 0xFF00FF00}};

A te∩ stejn²m zp∙sobem vytvo°φme pole index∙:

WORD arIndices[] = { 0, 1, 2, 1, 3, 2};

Nynφ vytvo°φme samotn² index buffer pro 6 index∙ a naplnφme ho daty z v²Üe uvedenΘho pole:

g_lpD3DDevice->CreateIndexBuffer(6 * sizeof(WORD), D3DUSAGE_WRITEONLY , D3DFMT_INDEX16 , D3DPOOL_DEFAULT, &g_lpD3DIB);

WORD *pdwIndex;
    if(SUCCEEDED(g_lpD3DIB->Lock(0, 0, (BYTE**) &pdwIndex, 0))) {

    for(int i = 0; i < 6; i++) {
// zde uz pouzijeme cyklus
        pdwIndex[i] = arIndices[i];
    }
    g_lpD3DVB->Unlock();
}

ProΦ je index∙ prßv∞ 6? Mßme dva troj·helnφky a ka₧d² mß 3 vrcholy. Program vezme prvnφ t°i indexy, podφvß se do vertex bufferu a ud∞lß troj·helnφk z vrcholu 0, 1 a 2. PotΘ vezme dalÜφ 3 indexy a ud∞lß totΘ₧ z vrchol∙ 1, 3 a 2. Po°adφ index∙ musφ b²t po sm∞ru hodinov²ch ruΦiΦek, jinak by byl troj·helnφk obrßcen² a nebyl by vid∞t. Dßle musφme nastavit vstupnφ index buffer pomocφ metody SetIndices():

g_lpD3DDevice->SetIndices(g_lpD3DIB, 0);

Prvnφ parametr je ukazatel na index buffer a druh² je tzv. bßzov² index. Toto Φφslo je automaticky p°iΦteno ke ka₧dΘmu indexu.

Nakonec tedy vykreslφme Φtverec pomocφ metody DrawIndexedPrimitive():

g_lpD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2);

Tato metoda ji₧ mß vφce parametr∙:

Zbytek programu z∙stßvß stejn². Po spuÜt∞nφ se vykreslφ barevn² Φtverec. Program si m∙₧ete stßhnout v sekci Downloads.
 

20.4. Zßv∞r

V dneÜnφ lekci jsme tedy probrali vÜe, co jsem minule slφbil. Na p°φÜt∞ si nechßme prvnφ v∞tÜφ projekt, kde postupn∞ zaΦneme slepovat vφce knihoven dohromady.

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

Ji°φ Formßnek