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.
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∙:
Description - i tato informace slou₧φ ke zobrazenφ a platφ o nφ stejnΘ pravidlo jako u atributu Driver. Tento °et∞zec m∙₧e nap°φklad b²t: "RADEON 8500 SERIES".
VendorID, DeviceID, SubSysID, Revision - Tyto hodnoty oznaΦujφ konkrΘtnφ chipset grafickΘ karty. Pokud v²robce nenφ znßm², obsahujφ hodnotu 0.
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:
Width, Height - poΦet pixel∙ v horizontßlnφm a vertikßlnφm sm∞ru (640x480....)
RefreshRate - Obnovovacφ frekvence.
Format - Formßt re₧imu. S tφm je to trochu slo₧it∞jÜφ, proto₧e ka₧d² systΘm m∙₧e pou₧φvat jinΘ hodnoty, kterΘ ovÜem ve v²sledku reprezentujφ bu∩ 16-ti nebo 32-bitov² re₧im.
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:
D3DSWAPEFFECT_DISCARD | Tento zp∙sob budeme asi nejΦast∞ji pou₧φvat. OvladaΦ vybere nejefektivn∞jÜφ zp∙sob prohazovßnφ, navφc m∙₧ete pou₧φt antialising a vφce zadnφch buffer∙. |
D3DSWAPEFFECT_FLIP | Tento zp∙sob funguje stejn∞ jako v DirectDraw. P°i ka₧dΘm volßnφ metody Present() se zadnφ buffer zobrazφ a b²val² p°ednφ se ocitne v pozici zadnφho. M∙₧ete pou₧φt i vφce zadnφch buffer∙. |
D3DSWAPEFFECT_COPY | Zde se kopφruje obsah zadnφho bufferu do p°ednφho nebo p°φmo do okna ve window re₧imu. Zde je d∙le₧itΘ, ₧e nem∙₧ete pou₧φt vφce jak jeden zadnφ buffer a ₧e ke zkopφrovßnφ dochßzφ okam₧it∞, tudφ₧ zde nefunguje ₧ßdnß vertikßlnφ synchronizace s obnovovacφ frekvencφ monitoru. |
D3DSWAPEFFECT_COPY_VSYNC | Poslednφ zp∙sob je stejn² jako D3DSWAPEFFECT_COPY, ale je vhodnΘ ho pou₧φt pro window aplikace, proto₧e kopφrovßnφ zadnφho bufferu je synchronizovßno s obnovovacφ frekvencφ monitoru. |
D3DPRESENT_INTERVAL_DEFAULT | Pro oknovΘ aplikace musφte pou₧φt tuto hodnotu. Ve fullscreen je to stejnΘ jako kdybyste nastavili D3DPRESENT_INTERVAL_ONE. |
D3DPRESENT_INTERVAL_IMMEDIATE | K prohazovßnφ dochßzφ jak nejrychleji to jde tj. neΦekß se na nßvrat paprsku monitoru. Pokud nap°φklad chcete testovat cφlov² harware, je vhodnΘ pou₧φt tuto hodnotu a nechat grafickou kartu "trhat" monitor:) |
D3DPRESENT_INTERVAL_ONE | Prohazovßnφ je synchronizovßno s obnovovacφ frekvencφ monitoru. |
D3DPRESENT_INTERVAL_TWO | Prohazovßnφ se provßdφ ka₧d² druh² cyklus. |
D3DPRESENT_INTERVAL_THREE | Prohazovßnφ se provßdφ ka₧d² t°etφ cyklus. |
D3DPRESENT_INTERVAL_FOUR | Prohazovßnφ se provßdφ ka₧d² Φtvrt² cyklus. |
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₧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
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.
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.