C/C++ & Visual C++Kurz DirectX (34.) |
|
┌vodem | DatovΘ struktury | Kurz DirectX | Downloads | Otßzky a odpov∞di | 2001 | 2002 | 2003 | 2004 |
|
V tΘto lekci dßle upravφme pohyb kamery, kter² jsme naΦali v minulΘ lekci. Doplnφme formßt souboru cesty a pou₧ijeme jin² typ interpolace mezi segmenty. Dßle si n∞co povφme o technice Level Of Detail (LOD). V tΘto lekci si povφme, jak LOD obecn∞ funguje a p°φÜt∞ zkusφme implementovat jednoduch² LOD do naÜeho enginu. 34.1. Pohyb kamery - pokraΦovßnφP°edstavte si, ₧e chceme rotovat kolem n∞jakΘho objektu. Zde bychom m∞li velk² problΘm p°i definici sm∞rov²ch vektor∙. V tomto p°φpad∞ by se nßramn∞ hodilo, abychom sm∞r kamery definovali pomocφ druhΘho bodu. Definujeme tedy look-at point a eye point. V n∞kter²ch p°φpadech se ovÜem hodφ ob∞ varianty, proto zavedeme specißlnφ znaΦenφ °ßdk∙, kterΘ pou₧φvajφ prvnφ nebo druhou mo₧nost: Pokud na zaΦßtek °ßdku napφÜeme znak dolar ($), poslednφ parametr se interpretuje jako sm∞rov² vektor. Pokud mφsto dolaru pou₧ijeme k°φ₧ek (#), parametr se interpretuje jako bod s tφm, ₧e pokud pou₧ijete star² formßt, pou₧ije se prvnφ varianta. Zm∞ny k≤du jsou minimßlnφ, v metod∞ LoadPath() p°ibude testovßnφ prvnφho znaku na °ßdku: // Second vector is look at point V tomto p°φpad∞ se tento znak p°eskoΦφ a zßrove≥ nastavφme p°φsluÜn² flag, na kter² reagujeme po naΦtenφ ostatnφch hodnot na °ßdku: // vDir is look at point Touto operacφ spoΦφtßme sm∞rov² vektor, kter² bychom jinak museli vklßdat p°φmo do souboru cesty. V p°φpad∞ k°φ₧ku se tento znak pouze p°eskoΦφ. Na zßv∞r tΘto metody jeÜt∞ provedeme zacyklenφ spojovΘho seznamu. To se nßm bude hodit v zßp∞tφ, a₧ budeme implementovat novou interpolaΦnφ metodu: // Cycle path - last next is first and first previous is last Nßslednφka poslednφho segmentu nastavφme na prvnφ a p°edchßzejφcφ prvnφho nastavφme jako poslednφ. Dejte si ovÜem pozor, a₧ budete spojov² seznam odstra≥ovat z pam∞ti, kde se sleduje prßv∞ hodnota NULL poslednφho prvku - nynφ ₧ßdnß NULL hodnota nikde nenφ. Catmull-rom interpolace Jednß se o specißlnφ interpolaci, kterß pro v²poΦet vyu₧φvß hned 4 bod∙ na k°ivce (u lineßrnφ staΦily pouze dva). K°ivka mezi t∞mito body p°ipomφnß Bezierovu k°ivku, rozdφl je v tom, ₧e v p°φpad∞ Catmull-rom k°ivka prochßzφ p°es °φdφcφ body. Nebudu se tu v∞novat konkrΘtnφm vzorc∙m, jak spoΦφtat interpolovan² vektor. Na internetu se dß najφt mnoho podrobn²ch Φlßnk∙ k tΘto problematice. Direct3D podporuje tuto interpolaci v podob∞ funkce D3DXVec3CatmullRom(), kterß vlastn∞ ud∞lß vÜechno za vßs. Mß Üest parametr∙: ukazatel na v²stupnφ vektor, Φty°i ukazatele na vektory, z kter²ch se v²sledn² vektor poΦφtß a faktor interpolace - podobn∞ jako u lineßrnφ interpolace. Pro urΦenφ v²stupnφho vektoru je krom∞ bod∙ ohraniΦujφcφ aktußlnφ segment pot°eba dalÜφ dva body - jsou to sousedi hraniΦnφch bod∙. Z toho plyne, ₧e nejde urΦit sprßvn∞ vektor v prvnφm a poslednφm segmentu pokud nenφ k°ivka cyklickß. Proto jsme tedy nßÜ spojov² seznam zacyklili. Na nßsledujφcφm obrßzku je vid∞t, co jsem te∩ popsal:
Body P0-P3 jsou pot°eba pro v²poΦet interpolace v aktußlnφm segmentu. Parametr s je nßÜ interpolaΦnφ faktor, kter² poΦφtßme v metod∞ ProcessCamera(). D∙le₧it²m momentem je tedy v²b∞r sprßvn²ch bod∙, z nich₧ se poΦφtß interpolace: ps1 = ps2 = ps3 = ps4 = m_curSeg; Testovat hodnoty bychom ani nemuseli, proto₧e v celΘm spojovΘm seznamu by se nem∞la vyskytovat hodnota NULL. PotΘ ji₧ m∙₧eme zavolat funkci D3DXVec3CatmullRom() pro oba vektory: D3DXVec3CatmullRom(&m_curInterpolation.vPos, &ps1->vPos, &ps2->vPos, &ps3->vPos, &ps4->vPos, s); Zachoval jsem i lineßrnφ interpolaci pro srovnßnφ. Velkß v²hoda tΘto novΘ interpolace toti₧ spoΦφvß v tom, ₧e pohyb je mnohem plynulejÜφ a nedochßzφ k ostr²m zm∞nßm sm∞ru. 34.2. Level of Detail (LOD)Tato technika vyu₧φvß toho, ₧e vzdßlenΘ Φßsti terΘnu nemusφ b²t vykresleny ve vysok²ch detailech jako Φßsti nejblφ₧e k pozorovateli. My te∩ vykreslujeme vÜe stejn∞ detailn∞ a u vzdßlen²ch list∙ ani jednotlivΘ detaily nerozeznßme. Tento problΘm °eÜφ prßv∞ LOD, kde krom∞ jinΘho dosßhneme v²raznΘho nav²Üenφ v²konu. ╚φm je list dßle od kamery, tφm vφc vynechßme troj·helnφk∙ a malΘ troj·helnφky spojujeme do v∞tÜφch a v∞tÜφch. Nejvzdßlen∞jÜφ listy nahradφme pouze dv∞ma troj·helnφky! Jak u₧ to b²vß, i zde se najdou problΘmy, kterΘ se obtφ₧n∞ °eÜφ. P°edstavte se dva navazujφcφ listy, kterΘ jsou velmi ΦlenitΘ v mφst∞ p°echodu (pokud mluvφm o Φlenitosti, mßm na mysli velkΘ rozdφly nadmo°skΘ v²Üky na malΘm prostoru). Algoritmus nahradφ druh² list mΘn∞ detailnφm listem a druh² list ponechß. Nynφ nastane ne₧ßdoucφ efekt, kdy mezi prvnφm a druh²m listem vznikne mezera, bu∩ dφra "za" terΘn nebo p°evis. Toto chovßnφ m∙₧e b²t znaΦn∞ nep°φjemnΘ a terΘn ve v²sledku nevypadß moc p∞kn∞. ╪eÜenφ je mnoho. My si zde ukß₧eme jedno z t∞ch jednoduÜÜφch, kterΘ nenφ dokonalΘ. Pro ka₧d² list spoΦφtßme p°i inicializaci faktor p°ev²Üenφ listu. Pokud je tato hodnota p°φliÜ vysokß, znamenß to, ₧e tento list je velmi Φlenit² a tudφ₧ ho budeme nahrazovat se zpo₧d∞nφm - Φili a₧ bude opravdu daleko. Tak₧e nahrazovßnφ nebude zßvislΘ pouze na vzdßlenosti od kamery, ale takΘ na reliΘfu listu. DalÜφm vylepÜenφm by t°eba mohl b²t zp∙sob, kdy navφc porovnßme faktory okolnφch list∙ apod. Mo₧nostφ je hodn∞. ProblΘm s dφrami jsme vy°eÜili, ale zßrove≥ jsme trochu zhorÜili ·Φinnost celΘ techniky. Ale i p°esto je redukce kreslen²ch troj·helnφk∙ v²raznß a nßr∙st FPS rovn∞₧. Jak budeme techniku implementovat v naÜem terΘnu? Ka₧d² list obsahuje seznam sv²ch index∙ VèECH troj·helnφk∙. Zde mßme na v²b∞r. Bu∩ vyu₧ijeme tento seznam pro vÜechny ·rovn∞ LODu a budeme vybφrat ty sprßvnΘ troj·helnφky, co₧ se projevφ mφrnou Φasovou ztrßtou p°i o°ezßvßnφ list∙ nebo vytvo°φme dalÜφ seznamy nov²ch index∙, kterΘ obsahujφ v₧dy indexy pro jednu ·rove≥. Druhß mo₧nost zase zabere vφce pam∞¥ovΘho mφsta, ale bude trochu rychlejÜφ. Zkusit si m∙₧ete ob∞ varianty, jß zde ukß₧i pouze druhou zmφn∞nou. Upravφme tedy strukturu QTNode tak, ₧e p°idßme novΘ pole index∙ celkem pro 5 ·rovnφ (mßme listy 16x16, to bude 1. ·rove≥, dßle budeme vytvß°et listy 8x8, 4x4, 2x2 a 1x1 pro 5. ·rove≥). P°idejme tedy tyto atributy: // pIndicesX je pole index∙ X-tΘ ·rovn∞, wIndXCount je poΦet index∙ X-tΘ ·rovn∞ a wTilesXCount je poΦet polφΦek na X-tΘ ·rovni (to bude 16x16, 8x8, 4x4, 2x2 nebo 1x1). Atribut fLODFac je ji₧ zmφn∞n² faktor zvln∞nφ listu. PoΦty index∙ a polφΦek bychom samoz°ejm∞ mohli poΦφtat a₧ v dob∞ o°ezßvßnφ, ale jsou to konstanty, tak proΦ je nemφt p°ipravenΘ (vÜimn∞te si, ₧e op∞t na ·kor pam∞ti, ale tak to je tΘm∞° v₧dy). Nejd∙le₧it∞jÜφ nynφ bude inicializace vÜech seznam∙. Nejprve alokujeme pam∞¥ pro tyto seznamy: // allocate space for indices Ka₧dß dalÜφ ·rove≥ mß 1/4 index∙ co p°edchozφ, proto₧e obsahuje 4x mΘn∞ polφΦek. Nynφ nßsleduje smyΦka p°es cel² list, ve kterΘ najednou naplnφme vÜechny seznamy: for(y = pNode->arBounds[0].y; y < pNode->arBounds[3].y; y++)
pNode->pIndices1[i + 0] = bx + by * LOC_V_SIZE; if(x % 2 == 0 && y % 2 == 0) pNode->pIndices1[i + 0] = (bx+1) + by * LOC_V_SIZE; if(x % 2 == 0 && y % 2 == 0) V ka₧dΘm opakovßnφ inicializujeme hned 6 index∙ pro celΘ polφΦko (dva troj·helnφky). Pro p°ehlednost jsem barevn∞ odd∞lil jednotlivΘ ·rovn∞. Zßkladnφ 1. ·rove≥ je zelenß a nikterak se neliÜφ od p°edeÜl²ch dφl∙. Jen si vÜimn∞te, ₧e ka₧d² cyklus se do seznamu zapφÜe 6 index∙. Zajφmav∞jÜφ bude Φervenß neboli 2. ·rove≥. Zde se zapisuje jen ka₧d² vertex, Φili skßΦe se ob jeden vertex a tφm se vytvo°φ sφ¥ s poloviΦnφ hustotou. Takto pokraΦujeme p°es modrou, fialovou a nakonec ₧lutou ·rove≥ kdy z listu ud∞lßme jedno velkΘ pole (zapφÜe vlastn∞ jen 6 index∙ pro dva troj·helnφky). TakΘ si vÜimn∞te, ₧e ka₧dß ·rove≥ mß svΘ poΦφtadlo iX pro index na X-tΘ ·rovni. V prvnφ Φßsti cyklu vybφrßme maximßlnφ a minimßlnφ v²Üku vertexu. Tyto hodnoty v zßp∞tφ pou₧ijeme na v²poΦet faktoru: pNode->fLODFac = MaxZ - MinZ; Naposledy upravφme metodu CullTerrain(), kde vybereme sprßvnou ·rove≥ a zkopφrujeme p°φsluÜnΘ indexy. V p°φpad∞, ₧e je LOD aktivnφ, spoΦφtßme vzdßlenost od kamery a list "p°iblφ₧φme" o faktor. Slo₧it∞jÜφ listy se tak budou zdßt blφ₧e a nenahradφ se, i kdy₧ ve skuteΦnosti jsou daleko: // Vzdalenost listu od kamery - pocita se pouze pro LOD urovne > 1 Dßle budeme vybφrat ·rovn∞ podle vzdßlenosti: if(d < 150.0f) ... } K≤d zde neuvßdφm cel², proto₧e podmφnky se stßle opakujφ a₧ na ·rove≥ 5. V₧dy ovÜem musφme kopφrovat indexy ze sprßvnΘ ·rovn∞ a nakonec zv²Üit poΦet polφΦek v rßmci lokace - ka₧dß ·rove≥ mß tento poΦet jin²! A to je vÜe! Nynφ se bude mφsto 400 000 polygon∙ vykreslovat pouze okolo 40 000 polygon∙. Cel² p°φklad si samoz°ejm∞ m∙₧ete stßhnout v sekci Downloads. 34.3. Zßv∞rNa zßv∞r uvedu obrßzek ze souΦasnΘ verze naÜeho 3D enginu s technikou LOD:
Je vid∞t, ₧e vzdßlenΘ kopce u₧ jsou mßlo detailnφ a jevφ se jen jako mraky v dßlce... V programu m∙₧ete m∞nit interpolaΦnφ metodu klßvesou I. Pokud zapnete lineßrnφ interpolaci, je vid∞t, ₧e pohyb je vφce sekan² ne₧ v p°φpad∞ Catmull-rom interpolace. V p°φÜtφ lekci se vrßtφm k normßlov²m vektor∙m a ukß₧eme si jednoduch² zp∙sob, jak je spoΦφtat p°esn∞! Krom toho si tyto vektory zobrazφme nad terΘnem. T∞Üφm se p°φÜt∞ nashledanou.
|
|