C/C++ & Visual C++Kurz DirectX (32.) |
|||||||||||||||||||||||||||||||||||||
Ve 32. lekci programovßnφ v Direct3D postoupφme dßl a zbavφme se oÜkliv²ch Φern²ch okraj∙ kolem terΘnu. V dalÜφ Φßsti Φlßnku se podφvßme jak v Direct3D pracuje mlha. Nakonec jeÜt∞ upravφme t°φdu XMesh, aby se automaticky poΦφtaly normßlovΘ vektory. 32.1. Obloha a zakonΦenφ terΘnuObjekt, kter² ohraniΦuje nßÜ sv∞t naz²vßme skybox, co₧ je doslova krychle, kter² mß na vnit°nφ stran∞ texturu okolφ (v naÜem p°φpad∞ to bude nebe, ale m∙₧e to byt t°eba horizont apod.). Cel² nßÜ sv∞t je uvnit° tΘto velkΘ krychle, tak₧e se zdß, ₧e sv∞t nemß ₧ßdnΘ viditelnΘ hranice. Proto₧e jsem nevymyslel lepÜφ ΦeskΘ slovo, budu pou₧φvat anglick² v²raz skybox. NßÜ skybox vlastn∞ nebude ani box, proto₧e je to p°i omezenφ kamery zcela zbyteΦnΘ. StaΦφ nßm jen vlastn∞ okraje kolem terΘnu (Φili svislΘ st∞ny krychle, kterΘ vlastn∞ nebudou svislΘ, viz. dßle). Okraje rozÜφ°φme, abychom zabrßnili vypadnutφ kamery z prostoru (kamera m∙₧e ve skuteΦnosti zcela opustit plochu terΘnu!) - Φili ud∞lßme takov² "trycht²°". NicmΘn∞ budeme pot°ebovat 8 vrchol∙, stejn∞ jako kdybychom pou₧ili krychli. Za to ale nebudeme definovat seznam troj·helnφk∙ a vystaΦφme si s pßsem (triangle strip), kter² se renderuje rychleji, aΦkoli zde se to samoz°ejm∞ neprojevφ. Skybox bude reprezentovat objekt ID3Object: I3DObject *m_pSkyBox; Tomuto objektu musφme vytvo°it vertex i index buffer: // horni rozsireni oblohy dif = (i & 0x2) ? 200.0f : -200.0f; m_pSkyBox->GetIB()->GetBuffer()->Lock(0,0, (BYTE**) &pIndices, 0); K≤d vypadß slo₧it∞ a nep°ehledn∞ a je lepÜφ, kdy₧ si objekt nakreslφte na papφr. OΦφslujte si hrany podle tabulky:
èedivΘ °ßdky oznaΦujφ "hornφ" vrcholy, bφlΘ dolnφ. VÜimn∞te si, ₧e tyto °ßdky majφ v k≤du na prvnφm bitu jedniΦku. Tφmto zp∙sobem p°i°azujeme vlastnosti vrchol∙m. Nejprve se tedy vytvo°φ objekt I3DObject, v dalÜφm kroku se naplnφ vertex a index buffer. Index∙ je t°eba jen 10, proto₧e chceme pou₧φt triangle strip (na prvnφ troj·helnφk pot°ebujeme 3 vrcholy, na dalÜφ jen jeden, 3 + 7 * 1 = 10). Inicializaci VB provßdφme ve zdvojenΘ smyΦce for, a v ka₧dΘm cyklu vytvo°φme dva vrcholy, kterΘ jsou pod sebou (Φili majφ stejnΘ x a y sou°adnice, ale z se liÜφ) - je to v₧dy dvojice °ßdk∙ v tabulce, bφl² a Üed². Dolnφ vrchol je jednoduch², znßme velikost terΘnu a tento vrchol "pasuje" na roh terΘnu. HorÜφ je to s texturov²mi sou°adnicemi (v naÜem p°φkladu by nebyly pot°eba, proto₧e texturu nepou₧φvßm). VÜimn∞te si, ₧e u-sou°adnice je kopiφ prvnφho bitu k≤du vrcholu. Tento °ßdek kopii provede: pVertices[i].tu1 = (i & 0x1) ? 1.0f : 0.0f; U sou°adnice v je to slo₧it∞jÜφ. Kdy₧ se ovÜem podφvßme do tabulky, op∞t je vid∞t, ₧e sou°adnice v je 1, pokud se 2. a 3. bit k≤du liÜφ. Pokud jsou tyto bity stejnΘ (0 nebo 1), je sou°adnice nulovß. Nßsledujφcφ °ßdek provede popsanou operaci: pVertices[i].tv1 = ((i & 0x6) == 0x6 || (~i & 0x6) == 0x6) ? 0.0f : 1.0f; Tilda p°ed prom∞nnou i znamenß negaci. Prom∞nnß dif, urΦuje rozÜφ°enφ objektu. ProblΘm je, ₧e u ka₧dΘho vrcholu mß tato prom∞nnß jinΘ znamΘnko. Zde se problΘm rozd∞lφ na x a y sou°adnice (pro ka₧dou sou°adnici d∞lßme samostatn² test). Pokud je x-sou°adnice 0, je t°eba parametr dif odeΦφst, v opaΦnΘm p°φpad∞ p°iΦφst. A x-sou°adnice je jedniΦkovß, prßv∞ kdy₧ je jedniΦkov² 2. bit k≤du: dif = (i & 0x2) ? 200.0f : -200.0f; Pro sou°adnici y platφ totΘ₧, jen se dφvßme na 3. bit: dif = (i & 0x4) ? 200.0f : -200.0f; TexturovΘ sou°adnice druhΘho vrcholu poΦφtßme ·pln∞ stejn∞. Index buffer je tak mal², ₧e jsem ho naplnil v²Φtem hodnot z pole. Kdy₧ si objekt nakreslφte, bude vßm jasnΘ, proΦ jsou vrcholy spojeny zrovna takto. Je toti₧ d∙le₧itΘ, aby normßlovΘ vektory ploch sm∞°ovaly dovnit° - kamera je uvnit° objektu. JeÜt∞ si krßtce povφme n∞co o zakonΦenφ terΘnu. ZakonΦenφ znamenß, ₧e mezi hranou skyboxu a hranou terΘnu nebude dφra. Tento problΘm se dß °eÜit tak, ₧e p°idßte dalÜφ troj·helnφky mezi zmφn∞nΘ hrany, co₧ je ale pom∞rn∞ nßroΦnΘ (kv∙li optimalizaci byste museli tyto troj·helnφky p°i°adit okrajov²m list∙m stromu). Jß jsem to vy°eÜil ·pln∞ jednoduÜe, staΦφ vÜem krajnφm vertex∙m p°i°adit z-sou°adnici 0.0: if(x == 0 || x == m_iTerrainVerticesX-1) Tento k≤d provedeme ji₧ p°i pln∞nφ pole m_arTerrain v metod∞ GenerateTerrainFromFile(). St∞na na hran∞ terΘnu sice nebude zcela svislß, ale to zas tolik nevadφ (je to tak zanedbatelnΘ, ₧e to ani nenφ vid∞t). 32.2. Mlha v Direct3DV Direct3D existujφ dva typy mlhy - pixelovß a vertexovß. Hlavnφ rozdφl mezi nimi je, ₧e vertexovß mlha je poΦφtßna b∞hem fßze transformacφ a osv∞tlovßnφ pro ka₧d² vertex, naproti tomu pixelovou mlhu poΦφtß ovladaΦ za°φzenφ pro ka₧d² pixel. V dokumentaci MSDN mßte podrobn∞ popsßno, jak²m zp∙sobem se mlha poΦφtß. Pro naÜe ·Φely bude staΦit, kdy₧ vßm ukß₧i, jak se prakticky mlha pou₧φvß. V naÜem p°φkladu jsem pou₧il pixelovou mlhu. Co musφme ud∞lat proto, abychom mlhu spustili? Je to velice snadnΘ. 1) Nastavφme pomocφ SetRenderState() parametr
D3DRS_FOGENABLE na hodnotu TRUE. Tφm mlhu zapneme. D3DFOG_EXP - exponencißlnφ mlha prvnφho typu. "Hustota" mlhy se zvyÜuje nep°φmo ·m∞rn∞ vzdßlenosti od kamery. U exponencißlnφ mlhy definujeme pouze jeden reßln² parametr a tφm je hustota mlhy. VÜe si samoz°ejm∞ ukß₧eme na jednoduchΘm p°φkladu: float fDensity = 0.005f; Tφmto nastavφme exponencißlnφ lehkou mlhu ₧lutΘ barvy, nakonec mlhu zapneme. Pokud bychom pou₧ili lineßrnφ mlhu, je t°eba definovat dva parametry: float fFogStart = 1.0f; V p°φkladu z lekce pou₧φvßme prvnφ typ, ale dobrΘ je vytvo°it metodu t°φdy XDisplay pro nastavenφ vÜech typ∙ mlhy, vΦetn∞ vertexovΘ. O tom si ovÜem povφme p°φÜt∞. 32.3. Modifikace t°φdy XMeshKdy₧ exportujete model nap°φklad z 3D Studia Max, m∙₧ete k modelu p°idat i normßlovΘ vektory, kterΘ jsou pot°eba pro v²poΦet osv∞tlenφ. V tomto p°φpad∞ nenφ co °eÜit, proto₧e Direct3D tyto vektory automaticky naΦte spolu s ostatnφmi atributy vrchol∙. Nynφ si ale p°edstavte, ₧e model normßly neobsahuje. Mesh bez normßl se zobrazφ bu∩ Φern² anebo bφl² pokud vypnete osv∞tlenφ. Abychom tento problΘm vy°eÜili, pou₧ijeme funkci knihovny D3DX D3DXComputeNormals(). To vypadß nßramn∞ jednoduÜe, ale tak snadnΘ to nenφ. Uvedenß funkce p°edpoklßdß, ₧e ve formßtu vrchol∙ meshe bude slo₧ka normßl (D3DFVF_NORMAL), v opaΦnΘm p°φpad∞ se toti₧ nic nestane. Tak₧e nejprve musφme "p°eformßtovat" mesh do vlastnφho formßtu. To znamenß, ₧e vÜem vrchol∙m meshe urΦφme vlastnφ formßt s tφm, ₧e spoleΦnΘ vlastnosti se kopφrujφ. Proto jsem vytvo°il nov² typ MESH_VERTEX a formßt tohoto typu MESH_FORMAT: struct MESH_VERTEX #define MESH_FORMAT D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1|D3DFVF_DIFFUSE VÜimn∞te si, ₧e vrchol obsahuje to samΘ co VERTEX. Nynφ pou₧ijeme metodu CloneMeshFVF(), abychom mesh p°eformßtovali. Tato metoda vytvo°φ identickou kopii zdrojovΘho meshe, ale vrcholy majφ pochopiteln∞ po₧adovan² formßt. m_lpMesh->CloneMeshFVF(m_lpMesh->GetOptions(), MESH_FORMAT, m_lpDevice, &lpMesh); V dalÜφm kroku zjistφme, zda-li p∙vodnφ mesh ji₧ obsahoval normßly, v tomto p°φpad∞ nemß smysl generovat novΘ. Jinak pou₧ijeme v²Üe uvedenou funkci D3DXComputeNormals(). if(!(m_lpMesh->GetFVF() & D3DFVF_NORMAL)) Dßle jsem p°idal novou metodu t°φd∞ XMesh, kterß nastavφ barvu urΦitΘho podobjektu (subset) meshe. K tomu, abychom mohli p°istupovat k vrchol∙m jednotliv²m podobjekt∙m je t°eba mφt k dispozici tabulku atribut∙. Tato tabulka po vytvo°enφ meshe neexistuje a je t°eba ji vytvo°it metodou Optimize() s parametrem D3DXMESHOPT_ATTRSORT. lpMesh->Optimize(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &m_lpMesh); Nynφ ji₧ je tabulka k dispozici a m∙₧eme pou₧φt metodu GetAtrributeTable(). int XMesh::SetSubsetColor(int iSubSet, D3DCOLOR dwColor)
} V metod∞ nejprve zφskßme tabulku atribut∙, v prvnφm kroku je t°eba zφskat velikost tabulky (v tomto p°φpad∞ zadßvßme hodnotu NULL), dßle zφskßme vlastnφ tabulku opakovan²m volßnφm. V tabulce jsou mimojinΘ ulo₧eny offsety ve vertex bufferu pro jednotlivΘ podobjekty a poΦet vrchol∙. PotΘ VB zamkneme a modifikujeme vybran²m vrchol∙m barvu. Na zßv∞r VB op∞t odemkneme. 32.1. Zßv∞rP°φÜt∞ se jeÜt∞ podrobn∞ji vrßtφme k mlze, proto₧e v Direct3D je mo₧nostφ mnoho. Nakonec si jeÜt∞ trochu pohrajeme s kamerou, aby se nemohla dostat pod terΘn. T∞Üφm se p°φÜt∞ nashledanou.
|
|||||||||||||||||||||||||||||||||||||