![]() |
C/C++ & Visual C++Kurz DirectX (33.) |
V dnešní lekci vylepšíme kameru, přidáme režim, kdy se kamera bude pohybovat po předem definované cestě. Dále přidáme několik metod do třídy XDisplay starající se o mlhu. 33.1. Pohyb kameryDo teď byl pohyb kamery zajištěn pouze pomocí interaktivního ovládání, které vyžadovalo vstup z klávesnice. V dnešní lekci přidáme do kamery neinteraktivní režim, kdy pohyb kamery bude řízen automaticky. Abychom pohyb jednoznačně určili, jsou třeba tři základní informace: poloha kamery, směr a čas, kdy se v této konfiguraci kamera nachází. Soubor cesty Výše uvedeny informace budou uloženy v souboru path.txt, který bude mít následující formát: Na každém řádku tedy bude jedna klíčová hodnoty polohy kamery. Mezi dvěma polohami se bude plynule interpolovat. Soubor budeme číst po řádcích, jednotlivé řádky rozkládat do jednotlivých položek pomocí oddělovače (zde středník). Struktura PathSegment Z této struktury postavíme spojový seznam všech segmentů načtených ze souboru. struct PathSegment PathSegment *pNext; Struktura uchovává všechny parametry kamery a navíc ještě ukazatel na následníka a předchůdce ve spojovém seznamu. Řetěz bude vypadat následovně:
Nyní upravíme třídu XCamera. Za prvé přidáme několik členských proměnných: // Cela path (1) // Rezim kamery (6) 1) Ukazatel na první segment spojového seznamu cesty enum PATHSTATUS 5) Modifikátor rychlosti pohybu. Implicitně je roven 1.0 (čas v souboru path odpovídá skutečnosti). enum CAMERAMODE 7) Informace o tom, zda je cesta načtena ze souboru. Nejdříve je pochopitelně nutno soubor path načíst a teprve pak je možno spustit vlastní pohyb. virtual HRESULT LoadPath(LPCSTR szPath); (1) float ExtractNumber(int i, char *line); (7) 1) Metoda načte soubor path a vytvoří spojový seznam popsaný výše. Nakonec připraví kameru pro spuštění interpolace. Nyní všechny tyto metody naimplementujeme. Nejsložitější metoda je LoadPath(), která využívá metodu ExtractNumber(). Začneme tedy od této metody: float XCamera::ExtractNumber(int i, char *line) for(int u = 0; u < i; u++) // Find first ; Možná není na první pohled vidět, co tato metoda vlastně dělá. Přijímá dva parametry: celé číslo jako pořadí čísla, které chceme extrahovat a řetězec řádky ze souboru path. Z tohoto řetězce je vybráno číslo podle parametru i, poté se převede na float, který je vrácen. V první smyčce tedy přeskáčeme všechny čísla před požadovaným. Funkce strspn() vrací index výskytu oddělovače. Tuto hodnotu ve vstupním řetězci přeskočím a to opakujeme tak dlouho až se dostaneme před požadované číslo. V další části se použije stejný postup na zkopírování části vstupu do pomocné proměnné number, který ještě zakončíme znakem '\0' a nakonec převedeme funkci atof() na float. Metoda LoadPath() načte ze souboru cestu a vytvoří spojový seznam. HRESULT XCamera::LoadPath(LPCSTR szPath) char szFullPath[MAX_PATH]; V první části načteme soubor pomocí funkce cmnLoadFileFromPath(). Tato funkce je v knihovně common.dll. Protože nevíme velikost souboru, nejprve zavoláme funkci s hodnotou NULL. Takto nám vrátí velikost bufferu, který musíme alokovat pro soubor. V druhém volání již použijeme buffer file. Funkce cmnGetDataFilePath() je opět z knihovny common.dll a pouze spojí cestu spuštěného programu a zadaného souboru, tím vytvoří úplnou cestu k souboru cesty. Na závěr této části vymažeme předchozí cestu, pokud taková existuje. pfile je ukazatel stejně jako file, ale s pfile budeme později hýbat. file nesmíme změnit, protože ho nakonec budeme dealokovat. while(pfile[0] != '\0') D3DXVec3Normalize(&ps.vDir, &ps.vDir);
V poslední části připravíme ostatní proměnné pro spuštění pohybu. Za prvé říkáme, že cesta je načtena. Do proměnné m_curInterpolation uložíme počáteční segment stejně jako do proměnné m_curSeg. Nakonec nastavíme pozorovací a pozorovaný bod. K tomu použijeme objekt aktuální polohy m_curInterpolation. m_curInterpolation.vPos je přímo pozorovací bod a pozorovaný dostaneme jednoduše tak, že k této hodnotě přičteme směr m_curInterpolation.vDir. Následující trojicí metod se dá ovládat pohyb kamery. Každá z těchto metod se nejprve přesvědčí, zda-li je načtena nějaká cesta. Metoda StartPath() provede dvě věci. Nastavením příznaku m_ePathStatus na hodnotu PLAY způsobí, že se začne počítat čas interpolace, který je uložen v proměnné m_curInterpolation.fTime. Pomocí této hodnoty se interpoluje (k tomu se dostaneme za chvilku) a pokud se mění, kamera se pohybuje. Za druhé je třeba kameře říci, aby přešla z interaktivního režimu do režimu PATH. Toto se dá rovněž nastavit metodou SetCameraMode(). Aby se pohyb kamery projevil po vizuální stránce, je třeba ještě trochu upravit metodu ProcessCamera(). Ta se rozdělí na dva případe: interaktivní a automatický s cestou. Interaktivní režim zůstane stejný jako doposud. Zajímavější bude druhý zmíněný způsob: // Path mode D3DXVec3Lerp(&m_curInterpolation.vPos, &m_curSeg->vPos, &m_curSeg->pNext->vPos, s); Pokud je nastaven příslušný režim pomocí metody SetCameraMode() (či metodou StartPath()), je pozorovaný a pozorovací bod počítán zcela jinak.
Interpolace probíhá pouze pokud je sekvence spuštěna (první podmínka). V tomto případě se vynásobí čas modifikátorem zrychlení, spočítá se časový rozdíl mezi
aktuálním a následujícím segmentem a určí se faktor interpolace. Ten je 0.0 pokud je kamera na začátku aktuálního segmentu nebo 1.0 pokud se kamera nachází na začátku následujícího segmentu.
V případě, že faktor je větší než 1.0, znamená to, že jsme již v dalším segmentu a je třeba přepnout aktuální segment, tedy z následujícího se stane aktuální. V opačném případě, tedy když je faktor záporný, znamená to, že jsme se dostali do předchozího segmentu, zde je třeba použít ukazatel na předcházející segment (kamera se pohybuje v opačném směru). Pokud ukazatele pNext nebo pPrevious ukazují na NULL, znamená to, že jsme na konci sekvence a je třeba se vrátit na začátek. Po přepnutí aktuálního segmentu
je třeba znovu spočítat faktor. Na závěr nastavíme pozorovací a pozorovaný bod pro matici pohledu. Všimněte si, že tyto řádky jsou stejné jako v metodě LoadPath(). 33.2. Podpora mlhy ve třídě XDisplayMinule jsme si říkali něco málo o mlze, ale nastavovali jsme ji přímo ve třídě XTerrain dost neohrabaným způsobem. Proto jsem přidal tři nové funkce do třídy XDisplay. EnableFog(BOOL bEnable) - vypne nebo zapne mlhu Parametr uFogType může nabývat hodnot: D3DFOG_LINEAR, D3DFOG_EXP nebo D3DFOG_EXP2. U lineární mlhy je třeba nastavit parametry fStart a fEnd. U exponenciální musí být nastaven parametr fDensity. Parametry Color určuje barvu mlhy. 33.3. ZávěrA je tu opět konec! Příklad si samozřejmě můžete stáhnout v sekci Download včetně zdrojových kódů. Abyste viděli výsledek dnešní práce, stiskněte klávesu C, kterou spustíte pohyb kamery podle cesty zadané v souboru path.txt, který si samozřejmě můžete upravit dle libosti. A jaký problém budeme řešit příště? Příště bych Vám chtěl ukázat další optimalizační techniku LOD (Level Of Detail), která pracuje na principu snižování složitosti terénu. Těším se příště nashledanou.
|
|