![]() |
C/C++ & Visual C++Kurz DirectX (35.) |
Úvodem | Datové struktury | Kurz DirectX | Downloads | Otázky a odpovědi |
|
V této lekci se ještě vrátíme k normálovým vektorům terénu. Do teď jsme totiž tyto vektory počítali velice zjednodušeně a dá se říct i nepřesně. Dnes si ukážeme způsob, jak vektory určit přesněji. V další části lekce tyto vektory zobrazíme nad terénem, abychom viděli, že jsou skutečně správně. 35.1. Normálové vektory (2.)Do dnešní lekce jsme normálový vektor každého vertexu počítali pouze ze dvou směrových vektorů, které byly určeny polohou daného vertexu a jeho sousedy. Tento způsob lze použít v případě, že terén není příliš členitý (tedy nejsou zde náhlé změny výšky vertexu). V tomto případě totiž je vypočtený normálový vektor značně nepřesný. Mezním případem je ostrá hrana. Normála bude kolmá buď k jedné nebo k druhé rovině (podle toho, kde leží uvažované vertexy), což je samozřejmě neodpovídá skutečnosti. Správně řešení spočívá v tom, že vezmeme v úvahu všechny dílčí normálové vektory rovin přilehlých k daném vertexu a z těchto vektorů pak určíme průměrný normálový vektor. Tedy pro vyznačený vertex se jeho normála spočítá jako průměr vektorů n0 až n5 (dřív jsme vlastně vzali vektor n1 a ten jsme prohlásili za normálu n). Jak budeme postupovat při výpočtu? Nebude to nic moc složitého. Nejprve vybereme sousedy vertexu, pro který chceme normálu vypočítat. Musíme brát v úvahu to, že ne každý vertex má všech 6 sousedů. Například vrcholy na kraji terénu budou mít o dva sousedy méně, vrcholy na "rohu" dokonce o tři sousedy méně.
Postupně tedy otestujeme existenci sousedů v1 až v6 a rovnou spočítáme směrový vektor z vektoru v0 výrazem vx - v0 kde vx je v1 až v6. Přitom ještě uložíme informaci, že daný soused skutečně existuje a že ho později musíme brát v úvahu. Kód této části bude vypadat následovně: // Vektor, pro ktery normalu pocitame - stredovy vektor Proměnná vecMask je typu unsigned char nebo BYTE. Ve vektorech s1 až s6 jsou uloženy směrové vektory příslušných vertexů v0 - v6. V dalším kroku vybere správné sousedy a vypočteme dílčí normály. V proměnné vecMask je nastaven bit pokud existuje směrový vektor, takže dva sousední bity představují dva sousední směrové vektory, ze kterých určíme normálu. // Spocitame normaly pro sousedni dvojice Pro každé dva sousední směrové vektory spočítáme vektorový součin a výsledný vektor normalizujeme na jednotkovou velikost. V proměnné n0 je suma všech dílčích normál. Tento vektor v zápětí podělíme hodnotou iNormCount a získáme konečný normálový vektor jednoho vertexu! // ulozime vysledny vektor - udelame prumer vsech dilcich normal Jako třešničku na dortu vytvoříme konečný vektor jako průměr všech dílčích vektorů přilehlých rovin. Tímto algoritmem spočítáme normály o hodně přesněji než původní verzí. Na druhou stranu výpočet trvá podstatně déle, pro každý vertex totiž voláme funkci D3DXVec3Cross() hned 6x!!! 35.2. Zobrazení normálových vektorůV druhé části lekce se budeme zabývat tím, jak normály zobrazit u každého vertexu. Normálu zobrazíme jako čáru z příslušného vertexu směrem vzhůru. Výsledek pak bude vypadat jako kdyby na terénu byla dokonale kolmá tráva. Pro každou normálu budeme potřebovat dva body (vertexy). V lokaci máme 128x128 políček takže dohromady to bude 16384 normál s 32768 vrcholy. Vytvoříme tedy pro každou lokaci další vertex buffer. Index buffer nebude v tomto případě potřeba, protože jednotlivé čáry spolu nebudou mít nic společného, tudíž je jakákoliv indexace zbytečná. struct Location Tento buffer vytvoříme v metodě CreateQuadTree(). Každá lokace má vlastní buffer na normály a velikost jsme odvodili o pár řádků výše: // Create VB for terrain and copy all locations Buffer můžeme vytvořit a naplnit ve stejné smyčce jako vertex buffer pro samotné vertexy. m_pTerrainVB->GetBuffer()->Lock(l*LOC_V_SIZE*LOC_V_SIZE*sizeof(VERTEX), pVertices[i] = m_arTerrain[x][y]; Modře je vyznačen nový kód ve smyčce. Nejprve uzamkneme příslušný buffer lokace, poté ve dvou vnořených smyčkách nastavíme dva body pro každou normálu. První z těchto bodů je samotný vertex, kterému normála patří. Druhý bod je posunutý ve směru normály (normálový vektor máme již spočítaný). Navíc ještě každému bodu přiřadíme jinou barvu, aby byl vektor pěkně vidět na zeleném terénu. Na závěr buffer samozřejmě odemkneme. Na úplný závěr lekce ještě ukáži, jak normály vykreslit: if(m_dwFlags & TF_SHOWNORMALS) Viditelnost normál je závislá na příznaku TF_SHOWNORMALS. Nastavíme standardní parametry jako vertex shader, texturu na NULL, vypneme světlo (normály normál nevedeme) a pak vykreslíme vektory pro každou viditelnou lokaci. Vykreslování normál není příliš efektivní, ale v tomto případě nám samozřejmě nejde o výkon. 35.3. ZávěrNa závěr tu máme obrázek terénu s vykreslenými normálovými vektory:
Příklad si samozřejmě můžete stáhnout v sekci Downloads. Vykreslování normálových vektorů lze zapnout a vypnout klávesou U. Těším se příště nashledanou.
|
|