bachelor-thesis/ch2.tex
Oleg Petruny eb13264035
All checks were successful
CI / Build thesis PDFs (pull_request) Successful in 1m5s
CI / Verify PDF/A (pull_request) Successful in 1m29s
Graphics completed
2025-07-02 19:09:17 +02:00

361 lines
59 KiB
TeX

\chapter{Vývoj hry}
\label{chap:main}
Přenos starého projektu na~další major verzi~UE nebyl nijak problematický, dokonce v~editoru je~možnost rychlého exportu assetů do~jiného projektu. Rozhodně tomu pomohlo, že~se~C++~kód nepřenášel, ale~byl napsán znovu. UE~citelně rozšířil seznam dostupných tříd, přitom~některé jsou~již deprecated nebo~odstráněny úplně. Tak~mimo~jiné byly~odstraněny třídy Matinee (bývalý formát a editor animací objektů) pro~podporu novejší třídy Sequencer nebo~starý PhysX\footnote{PhysX je open-source fyzický engine s hardwarovou akcelerací pro grafiky s CUDA architekturou (GPU společnosti NVIDIA).} rozhraní, které~je nahrazeno systémem Chaos. Přesto se~něco pokazilo při~exportu objektů s~dynamickou fyzikou (závěsy, které~reagují na~simulaci větru, se~musely předělat).
Přenos byl~odůvodněn převážně malou velikostí starého projektu a~taky lákavou nabídkou nových technologií, zejména Nanite a~Lumen. Navíc pátá verze Unrealu -- přesněji verze~5.5 -- přinesla značná vylepšení jako:
\begin{itemize}
\item Nový systém zpracování vstupu Enhanced Input\footnote{https://dev.epicgames.com/documentation/en-us/unreal-engine/enhanced-input-in-unreal-engine}. Místy má~příliš mnoho objektové abstrakce, ale~rozhodně velký krok vpřed. Umožňuje snadné dynamické přepínání různých sad ovládání (multiplayer hry, gameplay/menu), dynamické modifikátory a~spouštěče vstupu (změna senzitivity, víceklik, podržení tlačítka určitou dobu), podpora vstupu více než~jedné periferie naráz a~podpora přeřazení vstupu (např.~změna tlačítka odpovídající za~skok herní postavy). Předtím tohle a~spoustu dalšího se~muselo naprogramovat ručně.
\item Podporu vektorové grafiky v~UI. Veškeré staré UI~elementy byly~tvořeny pomocí základních vektorových obdélníkových tvarů právě proto, aby~se~vyhnulo použití rastrové grafiky, která~je~velmi závislá na~rozlišení. Aktuálně všechny UI~elementy jsou tvořeny ještě starou metodou, pro~udržení konzistentního vzhledu. V~budoucnu bychom určitě využili této~možnosti.
\item Přepracované vykreslování textů -- rychlejší vykreslování a~efektivnější využití paměti.
\item MetaSound\footnote{https://dev.epicgames.com/documentation/en-us/unreal-engine/metasounds-the-next-generation-sound-sources-in-unreal-engine} pro~přehrávaní nebo procedurální generování zvuků, který~nahrazuje starou třídu~Cue. De-facto se~jedná o~Digital Signal Processing (DSP) grafový engine a~editor. Bohůžel jsem nestihl tento nástroj využit v~práci.
\item World partition systém\footnote{https://dev.epicgames.com/documentation/en-us/unreal-engine/world-partition-in-unreal-engine}, který~dokáže automaticky rozdělit jeden velký svět na~streamovací kousky a~propojit sdílení dat mezi nimi i~při multiplayer hře přes internet. Taky není využit v~této práci.
\end{itemize}
Samozřejmě je~toho daleko víc, ale~většina ostatních vylepšení jako~rovněž nový systémy animací postav Motion Matching\footnote{https://dev.epicgames.com/documentation/en-us/unreal-engine/motion-matching-in-unreal-engine} nebo~nový fyzikální engine Chaos\footnote{https://dev.epicgames.com/documentation/en-us/unreal-engine/destruction-overview} neměly vliv na~rozhodnutí.
Podrobné informace jak~každá implementace funguje a~jak s~ní~pracovat, je~popsáno v~přiložené programátorské dokumentaci.
\section{Herní logika, systémy, mechaniky}
\label{sec:systemsAndMechanics}
\subsection{Architektura}
Protože Unreal Engine byl~na~začátku vyvíjen primárně pro~online multiplayer hru Unreal Tournament a~dnes~je stejně~tak vyvíjen spolu s~extrémně velkou online multiplayer hrou Fortnite, je~backend enginu velmi abstraktní.
Například každý svět musí obsahovat vlastní game mode (třída AGameMode), který~funguje jako~správce daného světa -- přestože svět se~může spravovat sám. Veškerá funkcionalita používaná v~singleplayer hrách mohla být přímo v~kódu levelu nebo~v~globální instanci celé hry. Důvodem této abstrakce je~právě nativní podpora multiplayer her, která~potom vývoj takových her zjednodušuje.
Protože tento projekt je~zaměřen pro~hru jednoho hráče, práce je~často programována navzdory ustáleným UE~C++ zásadám (guidelines) pro~pohodlí a~rychlost vývoje. Proto~často třídy manažerů systémů, game~modů, instance hráče a~další jsou na~architektuře singletonu. Přináší~to nejen zmíněné pohodlí, ale~navíc šetří od~tří do~deseti volání getterů, reflexí (castů), vyhledávání v~hash tabulkách a~iteraci polí v~každém místě použití. Přesto nemá žádný vliv na~stabilitu programu a~dokonce šetří výkonem zařízení.
Jen pro představu, co~obnáší klasické získání reference na~instanci vlastní třídy hráče na~pozadí. GetGameMode()\textrightarrow GetPlayerController(index)\textrightarrow GetPlayerPawn()\textrightarrow Cast<Class>(). A~blueprinty disponují zkrácenou verzí GetPlayerPawn(index)\textrightarrow Cast<Class>(). V~případě~C++ je~potřeba navíc ověřovat zda~nějaké z~volání nevrátilo nullptr.
\subsection{Scény a ukládání hry}
Scény, resp. levely (třídy UWorld a ALevelScriptActor)\footnote{UWorld instance je~přímo celý svět, který~funguje jako~balík metadat a~kontejner pro~veškeré instancované objekty v~něm. ALevelScriptActor je~objekt instancovaný v~UWorld automaticky a~obsahuje uživatelskou logiku světa.}, lze~taktéž získat v~podobě singletonu. Základní implementace byla~rozšířená pro~high level mechanismus volání událostí ve~scéně. Ten~je~zapotřebí například, když~hráč aktivuje spínací plošinu ve~hře a~ta~následně otevře dveře.
\newpage
Na rozdíl od~jiných enginů, v~UE objekty ve~světě nemůžou referencovat jiné~nezávislé objekty. Jednoduše referenci nelze přiřadit z~důvodu abstrakce popsané v~předchozí podsekci, protože~každý objekt může~mít vlastní herní svět (a~nejen~to). Proto~pokud~plošina z~našeho příkladu chce otevřít dveře, musí~zkusit poslat požadavek správci herního světa, ten~požadavek se~nějak zpracuje a~teprvé~poté správce buď~provede akci otevírání dveří samostatně nebo~zavolá odpovídající funkci v~instanci objektu. Pokud~by~bylo potřeba opustit singleton architekturu pro~podporu paralelní existenci světů, stačí předělat členskou (member) funkci instance světa na~statický multicast delegate\footnote{Delegate jsou obaly na~C++ funkce, lambdy, funkce s~reflexi a~funkce z~Blueprintu. Delegate může~být typu single, pro~uložení reference na~jednou funkci, nebo~multicast pro~uložení dynamického seznamu funkcí. Podrobněji jsou~popsané v~programátorské dokumentaci.}, ke~kterému se~každý svět při~konstrukci bude vázat.
Navíc hra byla rozšířena o~implementaci obnovení hry z~úložených dat. Při~návrhu byla~snaha udělat postup co~nejjednodušší. Hra se ukládá pomoci globální herní instance (třída GameInstance)\footnote{GameInstance je~první objekt vytvořený enginem hned po~úvodním načtení základu enginu a~taky poslední objekt na~destrukci při~vypínání hry.} při~vypínání hry a~načítá taktéž při~spuštění. Byl~využit existující systém serializace v~UE, který~ukládá inventář postavy, jméno levelu a~checkpoint na~něm spolu s~posledním stavem levelu.
\subsection{Interakce}
Interakce jsou~často řešeny pomocí architektury interface tříd\footnote{Interface třídy jsou~konkurenčním přístupem komponentní architektuře. Interface je~běžná praktika v~OOP (Objektově Orientovaném Jazyce), která~funguje jako~domluva, že~objekt bude obsahovat určité member funkce. Komponenty jsou~samostatné určité podinstance objektu. Komponentní přístup se~osvědčuje jako~intuitivnější a~více flexibilní zatímco Interface přístup při~vývoji her je~spíše nepříjemné vynucení ze~světu~OOP.} především kvůli populárním návodům vyzdvihující tuto metodu jako~nejlepší ještě~z~doby, kdy~Unreal Engine~4 pouze vznikal. Nevýhodou je~potřeba v~obsáhlém a~repetitivním nastavení každého objektu, který~chceme zapojit do~mechaniky interakce.
Byl navržen komplexní systém pro~správu každého interakčního objektu a~komponent (viz.\Cref{fig:InteractableSystemDiagram}). Objekt dědící třídu AInteractable při~instancování samostatně nastaví a~následně přepíná potřebné kolize. Zároveň spravuje interakční komponenty a~reaguje na~požadavky, které~jsou na~ně směřovány. Komponenty se~dělí na~aktivátory a~modifikátory.
\begin{figure}
\centering
\includegraphics[width=1\linewidth]{img/InteractableSystemDiagram.pdf}
\caption{Diagram zpracování systému interakčních objektů.}
\label{fig:InteractableSystemDiagram}
\end{figure}
\newpage
\paragraph{AInteractableActivator} Aktivátory jsou~komponenty s~určitými mechanismy detekce objektů. Instance hráče automaticky vytváří pro~sebe jednu podinstanci každého aktivátoru registrovaného v~enginu. Libovolný objekt může rovněž obsahovat libovolný aktivator. Práce obsahuje klasický způsob detekce objektů pomoci ray~tracingu a~následného dereferencování objektu v~případě nárazu paprsku.
Navíc je~k~dispozici detekce objektů v~zorném poli hráče. Ta~funguje na~zpomaleném snímání určité stencil vrstvy\footnote{Stencil Buffer sousedí s~Z-Bufferem a~má~pouze jeden osmi~bitový celočíselný kanál. Slouží především jako~pomocník při~tvorbě specifických renderovacích technik a~efektů. Nejběžnější použití je~renderování obrysů objektů, označení objektů pro~následné zpracování v~nějaké render pipeline a~tvorba portálů.} s~vynecháním většiny render pipeline a~v~malém rozlišení. Zachycený snímek obsahuje pouze viditelné hráčem interakční objekty v~podobě masky. Následně je~maska v~grafickém vlákně zpracovaná pomocí algoritmu vyhledávání komponent z~počítačového vidění, kterou~poskytuje knihovna OpenCV. Nakonec do~středu nalezených komponent se~promítne paprsek a~zachytí objekty (viz.~\Cref{fig:InteractableScreenCapture}).
Původně bylo předpokládáno využití HLSL compute shaderu\footnote{High-Level Shader Language je~proprietární shader jazyk používaný v~DirectX.} pro~vyhledání komponent v~textuře, ale~z~časových důvodů jsem nedodělal přenos dat mezi CPU a~GPU, jelikož dohledat dokumentaci o~použití shaderu je~poměrně náročné. Proto~aktuální vyhledávání komponent je~spouštěno na~procesoru a~v~renderovacím vlákně na~moderních zařízeních trvá pět až~deset milisekund. V~praxi se~tento problém často řeší náhodným promítáním velkého množství paprsků nebo~velkého hitboxu napodobujícího tvar pohledového frustrumu kamery. Tato řešení jsou sice~rychlá na~implementaci, avšak~při~větších vzdálenostech vykazují výrazné snížení přesností a~větší spotřebu výpočetních prostředků. Navíc zahrnují časté počítání nárazů na~velké množství objektů, čímž~výkonnostně nejsou o~nic~lepší metody implementované v~této práci.
\begin{figure}
\centering
\includegraphics[width=1\linewidth]{img/InteractableScreenCapture.pdf}
\caption{Debug náhled aktivace interakčních objektů v zorném poli hráče.}
\label{fig:InteractableScreenCapture}
\end{figure}
\paragraph{AInteractableModificator} Modifikátory jsou~komponenty s~určitou logikou libovolné modifikace objektu, ve~kterém jsou~instancovány. Tyto~komponenty mohou obsahovat pouze objekty označené jako~interakční (dědí třídu interakčního objektu). Aktuální implementace nabízí modifikátory pro~aktivaci nějaké události pomoci dosahu~,,ruky'' nebo zahlédnutím~,,očima'' hráče, pohyb a~rotace předmětu v~prostoru, ukládání předmětu do~inventáře hráče.
Z~časových důvodů byla zamítnuta implementace modifikace geometrie objektu, která~by~využívala nového rozhraní Chaos.
Největší přínos nového systému zpracování vstupu v~Unreal Engine~5 se~projevil právě u~modifikátorů. Ty~využívají možnost dynamického přidávání nebo~odstraňování vstupních kontextů za~běhu.
\subsection{Cutscény a Quick Time Events}
Unreal Engine je~známý~tím, jak~dobře umožňuje animovát scény. Rozhraní a~editor systému Sequencer jsou~přívětivé a~nabízejí široké možnosti. Bohužel~však většina těchto výhod končí mimo samotný editor, jelikož~chybí pohodlné prostředky pro~režii různých souborů animací (totéž platí i~pro~UI animace). Proto byl~dodán systém UCutsceneManager implementující frontu animací spolu s~uživatelským rozhraním pro~jejich přeskakování.
Pro~přiblížení problému, vyjmenuji časté potřeby, které~vznikají při~běžném použití animací.
\begin{itemize}
\item Zároveň spuštěné animace bojují o~vlastnictví objektů,
\item animace nelze přetáčet,
\item u~animace nelze zjistit zpětně zda~byla přehrána až~do~konce, pouze přivázat volání funkce po~ukončení,
\item systém dokáže určit, zda~se~animace někde přehrává, ale~není schopen ukázat, kde~přesně.
\end{itemize}
Převážně pro~použití v~animacích je~implementována fronta rychlých interaktivních událostí (QTE - Quick Time Events), což~jsou~interaktivní UI~elementy na~obrazovce hráče. V~herním průmyslu jsou~využívány zejména v~cutscénách, pro~,,hlubší ponoření'' hráče do~děje. Klasickými příklady jsou~animace šplhání herní postavy po~nějaké překážce nebo~kinematografický souboj mezi postavami. Při~takových událostech lze~přiblížit hráče k~dynamické a~napínavé situaci pomocí klikání na~stejně dynamické UI~elementy na~obrazovce v~souladu s~pohybem herní postavy. V~praxi se~objevují i~pokročilejší varianty napodobení děje pohybem myší a~joystickem nebo~gyroskopem ovládače. V~implementaci jsou~k~dispozici eventy jednotného a~vícenásobného klikání a~držení tlačítka v~časovém intervalu.
\subsection{Dialogy}
V~enginu je~zavádějící implementace pokročilého dialogového systému. Dialogy jsou~neintuitivní pro~tvorbu a~použití, vyžadují časté repetitivní kopírování stejných parametrů mezi~soubory dialogů a~k~tomu celý systém má~nedostatečnou dokumentaci. Navíc~,,dialogy'' v~tomto systému jsou~pouze samostatné věty, které~musí přehrávat nějaký zvuk a~mohou se~vybírat v~závislosti na~omezeném kontextu typu ,,kdo~na~koho mluví''. O~nepoužitelností takového rozhraní svědčí návody na~tvorbu vlastních dialogů nebo~vývojářský obchod plný pluginů implementujících tento systém lépe.
\newpage
Protože kvalitní řešení jsou~placená a~ty~zdarma jsou~často nevyhovující kvality, byla~navržená vlastní implementace. Jedná~se o~frontu, která~umí přehrávat celé tabulky dialogových vět. Dialog, resp.~množinu vět společného kontextu, lze~pohodlně zapsat do~tabulkového formátu přímo v~editoru. Jednotlivá věta obsahuje id, text, dobu přehrání nebo~zvukovou stopu. Ve~výsledku lze~do~fronty zařadit několik tabulek, které~se~mohou přehrávat sekvenčně od~n-té věty po~poslední, jednu náhodnou větu nebo~přesně jednu větu podle id.
\subsection{Minihry}
Herní průchod druhého levlu je~celý složen z~miniher. V~době vydání práce obsahuje pouze pět~hlavních miniher v~podobě ,,proof of~concept''. Z~časových důvodů nebyly vedlejší minihry implementovány. Každá z~miniher je~parodie na~již existující známou hru.
Minihry jsou samostatné objekty, které~může správce scény restartovat nebo~vypnout. Po~spuštění si~minihra sama přepne kontext ovládání na~sebe a~řídí svůj vlastní stav. Jestli~minihra nebyla ukončena dočasně, ale~dohraná, vráti ovládání zpět hráči spolu s~výsledkem a~skóre.
Dostupné zkušební implementace:
\begin{itemize}
\item Parodie flash hry Age of~War. V~pozadí scény s~úklidem učebnic dějepisu jsou~umístěny základny hráče a~soupeře (umělé inteligence). Hráč ovládá minihru pomicí~UI, kde~nakupuje jednotky typu: pěšák, střelec a~tank. Peníze získává za~zničení nepřátelských jednotek. Vyhrává ten, kdo~dokáže proniknout přes obranu nepřítele až~k~jeho základně a~zničit~ji. V~aktuální implementaci chybí vylepšení jednotek, zvuky, grafické efekty, modely a~animace jednotek. Přesto~lze vyzkoušet nákup a~,,souboj'' jednotek.
\item Parodie na~mobilní hru Subway Surfers. Aktuálně má~minihra nevhodné pozadí, neobsahuje audio a~grafické prvky. Podle návrhu hráč nahání veverku v~lese, která~mu ukradla část důležitého pro~příběh předmětu. Pomocí pohybů nahoru, dolů, vlevo a~vpravo se~hráč vyhýbá objevujícím se~překážkam v~lese. Překážková dráha má~šířku tří~běžeckých pruhů a~překážky mohou vyžadovat přeskočení, sklouznutí nebo~úhyb do~strany.
\item Podoba počítačové rytmické hry Osu!. Hráč má~za~úkol klikat na~objevující~se na~obloze hvězdičky v~souladu s~rytmem hudby (v~pořadí ve~kterém se~objevily). Aktuálně ,,hvězdičky'' jsou~v~podobě čtverečků, ale~hudba je~zcela hotova. Již~teď lze vyzkoušet klikání během prvních 10~sekund hudby.
\item Podoba mobilní hry Crossy Road. Hráč pomocí pohybu dopředu, dozadu, doleva a~dolů potřebuje posouvat se~vpřed po~překážkové dráze. Dráha je~složená z~pěti~pruhů kolmých ke~kameře, a~každý pruh je~složen z~dvanácti políček, na~které~může stoupnout hráč. Náhodně na~krajích pruhu se~objevují divoká zvířata, laviny a~silný vítr (v~originální hře to~jsou auta na~silnici), které~se~posouvají k~opačnému kraji přes všechna políčka a~mohou ukončit běh hráče. Podle návrhu se~minihra odehrává v~ledovém prostředí, kde~hráč prochází sněžnou krajinou. Audiovizuální prvky opět nejsou k~dispozici, ale~již~teď lze vyzkoušet posun dopředu a~úhyb překážkám.
\item Jednoduchá minihra rybolovu (více podob napříč různými hry). Hráč má~na~obrazovce svislý obdélníkový indikátor znázorňující vodní hlubinu. Podél indikátoru se~náhodně pohybuje obrázek rybičky, kterou~hráč musí udržovat v~malé pohyblivé zóně. Zóna se~pohybuje automaticky dolů nebo~nahoru držením tlačítka myší (rychlost pohybu není lineární, ale~kvadratická). V~implementaci chybí zvukové assety a~vyváženost složitosti, ale~je k~dispozici kompletní~UI a~mechanika lovu.
\end{itemize}
\subsection{Nehratelné postavy}
Pro~tvorbu NPC (Non-Playable Characters) byly použité základní prostředky enginu. Podle návrhu hry, k~dispozici měly~by~být tři~druhy logiky pro~NPC, ale~z~časových důvodů jsou~implementovány pouze~dvě. Jedno~z~chování je~pouhá chůze k~dynamickým bodům. Toto~základní chování se~potom rozděluje na~střežení oblasti nebo~boj s~hráčem.
Postavy, které~střeží oblast využívají v~UE5 nový systém vjemů nehratelných postav. Postavy umí reagovat na~zvuky, dotyky nebo~zahlédnutí jiných objektů. Toto~je~využito pro~postavy, které~hlídají vězení v~levelu 4. Ty~patrolují předem navržené trasy a~spouští určité akce až~zahlédnou hráče.
V~implementaci chybí kompletní logika boje s~hráčem. Aktuálně postavy pouze běží k~hráči pokud ho~zahlédnou. Zbytek nedodělané logiky je~spíš vizuálního charakteru a~spočíval~by v~jednoduchých animacích použití střelné nebo~ruční zbraně ve~hře.
Každé chování využívá Navmesh pro~orientaci na~úrovni.
\subsection{Nastavení}
Hra využívá existující v~enginu de/serializaci v~textovém formátu~,,.ini''. Při~exportu hry v~podobě samostatného buildu lze~využívat i~binární formát konfiguračních souborů. Tento~přístup značně zjednodušuje tvorbu konfiguračních proměnných. Díky~tomu stačí pro~tvorbu vlastních parametrů pouze~deklarovat potřebné proměnné v~C++~třídě.
Triviálně se~pracuje s~preferencemi hráče, které~určují hlasitost různých kategorií zvuků nebo~preferencemi ovládání. U~těchto preferencí stačí pouze~přečíst resp.~zapsat hodnotu. Jednoduché to~přestává~být v~momentě nastavení kvality grafiky a~parametrů zobrazení okna aplikace. Zejména změny zaměřené na~okno aplikace mohou způsobit pád~aplikace nebo~ještě hůř zablokovat vstup celého počítače a~donutit uživatele ke~kompletnímu restartování zařízení. Takové~situace mohou nastat celkem běžně, a~nemusí znamenat problém v~aplikaci. Například předčasný zásah~OS k~neodpovídajícímu procesu (hra se~delší dobu načítá po~aplikování nového nastavení) nebo~nevhodná reprezentace rozlišení, které~monitor nebo~GPU uživatele nepodporuje.
V~libovolném případě hra musí~být~schopna obstát nečekané závady, a~proto byl~navržen mechanismus obnovení předchozích funkčních nastavení. Po~zvolení nových parametrů a~jejich aplikování, hra nejprv~uloží stávající nastavení a~až~poté aplikuje ty~nová. Po~aplikování a~až se~proces okna vrátí zpět do~renderujícího stavu, v~menu se~objeví okénko po~dobu pěti~sekund očekávající schválení od~uživatele. Pokud~uživatel stihne potvrdit úspěšnou změnu parametrů, jsou~uložené jako~funkční. Pokud~uživatel z~libovolného důvodu změnu neschválí, potom jsou~obnoveny předchozí parametry.
\newpage
Právě nastavení zobrazení okna (a~výběr zhlazovácí metody) byly implementovány navíc, jelikož~nejsou volně k~dispozici v~high-level implementaci enginu. Jedná~se~o~možnost výběru rozlišení a~jeho třídění podle poměru stran, změna režimu vykreslování okna (bezokenní, okenní bez~rámce, okenní s~rámcem) aЁzměná obnovovací frekvence. Při~výběru a~nastavení rozlišení se~pracuje přímo s~DirectX\footnote{DirectX je~množina API pro~práci s~grafikou a~převážně pro~počítačové hry.} rozhraním a~zhlazovací metoda se~nastavuje přes~příkazové rozhraní enginu.
\section{Návrh tvorby generativního obsahu a jeho načítání za běhu}
\label{sec:contentGenerationAndIntegration}
\subsection{Možností generativních modelů v tomto projektu}
Herní úrovně jsou navrženy~tak, aby~pokrývaly rozsáhlé herní žánry a~situace, které~dosud~nebyly nebo~nejsou~často využívané s~generovanou tvorbou.
\begin{enumerate}
\item Level je~zaměřen na~tvorbu hororového obsahu. Je~to~skvělá příležitost vývoje a~použití modelu, který~využívá naše~fyzické, chemické a~psychické znalosti o~lidském organismu, aby~dokázal generovat strašidelný obsah a~následně ho~vhodně začlenit.
\item Level slouží k~testování modelu schopného tvorby libovolných miniher. Nabízí~se~tady~taktéž online tabulka skóre pro~základní a~vygenerované minihry.
\item Level existuje pro~generování nových logických úseků a~úkolů a~modifikaci stávajících logických překážek. Například nová logika zapojení kabelů v~elektrotechnické místnosti nebo~přestavba bludiště.
\item Level umožňuje vyzkoušet generování sekvencí chodeb. Chodby by~musely obsahovat patroly a~kryty~tak, aby~hráč dokázal nenápadně prolézt skrz patroly.
\item Poslední Level bude testovat schopnost navržení herních nepřátel, jejich logiku a~rozmístění na~úrovni.
\end{enumerate}
\subsection{Návrh architektury}
Architektura generování obsahu je~založená na~použití zřetězení různých modelů a~kontrolních mechanismů. Kompletní řetězce modelů jsou~nasazeny na~soukromých serverech, které~v~různých intervalech nezávisle produkují nové assety. Po~generování jsou hotové soubory přemístěny na~veřejné úložiště, odkud~hra při~zapínání stahuje několik~,,náhodných'' assetů (přesnou definici výběru obsahuje \cref{par:contentSharing}).
\paragraph{Fine-tuning} V~podobě open-source je~k~dispozici většina potřebných druhů modelů. Po~analýze vyplývá, že~bude~potřeba vytvořit pouze jeden~model, který~bude~schopen pracovat s~kódem v~Unreal Engine. Je~to~potřeba pro~programování assetu nebo~aspoň~jeho~umístění ve~světě hry. Nejjednodušší a~zároveň efektivní cesta je~založená na~fine-tuningu resp.~dotrénování modelu, který~se~již~využívá pro~programování.
\newpage
Dotrénování může~mít více~podob. Nejspíš by~se~jednalo o~fine-tuning programovacího modelu v~C++ s~dodatečnou syntaxí Unreal Enginu nebo~fine-tuning tvorby diagramů v~Blueprintech. Výsledné blueprinty potom~lze konvertovat do~Python příkazů, které~vytvoří vygenerovaný diagram v~editoru. Nelze jednoznačně říct, který~přístup je~vhodnější. Pro~C++~model je~k~dispozici více dat a~toto prostředí umožňuje větší tvůrčí svobodu, přestože~může zhavarovat aplikaci. Blueprinty jsou~zdaleka bezpečnější, ale~na~oplátku bude~těžší sbírat trénovací data.
\paragraph{Postup generování}
Vše~by~začínalo v~textovém modelu, který~vytvoří typ a~popis generovaného objektu. Pomocí třídícího mechanismu se~vybere příslušná množina dalších modelů, kontrolních mechanismů a~konverzních nástrojů. Asset bude~postupně procházet takovým řetězcem až~nabyde finální podoby. Na~konci bude~vždy kontrolní mechanismus, který~zvaliduje soubor a~ověří funkčnost assetu pomocí unit-testů ve~hře. Pokud~asset neprojde validací, celý postup, soubor a~vstupní popis se~zaznamenají pro~budoucí ruční doladění modelu.
Příklad tvorby interakčního objektu:
\begin{enumerate}
\item LLM vytváří popis assetu, v~tomto případě interakční objekt, který~přehrává specifický zvuk a~je~umístěn na~konkrétním místě v~levelu~3.
\item Kontrolní mechanismus vybírá následující potřebné modely a~nástroje.
\item Popis prochází modelem generující obrázky.
\item Obrázky prochází modelem generující 3D~model (nejdřív se~generuje 360°~video potřebného objektu, ze~kterého se~následně generuje mesh).
\item Další část popisu je~použita modelem generující zvukové stopy.
\item Poslední část popisu se~vloží do~našeho dotrénovaného programovacího modelu. Tento~model se~zároveň stará o~umístění assetu v~herních světech, protože~jako~jediný je~natrénovaný na~kontext této~hry.
\item Výsledné kousky linkovací mechanismus spojí do~jedné~třídy resp.~vloží do~jednoho Blueprintu. Předtím převede jednotlivé části na~assety v~enginu a~případně aktualizuje cesty referencí.
\item Konečný asset se~zkouší na~kompilaci a~prochází unit-testy. Pokud~tento~krok bude úspěšný, asset je~exportovan v~podobě~DLC nebo~patch~obsahu. Jinak~popis, vygenerováné částí a~výsledek se~logují pro~budoucí investigaci.
\end{enumerate}
\subsection{Poskytování obsahu}
\paragraph{Nasazování generátoru} Nezávislé řetězce modelů zjednodušují řízení sítě workerů. Pomocí Docker kontejneru\footnote{Docker je~software umožňující lokální virtualizaci prostředí nazývané kontejnery. Kontejnery jsou~předvytvořené samostatné prostředí s~potřebnými nástroji.} nebo~nasazovacího skriptu by~se~snadno vytvořil další worker (naše~generující jednotka), který~může ihned~začít s~generováním. Vygenerovaný obsah je~poté přemístěn na~veřejné úložiště, tedy~worker nepotřebuje nijak~velké vlastní úložiště.
\newpage
Protože~workery nemusí~odpovídat na~požadavky uživatele v~reálném čase a~plánovaná doba jedné hry je~15-30~minut, generátory nemusí~být~rychlé a~tedy~ani~náročné na~výpočetní prostředky. Nezáleží~nám ani~na~dlouhodobé životnosti workerů, jelikož~modely se~často sekvenčně přepínají (běží vždy pouze jeden model najednou). Takový~přístup přináší flexibilitu v~řízení prostředků a~umožňuje ukládat mezistavy generátorů. Dokonce nepotřebujeme nijak~velkou propustnost sítě, protože~jednoduché assety nemohou přesahovat velikost jednotek megabajtů a~jistě~máme větší časové intervaly mezi~vznikem souborů.
\paragraph{Stahování obsahu}\label{par:contentSharing} Hra automaticky stahuje a~aktivuje obsah před začátkem nové hry. Z~podrobné analýzy jsem~rozhodnul, že~nejsou~zapotřebí žádné autentifikační nebo~šifrovací vrstvy. Vždy~by~byla~možnost zpětnou analýzou (reverse-engineeringem)\footnote{Reverse-engineering je~metoda analýzy hotového produktu (v~nášem~případě binárního souboru), pro~získání neveřejných informací popisujících funkčnost produktu.} získat klíč z~binárních souborů hry a~napadnout celý systém. Když~se~nad~tím zamyslíme, volný přístup k~generovaným assetům nemá žádné zápory. Je~jednoduchý na~implementaci a~údržbu. Očekává~se ale připojení pomocí HTTPS\footnote{Hypertext Transfer Protocol Secure je~protokol pro~šifrovaný přenos dat využívaný pro~poskytování webových serverů.} a~ověření certifikátu\footnote{Certifikáty v~digitální podobě jsou~řetězcem veřejných asymetrických klíčů různých vydavatelů. Každý~předchozí vydavatel ručí za~důvěryhodnost dalšího vydavatele.} s~kopií uloženou v~aplikaci. Mohlo~by~totiž dojít k~man-in-the-middle útoku\footnote{Man-in-the-middle (MITM) je~druh kyberútoku, ve~kterém útočník tajně sleduje nebo~upravuje komunikaci mezi~dvěma uzly.} a~hráč by~mohl spustit ve~hře nebezpečný obsah.
Hra zahájí stahování pomocí API, který~vybere nějaké soubory. V~základu assety jsou~vybírány náhodně, ale~zároveň se~používá hodnocení získané od~hráčů, které~váhově lehce~mění hustotu pravděpodobnosti normálního rozdělení.
\paragraph{Hodnocení obsahu} Poté, co~si~hráč zahraje s~určitým assetem, máme~možnost získat zpětnou vazbu od~hráče. Hodnocení využíjeme k~váhové manipulaci náhodného výběru a~zároveň jako~data pro~doladění generátorů. Návrh~systému hodnocení staženého obsahu je~již náročnější problém. Úkolem je~umožnit pouze unikátní hodnocení a~pouze od~hráčů, kteří~si~s~tímto obsahem opravdu zahráli. Protože~nemáme žádnou autentifikaci, volné~hodnocení nemusí fungovat. Kdokoliv může~spamováním falešných hodnocení přemístit špatně hodnocený obsah do~kategorie lepších a~naopak. Autentifikace tomu~také nezabrání, pouze~oddálí takovou situaci.
Některé hry v~praxi používají sofistikováné metody využívající detekci nelegální kopie hry, nebo~využití API herních obchodů (achievementy, odznaky, ID~účtu~atd.). Takové metody se~zdají~být účinné, ale~už~dávno se~lehce obchází pomocí triviální simulace odpovědí API.
Táto práce nabízí sledování ID~účtu hráče, který~hru zahrál a~jeho seznam stažených souborů, pokud~hra bude šířená na~platformě Steam. UUID (Unique User Identifier) účtu ví~pouze vlastník účtu, čili~je~to citlivá informace. Proto~před odesláním takových dat je~budeme vždy šifrovat asymetrickým klíčem (veřejným certifikátem webu ze~kterého~zároveň obsah stahujeme). Až~bude hráč chtít ohodnotit ve~hře obsah se~kterým~zahrál, API~zkontroluje zda~UUID~hráče na~Steamu opravdu vlastní hru, že~toto~UUID stahovalo tento~obsah z~našeho serveru a~že~toto~UUID ještě tento~obsah nehodnotilo.
Pokud~by~hra byla~šířená zdarma, bude~potřeba zavést omezení na~N~hodnocení denně pro~jedno~UUID, protože~bude~možné bezproblémově vytvářet falešné účty. Jinak, z~ekonomických důvodů, nám~nebude vadit, že~někdo bude~nakupovat hru víckrát, aby~víckrát nevhodně ohodnotil obsah.
Pořád bude možné reverse-engineerovat~API a~zapsat stažení libovolného obsahu pro~nějaký účet. Taková situace je~zcela zanedbatelná, jelikož~jedno~hodnocení má~malý vliv na~průměr ve~větších číslech.
\subsection{Problémové typy obsahu}
Již teď je možné předpovědět co~nebude kompletně fungovat nebo~nebude fungovat v~dostatečné kvalitě.
\begin{itemize}
\item Herní obsah tvořený ručně nástroji v~editoru vyžadují samostatné modely. Například animace objektů na~levelu tvořené v~Sequencer, tvorba~UI~v editorovém designeru, práce~se~zvuky v~Cue, statická tvorba úrovní a~tedy i~Landscape nebo~foliáž a~tvorba fyzických objektů (simulace tkáně, destrukce, pružnosti a~dalších~jevů). Pravděpodobně i~jiné, ale~víc technologií v~této práci využito nebylo.
\item Materiály též vyžadují vlastní model, ale~jsou tvořeny pomocí grafových prvků podobné blueprintům a~máme k~dispozici velké~množství dat pro~trénování takového modelu. V~základu můžeme vystačit si~bez~generování materiálů a~pouze vytvářet variace barev.
\item Grafické provedení generovaných objektů může~mít velký dopad na~výkon hry. Optimalizaci může provést další model, který~bude provádět retopologii\footnote{Retopologie je proces zjednodušení složité topologie 3D~objektu bez~značně viditelných změn.} a~pro~tvorbu kolizí lze~použít k-DOP\footnote{k-DOP (k-Discrete Oriented Polytope) je~jeden z~postupů obalování složitých 3D~objektu do~jednodušších tvarů.} algoritmus dostupný~v~UE.
\end{itemize}
\section{Grafika}
\label{sec:graphics}
\subsection{Statické objekty}
Engine disponuje modely základnich tvarů (krychle, koule, valec) a navíc lze zdarma vzít libovolné assety z balíčku Starter Pack nebo assety použité v demo projektech společnosti Epic Games. Přestože assety mají souvislý styl, většinou jsou zaměřeny na konkretní prostředí, a proto v další hře nemusí najít využití. Zřejmě lze nahrát ze souboru a nastavit vlastní modely, které lze ručně vytvořit nebo obstarat na libovolné online platformě.
V Unreal Engine verze 5 navíc přidali bohatý na funkcionality editor 3D modelů. Tvůrci propagují editor tak, že v něm lze vytvářet vlastní modely, protože množina funkcí dovoluje tvořit ,,hardsurface'' a ,,sculpting'' modely, ale aktuální provedení není dostačujíci a je v nesrovnání s dedikovaným softwarem. Netvořicí ale editovácí funkce na druhou stranu jsou užitečné a šetří čas. Ty umožňují například editování UV map, normalových vektorů ploch nebo změnu středového bodu modelu. ,,Best practice'' je využití tohoto editoru pouze v případě nouze (například časová výhoda nebo neexistence původního souboru) a jinak editovat původní importovaný soubor.
\paragraph{Použití cizích assetů} Rychlejší a občas jednodušší je získání assetů třetí strany. K tomu existují různé volně dostupné webové platformy. Jednou z takových platforem je FAB, který navíc má přímou integraci s UE 5. Objektivně FAB nemá dostatečně velký výběr assetů, jelikož nemá ani dostatečnou popularitu vývojářů a tvůrců. Přičinou jsou hlavně větší platformní marže z prodeje a sice jednoduchý, ale přesto nevýhodné licencování produktů pro kupující stranu.
Z finančních důvodu, v této praci byli využite pouze produkty dostupné zdarma. Neznamená to, že vše skončí pouhým stahnutím souborů a vložením do editoru. Často (v této práci všech 100%) assety nevypovídají žádnou známku optimalizace nebo profesionální tvorby. Modely tak mají některé normaly plošek invertované, středové body jsou nesmyslně mimo, textury a UV mapy je potřeba kompletně předělat. Nejhorší jsou primitivní objekty, které mají bezdůvodně velké množství vrcholů. V praxi se nachází i náhodné vrcholy bezúčelně existující v prostoru modelu.
\paragraph{Vlastní tvorba} Vlastnoručně jsou tvořeny modely ze staré verze hry a během vývoje této práce se pouze upravovali nebo tvořili textury. Standardem v oboru jsou obecně Maya nebo 3ds Max pro všeúčelové zpracování a úpravy, ZBrush pro sculpting a Substance Painter pro texturování objektu. V tomto projektu byl použit výhradně Blender a software pro editaci obrazkových formátů, které jsou k dispozici na internetu zdarma. Výsledný model lze často bez problémů rovnou využít v enginu.
\paragraph{Modeling a Sculpting} Nejprv se vytvaří tvar modelu. Toho se docíli pomoci modelování polygonů nebo sculptingu. Obě metody jsou velmi odlišné a stejně tak mají odlišný výstup.
Sculpting se provádí předevšim přes grafický tablet, kde pomoci různých 3D štětcu se natahují nebo smršťují vrcholy a celý proces napodobuje tvorbu sochy z plastického materiálu. Především takový přístup se používa pro tvorbu organických modelů nebo modelů s měkkým povrchem jako například živá stvoření, rostliny nebo oblečení.
Modeling na druhou stranu je obecnější zpracování vrcholů, hran a ploch. Tady se manuálně přidavají resp. odebírají a posouvají vrcholy. Navíc toto prostředí obsahuje funkce umožňující různé druhy chytrého instancování, množinových operací mezi objekty a zjednodušených simulací vrcholů a tedy i objektů. V takovém prostředí se tvoří především komplexní resp. hybrydní nebo tvrdé povrchy jako například nábytek, architektura nebo scény se sculpting modely.
Specifickou scuplting instancí v enginu je Landscape, de-facto siť vrcholů předem určené hustoty, kterou můžeme v editoru sculptovat a napodobovat křivý resp. různě vysoký teren. Manuální sculpting je pomalý a přináší slabé až nevyhovující výsledky. Proto místo sculptingu se používá výškova neboli height mapa, což je textura odstinů šedí, kde káždý pixel kóduje výšku v 3D prostoru. Potom stačí naskénovat nějaký povrch (například reálný teren) a během par minut získat skvělé výsledky. Stejné height mapy lze použivat i jako štětce v běžném sculptingu, pro specifické detalizace povrchů, a samotné height mapy lze získat na nějakých online platformach dokonce zdarma.
\paragraph{Animace} Animace se tvoři v dalším kroku modelingu. Pokud jsme předtím vytvořili model pomoci sculptingu, potřebujeme ho imortovat do modeling prostředí. Začíná se tvorbou umělé kostry z tzv. kostí a kloubů.
Klouby slouží pouze k specifikaci hierarchie mezi kosti, tak že nějaká kost propaguje vlastní modifikaci na všechny následující. Navíc specifikují střed rotačního bodu.
Kostí jsou samostatné absraktní označení pro nosič prostorových transformací, pro který můžeme přiřadit množinu vrcholů. Potom v logice nějáké animace stačí pouze posouvat určité kostí a nějaký předrendrovácí engine bude souvislé modifikovat přiřazené vrcholy. Navíc kostí často modifikují vrcholy podle předem úrčené váhy pro každý vrchol, čímz lze škálovat a skládat posuny různých kostí na úrčitých vrcholech. Jen je potřeba brát v úvahu, že skeleton animace neboli modifikace provedené předrendrovacím enginem jsou spouštěné na CPU, jelikož jsou řízeny nějakou logikou herního světa. Moderní procesory s instrukčními sady AVX a více jádry v takových úlohach dokažou předvádět poměrně skvělé až nadbytečné výkony.
V Unreal Engine 5 přidaly rozhraní pro tvorbu skeleton animací přímo v editoru. Předtím bylo možné pouze hotové animace naimportovat. Uvnitř editoru je přiliš mnoho způsobů jak režirovat animace (myšleno přehrávání, slepení přechodů, modifikace, skládání atd.) a lze se v tom jednoduše ztratit. V základu je předpokládáná tvorba state-machine, který bude přehrávat a cyklit jednotlivé animace v závislosti na větvení grafu a podmínkach hran.
Táto práce obsahuje pouze jednoduché animace postav, které byli přenesené ze staré verze. Animace hráče navíc disponuje immersivním otačením trupu a animace nohou jsou přitahovány k podlaze pomoci inverse kinematic metody.
Tráva vidítelná na úrovních 1 a 2 je animováná pomoci offsetů vrcholů, zmíněna v předchozí kapitole. V reálnem čase pod hráčem se generují částíce s barevným gradientem kódující offset v prostoru. Takové častíce jsou vidítelné pouze pro speciální render target menší velikosti -- sníma se pouze blízké okolí hráče. Materiál trávy následný render target interpretuje jako texturu, kterou interpoluje spolu s texturou jednoduchého proceduralního shaderu větru dostupného v enginu. Výsledkem je výkonná procedurální animace reakce na vítr a chůzi hráče v okolí objektu obsahující velké množství instancí resp. vrcholů.
\paragraph{Texturování} Za účelem texturování nejdřív potřebujeme objektu úrčit jedinečnou UV mapu, která bude mapovat plochy 3D modelu na normalizovaný prostor 2D obrázku. Často tvůrci mají na začatku problem pochopit o co se vlastně jedná a jak model rozložit. K tomu může napomoct myšlenka s rozlepováním resp. slepováním hran papírové figurky. Celý koncept UV mappingu je totožný se zpětným procesem tvorby například papírove krychlé, kde nějak rozbalenou krychli skládáme z jednoho uceleného kousku materiálu.
Když máme hotové mapování, můžeme volně přirazovat textury, které mohou úrčovat barvu vrcholů, modifikovat jejích normalový vektor, lesk, matnost, průhlednost a případně další. Přibližně do roku 2014, kdy vznikl Substance painter a dnes i jeho alternativy, jediný způsob texturování objektu bylo manuální ,,kreslení'' navrch vytvořené mapy. Dnes existují uživatelsky přijemné softwary, kde stačí kreslit rovnou komplexní materiály na povrch 3D modelu a aplikace sama obstará data všech textur.
V tomto projektu většína objektů nepoužívá diffusní textury a vybarvování modelů je tvořené pomocí vybarvování určítých skupin jeho ploch. Přesto jsou často využiváné normal mapy nebo masky průhlednosti. Bohůžel se můsely zahodit mapy pro tesselaci povrchů používáné v staré verzi projektu, jelikož s příchodem UE 5 tvůrci odebrali celou podporu tesselace kvůli technologii Nanite.
\paragraph{Exportování a Importování}
Workflow nebo pipeline exportu jsou standardizováné v profesionálních softwarech jako 3ds Max. Blender má pouze základní možnosti exportu, které je potřeba nejdřív přizpusobit spicifickému hernímu enginu. Potřebný minimum je zajištění správné interpretace dopředního a vrchního vektorů celého modelu. Taky se vyplatí:
\begin{itemize}
\item nastavit šablonu pro všechny budoucí projekty, tak aby modelovací program a herní editor sdíleli měřítko jednotek,
\item vyzkoušet jak se chová exportovaná hierarchie modelů v jednou souboru,
\item před exportem ověřit že všechny plošky modelu mají správně natočený normalový vektor (očekává se směr směrující na venek z objektu).
\end{itemize}
Unreal engine se jeví standardem herního oboru a proto verze 5 implementuje systém importovacích pipelines. Jedná se o mocný nástroj, který citelně zrychluje a sjednocuje postupy importování různých assetů nebo dokonce stejných assetů podle specifických filtrů (adresař assetu, typ, obsah, podřetězce názvu atd.). Subjektivně největší výhodou je předání zodpovědnosti specifického importu pouze osobam v týmu s odpovídajícími znalostmi. V praxi týmový senior založí pipelines pro často využíváné importy, tak aby odpovídali vnitřním firemním politikam a proto nováček v týmu resp. celý tým nemá žádné starosti při importu assetů.
\paragraph{Optimalizace} Ikdyž objekty jsou statické, stále vyžadují optimalizace. Takový lze najít i v tomto projektu:
\begin{itemize}
\item Instancování -- jíž zmínene v predchozí kapitole -- se využívá k tvorbě prostorů hustých na specifické modely. V UE se jedná o editovácí prostředek sousedicí vedle Landscape. Umožnuje pokročilé nastavení různých množín instancí a jejích parametry náhodného umístění.
\item Optimální topologie objektu pro minimalizaci vrcholů potřebných k vykreslování. Převážná většina modelů -- patří sem i získáné od třetích stran -- mají růčně přepracovanou topologii. Jedná se nejen o jednoduchou redukci nepotřebných vrcholů, ale taky použití techniky ,,lítající'' neboli floating geometrie. Tato metoda spočívá v protínání plošek, místo skutečného propojení vrcholů někde uprostřed, protože takové propojení by vyžadovalo podrozdělení jedne z ploch a tedy zbytečného zvětšení vrcholů (viz. \Cref{fig:FloatingGeometry}). Taktéž objekty mají redukovanou k-DOP kolizní topologii, pro urychlení výpočtů fyzických simulací.
\item Modely náročné na vykreslování nebo použité v instancování používájí LOD technologii (viz \Cref{fig:LodShowcase}). Nanite v práci nebyl využit.
\end{itemize}
Optimalizace textur je zprovozněná pouze hlídáním rozumných rozlišení. Jinak některé textury určitě je možné seskupit do jedné textury a vybírat potřebnou instanci podle UV mapy, což zrychlí přístup k datům.
Jiná grafická optimalizace není nijak řešená. Modely použité v instancování občas mohou vyvolat snižení výkonu, což by bylo potřeba už řešit nahrazením plnohodnotných modelů na kolekce průhledných textur (billboard metoda popsaná v další podsekci).
\subsection{Dynamické a procedurální objekty}
\paragraph{Sequencer} Dynamická animace se vytváří přímo v editoru objektu Sequencer. Taková animace dokáže modifikovát parametry objektů na úrovní a volát funkce v úrčité okamžiky. Objekty mohou být úrčené předem nebo Sequencer umí dynamicky vyhledát jejích reference před spuštěním. Pravě v tomto prostředí se tvoří cutscény nebo cyklické animace objektů na úrovní.
\paragraph{Procedurální generování} V předchozí verzi hry modél trávy byl vytvořen pomoci billboard metody, kde místo vykreslování 3D geometrie vegetace, se vykresluje nějaký průník ploch s texturou vegetace a průhledným pozadím. Tato technika je standardem ve video hrach, přesto nestačila k splnění dizajnových účelů. Buď vegetace musela být řídká, nebo stála nesmyslně velkého množství prostředků a tvořili se lag spikes.
Pro tento účel se implementovál nástroj pro editor, který podle zadaných parametrů je schopný vygenerovát náhodnou a hustou trávu z 3D trojúhelníků. Výsledný objekt má několikanásobně více geometrických dat než billboard metoda, přesto má skvělý výkon a navíc vegetace působí mnohem hustějí, má kvalitnější vzhled a lépe reaguje na offset vrcholů v shaderech (viz \Cref{fig:GrassShowcase}). Trik je v přenesení velké texturové zátěže s převýpočty průhledností na vykreslování jednotné a jednoduché 3D geometrie. K tomu generativní přístup umožňuje kvalitnější pokrytí ploch, jako například v tomto projektu, kde trává se generuje pouze v oblastech určité velikosti a pokryté úrčitým materiálem, tedy tráva se negeneruje na cestíčkach a mezi povolenou a zakázanou plochou je pozvolný přechod v velikosti jednotlivých stebel. Takový přístup byl okoukan ze hry Ghosts of Tsushima od studia Sucker Punch Productions, kde autoři si vytvořili podobný proprietární nástroj, jelikož chtěli dosáhnout husté kinematografické a stilistické vegetace na konzolích.
\begin{figure}
\centering
\includegraphics[width=1\linewidth]{img/GrassShowcase.pdf}
\caption{Ukázka procedurální (vlevo) a billboard (vpravo) metod pro vykreslování vegetace. Procedurální metoda má přibližně 6-krát menší render time a paměťové požadavky.}
\label{fig:GrassShowcase}
\end{figure}
\subsection{Osvětlení}
Nabízí se nám dostatečné možností při výběru druhů osvětlení. Teměř každý z ních sdíli podobné parametry, které mohou definovat, to jak světlo vypada nebo ovlivňuje prostředí. Vedle běžných dizajnových parametrů nechybí ani široká škála technických triků a úskalí.
\paragraph{Forward shading} Jelikož celá hra je ve forward shading režimu, -- podle tvůrců enginu obsolete funkcionalita čekájící na plný rework, -- některé technologie jsou značně omezeny nebo nefungují a zhoršuje se to s každou novou verzi. Například proto není použitelný Rect Light, ale můžeme to obejít tak, že Point Light zdroji přiřadíme IES Texturu, která nám specifikuje tvar světla. Stejně tak lze vytvořit vlastní Light Function, což je materiál definujicí co a jak světelný zdroj vyzařuje.
Navíc je potřeba pamatovat na reálná technická omezení forward shadingu, jako nejvýše tři zdroje světla na jeden objekt a nedostatek SSAO nebo SSR. S čímž stále si můžeme nějak poradit. Pokud je potřeba víc zdrojů světel ve scéně, máme k dispozici tři různé sloučitelné kanály, které můžeme specifikovat pro konkretní objekt a zdroj světla. A pokud nutně potřebujeme Ambient Occlusion mužeme použít Lightmass Volume pro jeho simulaci a stejně tak můžeme použít Planar Reflections pro simulaci odrazů.
\paragraph{Základy osvětlení na úrovni} Kromě bodových světel na úrovní teměř vždy chceme přidat globální osvětlení, který sestává z Directional Light a Sky Light.
Directional zdroj funguje jako jeden velký bodový zdroj pro celou scénu, který napodobuje funkci slunce a slouží primárně k vykreslování stínů.
Zdroj typu Sky Light taky může ovlivňovat stíny, ale primárně zobrazuje Sky Box texturu a modifikuje ambient složku celého osvětlení.
Navíc pokud chceme zobrazit venkovní prostory, je dobré použit nějkou formu mlhy jako je Ambient Fog. Mlha přidá pocit vělkého a neomezeného prostoru ikdyž ve skutečnosti je malý a uzavřený. Navíc mlha výborně skryje a tedy umožní horší detalizaci objektů v dálce, čímž efektivně zkratíme renderovácí čas snímku.
Nakonec se lze uchýlit k použítí Volume objektů, kterých je velké množství a z důvodů rozsahu práce nebudou podrobně probírany. Pomoci těchto prostorů lze specifikovat oblastí s úrčitými parametry, které nějak budou napovídat enginu potřebné optimalizace, nebo zapínat výkonostně náročné vykreslovácí technologie. Pro představu Lightmass Importance Volume specifikuje oblast, kde je potřeba propočítat větší počet odrazů paprsku světla než jednou.
\subsection{Post-Processing}
Post-Processing lze definovat přímo v kameře nebo v jíž zmíněných Volume objektech. Každá definice je de-facto materíál, který lze vrstvít mezi sebou. PP vyžaduje hlubší grafické znalosti, aby bylo možné vytvořit něco užitečnějšího než barevnou korekci. Zároveň kvůli tématice práce jen nastínim jak jsem naimplementoval PP materiály (viz \Cref{fig:PPShowcase}), které mají gamedizajnový důvod, ale nestíhly se použít.
\begin{figure}
\centering
\includegraphics[width=1\linewidth]{img/PPShowcase.pdf}
\caption{Ukázka post-process materiálů ve hře. Efekt deště jsem nedokázal rozumně zachytít.}
\label{fig:PPShowcase}
\end{figure}
\begin{itemize}
\item Plovoucí obrazovka - UV prostor obrazu se lehce zakřiví pomoci animováné šumové textury.
\item Námraza - obraz interpolujeme s animavánou texturou. Nejlépe použít nejký gradient uprostřed jako pmasku průhlednosti, aby hráč měl čistší vídění.
\item Stylová dálková kamera - obraz rozložíme na trochu sesunuté proužky dle rozlišení výstupu a zároveň stejné proužky střídavě zabarvíme. Nakonec proužky animujeme posunem nahoru resp. dolu.
\item Dešť - obraz rozložíme na jemnou mřížku a v blocích vygenerujeme různé kapky pomoci složení dvou turbulencí, každá z kterých bude mít animovanou lehce odlišnou rychlost posunu (aby kapky nebyly stalé stejné). K tomu znovu rozložíme obraz, ale teď na hrubou mřížku, kde animujeme svislé pády bloků s gradientním ocasem. Oba výstupy složíme, tak že hruba mřížka bude animováná maska průhlednosti, která name bude v nějaký okamžik otevírat pouze nějaké kapky. Nakonec přidame trochu distortion a výsledek použijeme jako modifikator UV výstupního obrazu.
\item Pixelizace - rozložíme obraz na potřebnou mřížku dle rozlišení a modifikujeme UV prostor výstupního obrazu.
\item Tavení pixelů - vytvoříme netriviální vertikální gradient s více přechody. Výsledek znečistíme přimím zaokrouhlováním a umozňováním dat, zpixelizujeme rozdělením na mřízku a výsledek použijeme k modifikaci UV prostoru výstupního obrazu a barevné korekci.
\item Slepota - výstupní obraz nahradíme vlastním, ve kterém zobrazuje pouze ohraníčení objektůs effektem emise. Ohraničení lze dosáhnout různymi způsoby a v tomto projektu je implementováné pomoci drobného posunu hloubkouvé textury ve všech směrech. Mezi posuny se provede rozdíl s originální hloubkou a sloučením rozdílu dostaneme hrany objektů.
\item Tužka a papíř - výstupní obraz nahradíme texturou ambient occlusion.
\end{itemize}
\subsection{Materiály a shadery}
Prestože materiály jsou omezené shadery, stále lze pomoci nich definovat mnoho různých a komplexních grafických funkcí. Základem jsou jednoduché barevné výstupy s triviálními parametry lesku, matnosti a emise. Může záležet na druhu objektu, pro který materiály tvoříme a tedy potřebujeme správně nastavit i druh materiálu, čimž následně dostaneme další předtím uzavřene výstupy a vstupu nebo některé naopka definovat nebudeme moct. Například za účelem optimaizace, můžeme přepnout material ze základního režimu osvětlení neboli Default Lit do neosvětleného režimu Unlit, čimž budeme moct definovat barvu objektu pouze emisní složkou, ale zmenšíme vykreslovací čas potřebný pro materiál.
V UE materiály resp. shadery mají mnoho globálních proměnných z kterých můžeme získat cenné údaje o enginu, scéně, vykreslovaném objektu, render buffrech a atd. Dokonce můžeme definovat vlastní globální nebo lokalní parametry a měnit jejich hodnoty v logice světa. Použití takových proměnných lze často vidět právě již zmíněných post-procesech, které přebírají a modifikují hodnoty výstupního zobrazení nebo jsou animaváné pomoci sinusové funkce s globálním parametrem herního času jako vstup.
Stojí za to zmínit, že některé materiály se hodí pouze na úrčitý druh objektů podle velikostí a umístění ve světě. Jedním z příkladu v teto hře je materiál skla. Původně navržený shader, který simuluje zalomování a vnitřní objem, skvěle funguje na drobných objektech jako lahve nebo skleněné střepy. Při použití na velkých skleněných plochach jako jsou okna, takové simulace vytváři nežádané artefakty nebo nefungují správně. Pro takové situace byl přidan duplicitní shader skla, který primarně vykresluje polopruhlednou barvu na povrchu objektu.
\paragraph{Funkce} V materiálech se lze zbavit duplicitního kódu, čímž zaroveň se zrychlí kompilace a běh shader variací. Implementoval jsem funkce:
\begin{itemize}
\item Škalování vstupné hodnoty podle vzdaleností od kamery.
\item Uniformní škalování a tiling textury nezávislé na velikosti objektu.
\item Získání obrysů objektů v podobě masky.
\item Rotace objektu ve směru kamery.
\end{itemize}
\subsection{UI}
Před Unreal Engine 5 teměř každý UI byl rastrový a v minulosti to ani nebyl problém. Stačilo vytvořit mip-mapy pro pár nejrozšířenějších rozlišení (HD, WSXGA a Full HD) a k tomu škálovat mip texturu menšího rozlišení na potřebný lehce větší výstup. Předtím hry nevypadaly zaostřeně takže nemuselo ani UI a dokonce to rozostření rastrového obrazu nebylo tak viditelné na displejích menší velikosti v té době. Dnes rastrové UI vytvaří příliš komplikací při tvorbě a vykreslování. Je potřeba mnoho mip-map ve velkých rozlišeních pro ostrý obraz na každém displeji, což vyžadují velké množství paměti a hlavně velkou propustnost při čtení dat (hlavně animací).
Jelikož původní projekt vznikal ve čtvrté verzi enginu, ale v době již velkých rozlišení, nebylo realistické pro dva vývojaře celé hry vypracovat přijatelné rastrové UI. Proto jsem tehdy a teď vytvořil všechny prvky pomoci černobílých poloprůhledných vektorových čtverců s transformacemi. Rastrové textury se používají pouze v podobě masek nebo gradientů, při použití kterých nejsou zřejmé škalovací artefakty.
Všechny kořenové UI prvky (overlay prvky, kontejner questů, kontejner nápověd ovládání, menu atd.) spravuje mnou implementováná třída Widget Manager. Táto třída slouží nejen jako high-level api pro všechny kořenové prvky resp. kontejnery, ale primárně slouží pro přehlednou udržbu referencí na takové prvky. Bez manuálního udržování reference, po instancování libovolného UI prvku, ji již nelze získat. Tedy nemuže prvek ani odstranit z obrazovky.
Každý prvek se instancijuje na začátku a udržuje se v paměti po celou dobu. Hlávním důvodem je naplňovaní prvků daty, které občas může trvát déle a tedy při dynamickém instancování vyvolavat zaseknutí aplikace.
\paragraph{Texty a překlady} V enginu je více druhů řetězců:
\begin{itemize}
\item FString - běžný řetězec pro reprezentaci UTF-16 se stejnou množinou funkcí jak u std::string. Je optimalizovaný pro konkatanace - 8 bajty.
\item FName - pouhý ukazatel na tabulku triviálních unikatních bajtových řetězců. Používa se pro pojmenování konstant v kódu nebo tagování objektů a je to doporučený textový format pro přenos přes internet.
\item FText - komplexní řetězec schopný překladat obsah podle tabulky nebo formatovat čísla podle pravidel jazyka.
\end{itemize}
Engine při instancování úrčitého FText nebo FString se snaží najít již existující instanci v paměti čimž se dost redukuje duplicita dat zejména v blueprintech.
Při tvorbě projektu jsem si dál záležet, aby veškerý text viditelný hračem byl překladatelný. Zároveň jsem dbal na zachování unikátností řetězců, aby se v tabulce překladů nevyskytovali duplicitní záznamy.
\section{Audio}
\label{sec:audio}
V tomto projektu jsem se zaměřil primárně na sprovoznění všech potřebných technologií potřebných k dokončení uceleného produktu a proto ve hře je značný nedostatek audia. Přesto je ale připravené široké technické zázemí, které obsahuje drobné ukázky:
\begin{itemize}
\item nastavení a ukládání hlasitostí různých kategorií audia,
\item prostorové přehrávání,
\item dynamický hudební doprovod
\item a možnost dabování dialogů spolu s hotovým procesem generování hlasů.
\end{itemize}
Optimalizace audia nebyla mezi cíle této práce, avšak nějaký základní systematický pravidla byli určeny.
\begin{itemize}
\item Použít streaming a kompresi dat kdekoliv to bude možné,
\item hudební doprovod je formatu mp3,
\item hlasy a jiné zvuky jsou formatu wav.
\end{itemize}
V budoucnu by také pomohlo zabalit všechny hlasy a jiné audio do samostatných datových balíčků neboli chunků. Aktuálně všechny herní assety jsou automaticky zabalené do pár ucelených balíčků, což může vyvolát sice drobné zpomalení načtení assetů, ale stále kriticky ovlivnit audio zážítek.
\subsection{Kategorie a parametry audio assetů}
\subsection{Dynamický hudební doprovod}
\subsection{Dabing dialogů}
\section{Tipy při vývoji v UE}
\label{sec:UETips}
\paragraph{Načítací obrazovka}
\paragraph{Skripty pro editor}
% Blueprunty a python
\paragraph{C++ typy a reflexe}
\paragraph{Kompilace a export projektu}
\section{Co se nestihlo nebo změnilo}