%\documentclass[../projekt.tex]{subfiles}
%\begin{document}

\newcommand{\blank}{\begingroup\color{red}TODO: \endgroup}
\newcommand{\recite}{\begingroup\color{red}[TODO]\endgroup}

\newcommand{\norm}[1]{\lvert #1 \rvert}
\newcommand{\gap}{\par\vspace{0.7 em}}

\newcommand\commentfont[1]{\textcolor{gray}{#1}}
\SetCommentSty{commentfont}

\SetKw{Break}{break}
\SetKw{Return}{return}

\pgfplotsset{compat=newest}

\chapter{Úvod}
\label{uvod}

S vyššími nároky na rozsah a~realismus digitálních světů nastává potřeba modelovat tím detailnější a~složitější krajiny. Pro vytvoření hrubého základu terénu již existují metody jak procedurální, tak ruční, a~to v~libovolném modelovacím programu. Dosažení uvěřitelných rysů ale vyžaduje exponenciálně více práce, a~to například simulací přírodních jevů, jež je tvoří.\par

Cílem projektu je obohatit program Blender skrze zásuvný modul o~simulaci vodní eroze. Řešení je cíleno na alternativní postup práce oproti současným rozšířením, tedy čistě pomocí textur, a~na urychlení algoritmů s~využitím grafické karty. Představený algoritmus také vytváří přídavná data dále využitelná ve stylizaci a~je oproti již existujícím rozšířením schopen transportu barev.\par

Inspirací pro projekt byl právě pokus vytvořit ručně rozsáhlé pohoří pro využití ve hře. Postup a~dosažitelný výsledek zde ale ovlivňovala limitovaná výpočetní síla. Daná zkušenost vedla k~dále prezentovanému přístupu, jež byl zaměřen na odlehčení práce s~modelem po erozi a~snížení výpočetních nároků.\par

Následující kapitola~\ref{teorie} je zaměřena na seznámení se současnými algoritmy vodní eroze a~existujícími řešeními, jež je možné ve spojení s~aplikací Blender použít. Také se zaobírá důležitými technologiemi využitými v~projektu. V~kapitole~\ref{navrh} je pak prezentován návrh uživatelského rozhraní a~poskytnuté funkcionality, včetně přehledu samotné simulace.

Kapitola~\ref{implementace} následně zachází do detailu implementace veškeré funkcionality rozšíření. Měření a~zjištěné limitace projektu jsou probrány v~kapitole~\ref{sec:stats}. Závěrečná kapitola~\ref{ch:end} také přestavuje souhrn plánu budoucí práce.


\chapter{Existující algoritmy a~použité technologie}
\label{teorie}

Centrálním prvkem vytvářeného modulu je samotný algoritmus simulace eroze, je tedy nutné první představit současné metody řešení daného problému, jejich varianty a~vlastnosti. Dále jsou popsány existující aplikace, či přímo zásuvné moduly do programu Blender, jež je možné použít. Kapitola je zakončena rozborem technologií a~nástrojů, jež byly použity v~řešení této práce, a~které budou dále odkazovány v~popisu návrhu a~implementace.\par\vspace{0.7 em}

\section{Vodní a~termální eroze}

Vodní eroze je geologický proces, při kterém dochází k~odnosu, transportu a~usazování hornin a~půdního materiálu vlivem vodních toků. Tento proces vzniká v~důsledku působení sil vody, které narušují pevnost a~stabilitu svahů, erozují půdní vrstvy a~odkládají materiál v~podobě sedimentů. Příklad vodní eroze je ilustrován v~obrázku~\ref{fig:water-erosion}\footnote{Ilustrace byla získána ze stráněk \href{https://www.agric.wa.gov.au/water-erosion/water-erosion-south-west-western-australia}{agric.wa.gov.au}.}.\gap

Vodní eroze se dělí na dva základní typy - povrchovou a~hlubinnou erozi. Povrchová eroze se vyskytuje na povrchu půdy, kde jsou erozní procesy působeny přímo na vrstvu půdy. Hlubinná eroze vzniká, když voda pronikne do podloží a~narušuje ho vlivem tlaku a~pohybu vody. Algoritmy, kterými se kapitola dále zabývá, se soustředí především na povrchovou vodní erozi~\cite{Dusan}.\gap

\begin{figure}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/theory/4378049 Water erosion.jpg}
    \caption{Ilustrace vodní eroze. Je vidět koryto vytvořené vodním tokem brázdy na jeho stěnách.}
    \label{fig:water-erosion}
\end{figure}

Termální eroze je další geologický proces, při kterém dochází k~odnosu, transportu a~usazování hornin a~půdního materiálu vlivem tepelných vlivů, zejména cyklické změny teploty. Tento proces vzniká v~důsledku rozdílné expanze a~kontrakce hornin vlivem změn teploty.\gap

Vrstva uvolněná teplotními cykly není pevná, částice jsou tedy schopny pohybu. Přesun uvolněného materiálu je zde uvažovován pouze díky gravitaci, v~přírodě dochází ale také k~přesunu pomocí vody či větru. Povrch vytvořený termální erozí se odvíjí od takzvaného sypného úhlu, což je maximální úhel vzhledem k~vodorovné ploše, jež je materiál schopen vytvořit. Ilustrace simulace termální eroze je uvedena v~obrázku~\ref{fig:thermal-erosion}\footnote{Zdrojem obrázku je blog \href{https://www.world-machine.com/blog/?p=542}{world-machine.com}.}.\gap

\begin{figure}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/theory/thermal.jpg}
    \caption{Ilustrace simulace termální eroze. Svah uvolněného materiálu nabývá maximálně sypného úhlu.}
    \label{fig:thermal-erosion}
\end{figure}

\section{Celulární automaty}

První, ale stále používanou, metodou je simulace vodní eroze pomocí celulárních automatů~\cite{Musgrave}. Celulárním automatem je zde označován časově i~prostorově diskrétní model pracující nad dvoudimenzionálním polem buněk, nejčastěji takzvanou výškovou mapou. Jedná se o~pravoúhlou mřížku, kde v~každé buňce je uložena výška bodu, kterému buňka odpovídá. Výšek pro každou buňku, nebo dalších hodnot, jako je množství či rychlost vody, může být ale v~závislosti na algoritmu definováno více.\par
Samotná eroze pak probíhá změnou stavu všech buněk v~iteracích algoritmu. Pro výpočet změn je využíváno okolí vyhodnocované buňky, a~to nejčastěji buď Moorovo okolí, zde dále označovano jako osmiokolí, nebo Von Neumannovo okolí, dále značeno jako čtyřokolí. Jejich rozdíl je ilustrován v~obrázku~\ref{fig:neighbor}.\gap

\begin{figure}[H]
    \centering
    \begin{subfigure}[t]{0.35\textwidth}
        \centering
        \includegraphics[width=0.8\linewidth]{obrazky-figures/theory/moore.pdf}
        \caption{Moorovo okolí}
        \label{fig:moore}
    \end{subfigure}
    \begin{subfigure}[t]{0.35\textwidth}
        \centering
        \includegraphics[width=0.8\linewidth]{obrazky-figures/theory/neumann.pdf}
        \caption{Von Neumannovo okolí}
        \label{fig:von_neumann}
    \end{subfigure}
    \caption{Ilustrace okolí buňky. Šrafovaně jsou značeny buňky patřící do okolí a~bíle je zakreslena zkoumaná buňka.}
    \label{fig:neighbor}
\end{figure}

\section{Simulace pomocí rozpouštění}
Jeden z~možných algoritmů eroze využívá faktu, že pomalu tekoucí voda se vsakuje do zeminy a~vytváří pohyblivou vrstvu materiálu. Daná vrstva se nazývá regolit a~chová se jako hustá kapalina. Jejím přesunem je možné dále simulovat ukládání v~nižších oblastech terénu \cite{Stava}.\gap
Dále uvedený model je nejčastěji aplikovatelný pro dna jezer či pomalých řek. Svým vyhlazovacím účinkem se značně liší od simulací založených na síle, jež jsou rozebrány v~další kapitole~\ref{sec:sim-pipe}. Zde uvedená metoda byla představena v~práci Beneš \textit{et al.} a~rozděluje proces na následující kroky \cite{Benes}:
\begin{enumerate}
    \item Přísun vody
    \item Eroze materiálu a~zachycení do vody
    \item Transport vody i~materiálu
    \item Uložení sedimentu na nové pozici
\end{enumerate}
\gap
\noindent Každá buňka v~simulaci má definované tři hodnoty, výšku terénu $b$, výšku sloupce vody $d$ a~množství nesené látky $s$ v~daném bodě. Vzdálenost buňek je předpokládána jako jednotková, stejně jako kroky v~čase. Jejich interpretace je zobrazena v~ilustraci~\ref{fig:benes_columns}.\gap

\begin{figure}[H]
    \centering
    \includegraphics[width=0.25\linewidth]{obrazky-figures/theory/benes-column.pdf}
    \caption{Ilustrace zobrazuje uspořádání výšek terénu $b$, vody $d$ a~celkové výšky $h$ ve sloupcích.}
    \label{fig:benes_columns}
\end{figure}

\noindent Prvním krokem simulace je přísun vody v~čase $t$, jež odpovídá zvýšení sloupců vody:\par
\begin{equation}
d_{t+1} = d_t + K_r
\end{equation}\gap

Zde je $K_r$ konstanta, jež má význam stejně silného deště po celé oblasti simulace. Pro realističtější simulaci deště lze konstanta nahradit funkcí závislou na pozici. Větší množství vody by mělo být generováno ve středu simulace a~případné variace lze dosáhnout fraktalními funkcemi~\cite{Benes}. Pozemní zdroje vody jako jsou řeky či jezera lze reprezentovat podobným způsobem.\gap

Limitace množství vody v~modelu je dále zajištěna vypařováním, jež v~modelu pomocí konstanty vypařování $K_e$ a~původního množství vody $d_0$ vychází z~následující rovnice:\gap
\begin{equation}
d_t = d_0e^{-K_et}
\end{equation}\gap

\noindent Daný exponenciální model nedovoluje celkovému vyschnutí, tedy dosáhnutí nulové výšky, jež může být žádoucí. Za tímto účelem autor definuje prahovou hodnotu $T$ a~upravený výpočet uveden v~rovnici~\ref{eq:benes_water}.
 
\begin{equation}
d_t =
\begin{cases}
    0,& \text{pokud } d_0e^{-K_et} < T\\
    d_0e^{-K_et} - T,& \text{jinak} 
\end{cases}
\label{eq:benes_water}
\end{equation}\gap

\noindent Pokud výška sloupce nedosahuje prahové hodnoty, pak je nastavena na nulu. Pro změny v~jednotlivých iteracích při konstantních krocích lze pak hodnotu $e^{-K_e}$ předpočítat a~jednoduše aplikovat násobením.
Dalším krokem je depozice a~eroze materiálu. Klíčovou hodnotou pro rozhodování mezi danými procesy tvoří úroveň nasycení, jež je definována následovně:\par
\begin{equation}
S_t = K_sd_t
\end{equation}\gap

kde $K_s$ je koeficient nasycení, který udává množství materiálu, jež může nést jedna jednotka vody. Je-li nesené množství látky $s_t$ vyšší než maximální nasycení $S_t$, pak dochází k~ukládání materiálu. V~opačném případě je materiál odebrán z~terénu a~přidán k~rozpuštěnému množstí. V~obou případech platí:\par
\begin{equation}
b_{t+1} = b_t + \left(s_t-S_t\right)
\end{equation}\gap

\noindent Rychlost ukládání i~eroze materiálu lze upravit pomocí koeficientů. Dané hodnoty mohou být zásvislé na pozici v~mapě, čímž lze simulovat různé materiály. Posledním krokem je přesun kapaliny a~rozpuštěného materiálu. Za tímto účelem je definována celkovou výšku buňky $h$ jako součet výšek terénu a~sloupce vody:\par
\begin{equation}
h = b + d
\end{equation}\gap

\noindent K~přesunu materiálu dochází v~osmiokolí kolem zkoumané buňky. Pro každou z~nich je zjištěn rozdíl výšek $\Delta h = h-h'$, kde $h'$ je výška sousední buňky. K~přesunu dochází pouze do buněk, jež nejsou výše, tedy $\Delta h \leq 0$.\gap
Množství přesunuté každé sousední buňce by mělo odpovídat rozdílům výšek vzhledem ke zkoumanému bodu. Výšky sousedů zde budou zapisovány jako $h_i$, kde $i \in \{0,1,...7\}$, na přesném pořadí zde ale nezáleží. V~ilustraci~\ref{fig:benes_neighbour} je uveden příklad pořadí indexace buněk.\gap

\begin{figure}
    \centering
    \includegraphics[width=0.3\linewidth]{obrazky-figures/theory/neighbour.pdf}
    \caption{Příklad indexace sloupců v~osmiokolí}
    \label{fig:benes_neighbour}
\end{figure}

Nejdříve je získán součet výšek sousedů $sum$, jež jsou níže, nebo na stejné úrovni. Výpočet je uveden v~rovnici~\ref{eq:benes_sum}.\gap

\begin{equation}
sum = \sum_{i=0}^{7} 
\begin{cases}
    \Delta h_i,& \text{pokud } \Delta h_i >= 0\\
    0,& \text{jinak}
\end{cases}
\label{eq:benes_sum}
\end{equation}\gap

\noindent Pro součet i~následující výpočet je také možné použít rozdíly výšek sousedů a~vyhodnocované buňky namísto celkových výšek. Řešení by pak silněji preferovalo nejnižší sousedy. Daný součet je dále využit k~proporcionálnímu rozdělení vody mezi sousedy v~rovnici~\ref{eq:benes_water_sum}.\par
\begin{equation}
\Delta w_i = \Delta w\frac{\Delta h_i}{sum}
\label{eq:benes_water_sum}
\end{equation}\gap

kde $\Delta w_i$ je přísun vody pro souseda o~indexu $i$ a~$\Delta w$ je množství vody, jež středová buňka může poskytnout.
Autor v~práci neuvádí přesný výpočet daného množství, lze ale například uvažovat případ pro každé dvě buňky dle ilustrace~\ref{fig:benes_transport}.\par

\begin{figure}
    \centering
    \begin{subfigure}[b]{0.45\textwidth}
         \centering
         \includegraphics[width=0.75\textwidth]{obrazky-figures/theory/benes-difA.pdf}
         \caption{Vyrovnání sloupců vody}
         \label{fig:benes_transport_eq}
     \end{subfigure}
     \begin{subfigure}[b]{0.45\textwidth}
         \centering
         \includegraphics[width=0.75\textwidth]{obrazky-figures/theory/benes-difB.pdf}
         \caption{Přesun celého sloupce vody}
         \label{fig:benes_transport_full}
     \end{subfigure}
    \caption{Případy přesunu vody}
    \label{fig:benes_transport}
\end{figure}

\noindent Dále jsou sousední výšky sloupců označeny pomocí $h'$ a~$w'$. Vyrovnanou výšku hladiny středové buňky $\hat{w}$ pak lze vypočítat jako:\par
\begin{equation}
\hat{w} = \frac{h + w + h' + w'}{2} - h
\end{equation}\gap

\noindent Je-li menší než nula, pak je veškerá voda přesunuta níže. Jednotlivé přesuny lze sečíst a~případně nastavit na celý sloupec vody $w_t$, pokud jej součet přesahuje. Tímto krokem je završena celá iterace algoritmu a~opět může začít další přísunem vody.\gap

Prezentovaný model představuje řešení o~nízkých paměťových nárocích, jež lze použít v~kombinaci s~dalšími metodami. Odlišným řešením a~adaptací na použítí s~paralelním zpracováním se zabývá následující kapitola.

\section{Simulace pomocí sil a~rour}
\label{sec:sim-pipe}

Předchozí algoritmus se zaměřuje na pomalu tekoucí či stojatou vodu, pro přesnější popis vlivu řek či deště je ale třeba zavést několik rozšíření. Zde uvedený model byl představen v~práci Mei \textit{et al.} \cite{Mei} a~jeho hlavním poznatkem je efekt síly, tedy rychlosti a~množství, tekoucí vody na terén. Pro účely paralelizace výpočtu a~využití grafické karty model také zavádí několikaprůchodový algoritmus a~takzvané virtuální roury (anglicky \textit{pipes}) pro výměnu hodnot mezi buňkami.\gap

K předchozím hodnotám buněk, tedy výšce terénu $b$, sloupci vody $d$ a~množství sedimentu $s$, zavádí model dvourozměrný rychlostní vektor $\Vec{v}$ a~výtok $f$ (anglicky uváděno jako \textit{outflow flux}), který reprezentuje rychlost vody předávané sousedním buňkám. Model bude pracovat s~čtyřokolím, výtok se tedy skládá ze čtyř hodnot $f^L$, $f^R$, $f^T$ a~$f^B$, jež odpovídají levému, pravému, hornímu a~dolnímu spojení. Roury modelu ilustruje obrázek~\ref{fig:mei_pipes}.

\begin{figure}
    \centering
    \includegraphics[width=0.3\linewidth]{obrazky-figures/theory/pipes.pdf}
    \caption{Propojení rour prostřední buňky s~okolím}
    \label{fig:mei_pipes}
\end{figure}

 \noindent Postup simulace je dále třeba rozšířit o~práci s~rychlostním polem. Kroky, jež jsou jednotlivě dokončeny zcela před počátkem dalšího, jsou rozděleny následovně:

\begin{enumerate}
    \item Přísun vody
    \item Aktualizace toků a~pole rychlosti
    \item Výpočet eroze a~uložení sedimentu na základě rychlostí
    \item Sediment pozůstalý ve vodě je transportován dle rychlosti
    \item Vypařování vody
\end{enumerate}

\subsection{Přísun vody}

Pro výpočet nového sloupce vody vyžaduje model několik výpočtů. Mezikroky zde budou značeny $d_A$ a~$d_B$. Proměnnými $x$ a~$y$ jsou značeny souřadnice zkoumané buňky. Pro první úpravu sloupce přidáním vody pak platí:\par
\begin{equation}
d_A\left(x,y\right) = d_t\left(x,y\right) + r_t\left(x,y\right)
\end{equation}\gap

 \noindent kde $\Delta t$ je časový krok simulace a~$r_t$ je funkce určující příchozí množství vody. Podobně jako v~předchozím modelu může reprezentovat různé koncentrace deště, pozice vodních ploch nebo i~záviset na čase.\gap

\subsection{Výtoky}

Po dokončení přísunu vody je dalším krokem simulace výpočet výtoků. Na rychlost vody má v~modelu vliv jak gravitace a~výškové rozdíly, tak nastavitelné parametry roury mezi buňkami. Pro spoj je uvažován obsah průřezu roury $A$ a~pro reprezentaci velikosti modelu je zavedena délka mezi buňkami $l$.\par Délky mohou být různé pro různé osy, je-li například obdélníkový terén vyhodnocován na čtvercovém poli. Hodnotou průřezu lze limitovat rychlost vody ve spoji, může být tedy konstantní či závislá na čase dle potřeb modelu. V~práci Šťáva \textit{et al.} je například využita hodnota $l^2$. Pro mezivýpočet výtoku levého spojení v~dalším kroce $\hat{f}$ pak platí~\cite{Stava}:\par
\begin{equation}
\hat{f}^L\left(x,y\right) = \max\left(0, f_t^L\left(x,y\right) + \Delta t \cdot a~\cdot \frac{g \cdot \Delta h^L\left(x,y\right)}{l}\right)
\end{equation}\gap

\noindent kde $g$ je tíhové zrychlení a~$\Delta h^L\left(x,y\right)$ je rozdíl výšek mezi zkoumanou a~její levou buňkou, tedy $\left(x-1,y\right)$.\gap

\noindent Výška buněk je opět počítána jako součet terénu a~sloupce vody, tedy $d_t + b_t$. Výtok bude nabývat vždy kladných hodnot, neboť přesun vody opačným směrem bude uložen ve zdrojové sousední buňce. Daný vzorec byl odvozen z~práce O'Brien \textit{et al.} \cite{OBrien} bez uvažování externího tlaku na kapalinu. Ostatní strany mají analogické rovnice. Pro proporcionální rozdělení toků dále je zaveden faktor $K$ následovně:\par
\begin{equation}
K = \min\left(1, \frac{d_A}{\Delta t} \cdot \frac{l_Xl_Y}{\hat{f}^L + \hat{f}^R + \hat{f}^T + \hat{f}^B}\right)
\end{equation}\gap

\noindent kde $l_X$ a~$l_Y$ jsou délky buněk na odpovídajících osách (a tedy i~vzdálenosti buněk) a~$d_A$ je mezihodnota sloupce vody. Výsledné výtoky jsou násobkem mezivýpočtu a~získané hodnoty $K$, tedy:\par

\begin{equation}
f_{t+\Delta t}^L\left(x,y\right) = K \cdot \hat{f}_{t+\Delta t}^L\left(x,y\right)
\end{equation}\gap

\noindent a~podobně pro ostatní směry.

\subsection{Úprava sloupce vody}

Dalším krokem algoritmu je zjištění objemů k~přesunutí a~odvození druhého mezivýsledku sloupce vody. Rozdíl objemu vody je pomocí výtoků vyjádřen následovně:\par
\begin{equation}
    \Delta V\left(x,y\right) = \Delta t \cdot \left(\sum f_{in} - \sum f_{out} \right)
\end{equation}\gap

\noindent kde $f_{in}$ jsou výtoky v~sousedních buňkách směrem ke zkoumanému bodu a~$f_{out}$ jsou výtoky zkoumané buňky. Suma vstupů je tedy:\par
\begin{equation}
    \sum f_{in} = f_{t+\Delta t}^R\left(x-1,y\right) + \dots + f_{t+\Delta t}^B\left(x,y+1\right)
\end{equation}\gap

\noindent Výstupní tok je součtem výtoků zkoumané buňky:\par
\begin{equation}
    \sum f_{out} = \sum_{i=L,R,T,B} f^i_{t+\Delta t} \left(x,y\right)
\end{equation}\gap

\noindent Uvažujeme-li obsah buňky jako $l_X\cdot l_Y$, pak změna sloupce a~druhý mezivýpočet $d_B$ lze z~rozdílu objemu vyjádřit jako:\par

\begin{equation}
    d_B\left(x,y\right) = d_A\left(x,y\right) + \frac{\Delta V\left(x,y\right)}{l_Xl_Y}
\end{equation}\gap

\subsection{Úprava pole rychlosti}

Pro určení rychlosti vody je nejdříve uvažováno množství protékající zkoumaným bodem určitým směrem, zde značené $\Delta W$, jež je rozděleno na jednotlivé osy. Pro směr osy $X$ je pak průtok vody (v objemu za jednotku času) vyjádřen následovně:\par

\begin{equation}
    \Delta W_X = \frac{1}{2} \cdot \left(f^R\left(x-1,y\right) - f^L\left(x,y\right) + f^R\left(x,y\right) - f^L\left(x+1,y\right) \right)
\end{equation}\gap

\noindent Kladné hodnoty $\Delta W$ tedy vyjadřují dominantní tok směrem vpravo na ose $X$. Pomocí průměrné výšky sloupce vody $\overline{d}$ a~délky buňky v~druhé ose $l_Y$ je možné určit obsah průřezu tekoucí vody a~komponentu rychlosti $u$ v~čase $t+\Delta t$ lze pak získat podílem:\par

\begin{equation}
    u_{t+\Delta t} = \frac{\Delta W_X}{l_Y\cdot\overline{d}}
\end{equation}\gap

\noindent Při uvážení rovnoměrného přesunu vody mezi buňkami za časový krok lze průměrnou výšku sloupce vody zapsat $\overline{d} = \frac{1}{2} \cdot\left(d_A + d_B\right)$, neboť $d_A$ byla výška před výměnou. Obdobným postupem je pak možné vyjádřit komponentu $v$ pro osu $Y$.

\subsection{Eroze a~ukládání sedimentu}

Uváděný model využívá empirickou metodu pro výpočet kapacity vody danou rovnicí \cite{Simons}\footnote{Rovnice je uvedena na stránce 760 jako $S\cdot q \cdot \overline{u}$, kde $S$ je konstanta, $q$ je tangens úhlu povrchu a~$\overline{u}$ je průměrná rychlost vody. Změna na sinus úhlu byla provedena v~Mei \textit{et al.} pro zjednodušení výpočtu.}:

\begin{equation} \label{eq:capacity_homogeneous}
C\left(x,y\right) = K_c \cdot \sin\left(\alpha\left(x,y\right)\right)\cdot\norm{\Vec{v}\left(x,y\right)}
\end{equation}\gap

\noindent kde $\alpha$ vyjadřuje náklon povrchu vzhledem k~vodorovné ploše, $\Vec{v}$ rychlost vody a~$K_c$ konstantu kapacity. Pro ploché terény, kde rychlost sice může nabývat vyšších hodnot, ale náklon se blíží nule, také autor uvádí možnost zavedení prahové hodnoty náklonu. Namísto $\alpha\left(x,y\right)$ by pak bylo použito:\par

\begin{equation}
    \max\left(T_\alpha, \alpha\left(x,y\right)\right)
\end{equation}\gap

\noindent kde $T_\alpha$ je uživatelem zvolené minimum. Nahrazení by zajišťovalo alespoň nějakou úpravu terénu. Po získání kapacity lze hodnotu porovnat se současně neseným sedimentem, reprezentovaným proměnnou $s_t$, s~mezivýsledkem $s_A$. Platí-li, že $C > s_t$, pak dochází k~rozpuštění části terénu do vody:
\begin{equation} \label{eq:mei_erosion}
\begin{split}
b_{t+\Delta t} = b_t - K_s\left(C-s_t\right)\\
s_A = s_t + K_s\left(C-s_t\right)
\end{split}
\end{equation}\gap
\noindent kde $K_s$ je konstanta eroze. Pokud naopak platí $C \leq s_t$, potom dochází k~sedimentaci:
\begin{equation} \label{eq:mei_deposition}
\begin{split}
    b_{t+\Delta t} = b_t + K_d\left(C-s_t\right) \\
    s_A = s_t - K_d\left(C-s_t\right)
    \end{split}
\end{equation}\gap
\noindent kde $K_d$ je konstanta ukládání sedimentu.

\subsection{Přesun vody, sedimentu a~vypařování}

Transport materiálu v~modelu vychází z~rovnice advekce pro nestlačitelnou kapalinu, daného rovnicí:\par
\begin{equation}
    \frac{\partial s}{\partial t} = -\left(\Vec{v}\cdot\nabla s\right)
\end{equation}\gap

\noindent Numerických řešení rovnice je více. V~modelu Mei \textit{et al.} je pro výsledné množství sedimentu $s_{t+\Delta t}$ použit vzorec~\cite{Mei}:

\begin{equation}
s_{t+\Delta t}\left(x,y\right) = s_A\left(x-u\cdot\Delta t, y - v\cdot\Delta t\right)
\end{equation}\gap

\noindent kde $u$ a~$v$ jsou komponenty $X$ a~$Y$ rychlosti vody. Namísto dopředného přesunu sedimentu tedy vyhledává zpětně v~čase. Neleží-li takto vytvořený bod přímo na mřížce, pak model využívá interpolace z~okolních buněk. Alternativním řešením diferenciální rovnice je uvedeno například v~práci Šťáva \textit{et al.}, jež využívá metody zvané \textit{Semi-Lagrangian MacCormack}, jež má vyšší stupeň přesnosti a~je stále stabilní \cite{Selle}. Posledním krokem modelu je vypařování vody. Pro mezivýsledek sloupce vody $d_B$ je výsledná hodnota získána dle rovnice~\ref{eq:mei_water}, kde $K_e$ je konstanta vypařování.\par

\begin{equation}
d_{t+\Delta t}\left(x,y\right) = d_B\left(x,y\right) \cdot \left(1-K_e\cdot\Delta t\right)
\label{eq:mei_water}
\end{equation}\gap

\section{Vícevrstvé modely}
Výše zmíněné metody se zabývají pouze homogenním materiálem. Ve skutečném světě se ale terén skládá z~více vrstev, jež jsou různě ovlivněny procesem eroze. Rozšířením algoritmu z~předchozí kapitoly se zabývá práce Šťáva et al. \cite{Stava}, jež přidává pro každou buňku nová pole. Sloupec buňky pak vypadá jako v~ilustraci~\ref{fig:stava_columns}.\gap

\begin{figure}
    \centering
    \includegraphics[width=0.25\linewidth]{obrazky-figures/theory/stava-columns.pdf}
    \caption{Sloupce materiálu zobrazující několik vrstev terénu $b$}
    \label{fig:stava_columns}
\end{figure}

Každá vrstva materiálu má tedy vlastní tloušťku pro každou buňku uloženou v~polích. Tloušťka pro vrstvu $k$ je zde značena jako $b_k$. Celkovou výšku buňky lze pro sloupec vody $w$ získat součtem se všemi vrstvami:\par
\begin{equation}
    h\left(x,y\right) = w\left(x,y\right) + \sum_k b_k\left(x,y\right)
\end{equation}\gap

\noindent Odlišnou sílu eroze v~závislosti na vrstvách model reprezentuje odlišnou kapacitou sedimentu. Předchozí vzorec pro kapacitu~\ref{eq:capacity_homogeneous} upravuje následovně:\par

\begin{equation} \label{eq:capacity_adj}
T_k\left(x,y\right) = C_k\cdot\norm{v\left(x,y\right)}\cdot\sin\left(x,y\right)
\end{equation}\gap

\noindent kde konstanta $C_k$ je definována pro vrstvu $k$ a~$\sin\left(x,y\right)$ je sinus úhlu povrchu na daných souřadnicích. Dále je třeba zakomponovat vrstvy do samotné úpravy terénu, tedy eroze a~depozice.\gap

K ukládání materiálu dochází v~případě, že množství rozpuštěného sedimentu přesahuje kapacitu nejvyšší vrstvy, tedy $s_t\left(x,y\right) > T_{top}\left(x,y\right)$. Výpočet uloženého materiálu se řídí stejným vzorcem jako je vzorec~\ref{eq:mei_deposition}, dochází ale k~depozici pouze do nejvyšší vrstvy, jež by měla reprezentovat vždy sediment nebo nejlehčí materiál ve sloupci.\gap
Přesahuje-li kapacita rozpuštěný sediment, pak dochází k~erozi vrstev povrchu. Zde je ale třeba dbát na vyšší povrch, jež byl již rozpuštěn. Práce Šťáva et al. zavádí upravenou kapacitu sedimentu $\hat{T}_k$ pro zkoumanou úroveň:\par
\begin{equation}
    \hat{T}_k\left(x,y\right) = T_k\left(x,y\right) - \sum_{i=k+1}^{top}b_i
\end{equation}\gap

\noindent kde $k$ je index zkoumané úrovně a~$top$ je index té nejvyšší. Výsledná hodnota tedy vyjadřuje maximální hloubku, kam se dostane voda a~tedy kterou rozpustí, po proniknutí všemi vyššími vrstvami. Sloupec buňky je pak procházen od nejvyšší vrstvy a~je postupně porovnávána upravená kapacita s~rozpuštěným sedimentem $s$.\gap

Proces je ilustrován v~algoritmu~\ref{alg:multilayer}, jež odstraní část vrstvy a~přidá ji do neseného sedimentu. Pokud už na další erozi nemá voda kapacitu, pak je cyklus zastaven.\par

\begin{algorithm}
\caption{Postupná eroze vrstev\label{alg:multilayer}}
\SetKwFunction{Erode}{Erode}
\For{$k \gets top$ to $0$} {
    \eIf{$\hat{T}_{k}\left(x,y\right) < s\left(x,y\right)$} {
       \Erode{}
    } {
       \Break
    }
}
\end{algorithm}\gap
    
\section{Simulace termální eroze}

Pomocí celulárních automatů lze rovněž simulovat termální erozi. Model pro tento proces je použitelný i~pro přemísťování uloženého sedimentu. Práce autora J. Balázse se zabývá právě simulací termální eroze na grafické kartě \cite{Balazs}.\gap

Daný algoritmus termální eroze využívá systému rour stejně jako výše představený model vodní eroze~\ref{sec:sim-pipe}. Prvním krokem algoritmu je zjištění maximálního množství materiálu, které je buňka schopná předat sousedům. Pro výpočet je zaveden rozdíl výšek $H$ mezi zkoumanou buňkou a~nejnižším sousedem. Platí tedy:\par
\begin{equation}
    H = \max\left\{b-b_i; i = 1,\dots,8\right\}
\end{equation}\gap

\noindent Množství, které lze následně přesunout je dáno rovnicí~\ref{eq:thermal_amt_simple}. Rovnice~\ref{eq:thermal_amt} ilustruje výpočet v~případě, že je třeba použít lokální tvrdost materiálu $R$. Oba výpočty využívají plochu buňky $a$. Dále lze upravit přesunuté množství pomocí konstanty $C_t$.\par

\begin{equation}
    \Delta S = \frac{a \cdot H}{2}
    \label{eq:thermal_amt_simple}
\end{equation}

\begin{equation}
    \Delta S = \frac{a \cdot H \cdot \Delta t \cdot C_t \cdot R_t\left(x,y\right)}{2}
    \label{eq:thermal_amt}
\end{equation}\gap

\noindent Další částí výpočtu je zjištění množství materiálu, které v~jednotlivých rourách bude přesunuto. Za tímto účelem autor zavádí množinu $A$, která obsahuje sousedy buňky, jež jsou níže a~jejichž úhel je vyšší než sypný úhel materiálu. Podmínka je zobrazena v~rovnici~\ref{eq:thermal_talus}.\gap

\begin{equation}
    \forall n \in A: b > b_i \land \frac{b-b_n}{l}> R\left(n\right) \cdot C_a + C_i
    \label{eq:thermal_talus}
\end{equation}\gap

\noindent V~rovnici~\ref{eq:thermal_talus} je $b$ výška zkoumané buňky, $b_n$ výška souseda a~$l$ je vzdálenost mezi danými buňkami. Sypný úhel materiálu ovládají konstanty $C_a$ a~$C_i$. Pro lokální tvrdost povrchu zahrnuje rovnice funkci $R$.\gap

Podobně jako u~vodní eroze jak pak třeba rozdělit proporcionálně množství materiálu, které bude odebráno. Vypočtené množství materiálu je násobeno podílem výšek ovlivněných sousedů a~jejich sumy.\par

\begin{equation}
    \Delta S_i = \Delta S \frac{b_i}{\sum_{b \in A} b}
\end{equation}\gap

\noindent Druhou fází termální eroze je úprava výšek povrchu. Stejně jako v~modelu vodní eroze v~kapitole~\ref{sec:sim-pipe} je výsledný rozdíl materiálu získán součtem množství procházejícím rourami.

\section{Simulace částicemi}
\label{sec:particle_theory}
Celulární automaty nejsou jediný způsob využití výškových map pro účely eroze. Namísto abstrakce protékajícího množství vody se výše zmíněné mechanizmy dají aplikovat na jednotlivé částice pohybující se v~daném poli. Autor H.T. Bayer ve své práci zavádí právě model vodní eroze simulující jednotlivé kapky \cite{Bayer}.\gap

Pro reprezentaci každé částice jsou definovány dvourozměrné vektory pozice $p$ a~směru pohybu $dir$. Dále je zavedena rychlost pohybu $v$, neboť směr je zaveden jako normalizovaný vektor, tedy vždy bude platit $\norm{dir} = 1$. Každá kapka také může mít různý objem vody $w$ a~podobně jako u~celulárních automatů je definováno množství neseného sedimentu $s$.\gap

Principem algoritmu je pohyb částice směrem největšího sklonu terénu a~skládá se z~následujících kroků:

\begin{enumerate}
    \item Rozmístění částic na povrchu
    \item Výpočet nového směru a~pozice
    \item Eroze nebo depozice
    \item Určení nové rychlosti
    \item Vypařování
\end{enumerate}\gap

\noindent Kroky 2 až 5 se opakují dokud částice neopustí simulovanou oblast nebo není zachycena v~některém lokálním minimu povrchu, tedy dosáhne nulové rychlosti. Pro omezení délky simulace je také možné nastavit maximální počet iterací.\gap
Pro pohyb částice je nejdříve nutné získat náklon povrchu v~daném bodě. Výpočet nového směru využívá gradienty výškové mapy $g$, jejíž hodnotu je možné získat různými způsoby. Jako bod, pro který je gradient počítán, lze například považovat střed buňky, kde se částice nachází. Pro přesnější určení přímo v~pozici kapky autor využívá nejbližších čtyřech buněk a~bilineární interpolace.\gap

Leží-li částice na ose mezi celočíselnými souřadnicemi $x$, $x+1$, $y$ a~$y+1$ a~je-li výška buňky značena $h_{x,y}$, pak gradientu lze vyjádřit dle rovnice~\ref{eq:bayer_gradient}. Posun unvitř daného okolí je značen proměnnými $u$ a~$v$ pro osy $X$ a~$Y$. Posun je zobrazen v~ilustraci~\ref{fig:bayer_interp}.

\begin{equation}
    g = \begin{bmatrix}
        \left(h_{x+1,y} - h_{x,y}\right) \cdot \left(1-v\right) + \left(h_{x+1,y+1} - h_{x,y+1}\right) \cdot v\\
        \left(h_{x,y+1} - h_{x,y}\right) \cdot \left(1-u\right) + \left(h_{x+1,y+1} - h_{x+1,y}\right) \cdot u
    \end{bmatrix}
    \label{eq:bayer_gradient}
\end{equation}\gap

\begin{figure}
    \centering
    \includegraphics[width=0.3\linewidth]{obrazky-figures/theory/particle-interp.pdf}
    \caption{Ilustrace okolí kapky při výpočtu gradienty. Posun kapky uvnitř buňky je zapsán jako proměnné $u$ a~$v$. Okolní buňky jsou označeny jejich souřadnicemi.}
    \label{fig:bayer_interp}
\end{figure}

\noindent Výpočet nového směru pak pomocí konstanty setrvačnosti $c_i$ lze vyjádřit vzorcem:\par
\begin{equation}
    dir_A = dir_{t-1} \cdot c_i - g \cdot \left(1 - c_i\right)
    dir_t = \frac{dir_A}{\norm{dir_A}}
\end{equation}\gap

\noindent Výsledný směr $dir_t$ je tedy získán normalizací mezivýsledku $dir_A$. Nastane-li situace, kdy by byl vektor směru nulový, pak lze zvolit náhodný směr. Důvodem rozdělení rychlosti na směr a~velikost je prevence vytváření artefaktů na povrchu při vyšších rychlostech. Díky jednotkové velikosti směru jej lze přímo přičíst k~pozici kapky bez rizika přeskočení buňky:
\begin{equation}
p_t = p_{t-1} + dir_t
\end{equation}\gap

\noindent Situace, při které by částice strávila mnoho kroků uvnitř jedné buňky, je naopak zanedbána. Iterace algoritmu tedy nepředstavují konstatní časové kroky. Pro účely výpočtu eroze je následně vyjádřen rozdíl výšek mezi novou a~starou pozicí:\par
\begin{equation}
\Delta h = h_t - h_{t-1}
\end{equation}\gap

\noindent Je-li $\Delta h > 0$, pak se částice pohybovala směrem vzhůru a~v algoritmu bude docházet k~depozici materiálu. Místo depozice je stará poloha částice, aby se zaplnila předpokládaná prohlubeň, ze které se kapka dostala. Je-li množství neseného sedimentu dostatečné k~zaplnění prohlubně, pak zde uloží potřebný sediment a~zbytek si ponechá. Jinak je uložen veškerý nesený sediment. Záporný rozdíl výšek vede k~přepočítání kapacity kapky. Pro volitelnou konstantu $c_c$ je kapacita sedimentu definována následovně:\par
\begin{equation}
C = c_c\cdot\max\left(-\Delta h, c_{min}\right)\cdot v_t \cdot w_t
\end{equation}\gap

\noindent Autor také definuje konstantu $c_{min}$ pro nastavení minimálního rozdílu výšek. Vyšší hodnoty vedou k~silnější erozi i~ve velmi plochých oblastech terénu, což může být žádoucí. Je-li výsledná kapacita menší než nesený sediment, pak je přebytek uložen do staré polohy částice. Množství depozice lze také upravovat volitelnou konstantou:\par
\begin{equation}
c_d\cdot\left(s_t-C\right)
\end{equation}\gap

\noindent V~případě, že částice má přebytečnou kapacitu, pak dochází k~erozi. Zde je kladen důraz na nevytváření děr do povrchu. Množství materiálu, jež je odebráno ze staré pozice částice, se řídí vzorcem:
\begin{equation}
\min\left(c_e \cdot \left(C - s_t\right), -\Delta h\right)
\end{equation}\gap

\noindent kde $c_e$ je konstanta eroze. Daný postup zajišťuje, že částice neodebere větší výšku terénu, než kterou sama sestoupila. V~opačném případě by docházelo k~nestabilitě a~oscilaci povrchu. Pro rozdělení vlivu jak eroze, tak depozice, je možné znovu využít interpolaci.\gap

Neboť částice může zacházet pouze se svým nejbližším okolím, může docházet k~vytváření rysů povrchu, jež jsou užší, než je žádoucí. Pro rozšíření vlivu částice autor zavádí váhy eroze pro okolní buňky rovnicí~\ref{eq:part_interp}. V~dané rovnici figuruje $P_i$ jako pozice okolní buňky o~indexu $i$ a~konstanta $c_r$, jež definuje poloměr eroze. Váhy tedy vytváří kužel kolem částice. Možné váhy ilustruje obrázek~\ref{fig:bayer_weights}.\gap

\begin{equation}
w_i = \frac{\max\left(0, c_r - \left(\norm{P_i - p_t}\right)\right)}{\sum_{k=0}^n \max\left(0, c_r - \left(\norm{P_k - p_t}\right)\right)}
\label{eq:part_interp}
\end{equation}\gap

\begin{figure}
    \centering
    \includegraphics[width=0.3\linewidth]{obrazky-figures/theory/cone.pdf}
    \caption{Váhy eroze pro okolní buňky. Poloměr eroze je nastaven na 1{,}5.}
    \label{fig:bayer_weights}
\end{figure}

Při zpomalení kapky je důvodem nejčastěji velmi lokální změna terénu. Depozice je tedy stále prováděna pouze pro nejbližší okolí, neboť širší ovlivnění by nebylo žádoucí. Další možností odstranění příliš tenkých rysů je míchání s~rozmazanou verzí současné mapy ilustrované v~algoritmu~\ref{eq:bayer_mixing}. Zde figuruje konstanta $c_b$, jež ovlivňuje přimíchané množství.\par

\begin{equation}
map = c_b \cdot map_{blurred} + \left(1-c_b\right)\cdot map_{original}
\label{eq:bayer_mixing}
\end{equation}\gap

\noindent Následujícím krokem je získání nové rychlosti částice. Hodnota je vyvozena z~uraženého rozdílu výšek $\Delta h$ a~konstanty pro gravitaci $c_g$ geometrickým průměrem:\par
\begin{equation}
v_t = \sqrt{v_{t-1}^2 + \Delta h \cdot c_g}
\end{equation}\gap

\noindent Podobně jako pro ostatní modely je množství vody násobeno faktorem vypařování $c_e$:\par
\begin{equation}
w_t = w_{t-1} \cdot \left(1-c_e\right)
\end{equation}\gap

\section{Využité technologie}
V této kapitole jsou rozebrány nástroje a~technologie, na kterých je vytvořené rozšíření založeno a~které dále budou odkazovány v~implementaci v~kapitole~\ref{implementace}.

\subsection{Blender}

Blender je bezplatný open-source sofware s~širokou nabídkou nástrojů pro 3D tvorbu jako modelování, animace, vizuální efekty nebo i~fyzikální simulace. Aplikace je vytvářena neziskovou nadací Blender, jež se snaží poskytovat přístupné a~kvalitní 3D nástroje pro veřejnost a~také nabídnout soběstačné prostředí pro 3D tvorbu. Nově také Blender nabízí prostředí pro 2D animaci a~vektorovou grafiku.\gap

Aplikace je multiplatformní, přístupná jak pro Windows, tak pro macOS nebo Linux. Zaměřuje se na interoperabilitu s~jinými aplikacemi a~herními enginy, jako například Source, Unity, nebo Unreal Engine. Podporuje jak importování, tak exportování široké škály formátů včetně průmyslových standardů jako FBX a~OBJ.\gap

Kromě samotné 3D tvorby Blender nabízí kvalitní a~fyzicky přesný vykreslovací engine Cycles, jež využívá raytracing. Také podporuje hardwarové urychlení grafických karet i~procesorů a~technologie odstranění šumu OpenImageDenoise a~OptiX. Pro rychlé vykreslování a~animace ještě poskytuje engine zvaný EEVEE, který použivá kombinace tradičních vykreslovacích metod. Další enginy, jako například LuxCore, Octane nebo Corona, lze také přidat a~integrovat do aplikace skrze rozšíření.\gap

Díky snadné rozšiřitelnosti a~flexibilnímu uživatelskému rozhraní je aplikace užitečná jak pro amatérské tak profesionální uživatele. Široké využití nachází ve filmové i~herní tvorbě, nebo například v~architektonické vizualizaci. Skrze zásvuné moduly je možné použít Blender v~odvětvích jako například 3D tisku, nebo datové vizualizaci. Také má aktivní komunitu, jež dále rozšiřuje funkcionalitu.\gap

\subsubsection{Blender API}

Prvky uživatelského rozhraní, veškeré operace i~data všech prvků v~aplikaci Blender jsou přístupná skrze aplikační rozhraní v~jazyce Python. Vše, čeho může v~aplikaci uživatel dosáhnout, lze rovněž provést skrze skripty. V~kombinaci s~nabízeným flexibilním způsobem tvorby GUI aplikace Blender poskytuje snadné prostředí pro tvorbu rozšíření.\gap

K datům a~funkcím aplikace lze přistoupit uvnitř skriptů skrze Python knihovny Blenderu. Modulů přístupných rozšířením je mnoho a~pokrývají celou škálu funkcionality, včetně práce se zvukem, grafickou kartou nebo fonty. Mezi základní součásti knihovny patří následující moduly:\par
\begin{itemize}
    \item \texttt{context} --- poskytuje současný stav scény v~aplikaci včetně vybraných prvků.
    \item \texttt{data} --- obsahuje seznamy všech vytvořených entit pod správou aplikace.
    \item \texttt{types} --- definuje třídy základních datových typů, jako je objekt nebo obrázek.
\end{itemize}\gap

\noindent Aby se předešlo únikům paměti, tak správa zdrojů je zcela ovládaná aplikací Blender. Tvorba objektů, obrázků a~obecně alokace většího množství zdrojů je možná pouze skrze funkce poskytované knihovnou aplikace. Vrácené objekty, se kterými následně skript pracuje, mohou být následně zneplatněny, například při změně aktivního objektu, je-li uložen do proměnné. S~prvky scény a~uživatelského rozhraní se tedy pracuje pomocí řetězcových jmen, jež je jednoznačně identifikují.\gap

Uživatelské skripty a~rozšíření jsou spouštěny pomocí interpretu jazyka Python, jež je vlastní součástí instalace aplikace. S~tímto interpretem je nainstalováno již několik knihoven, jako například \texttt{numpy}. Jsou-li potřeba externí knihovny pro skript, musí být získány skrze nástroje daného interpretu.\gap


\subsubsection{Materiály}
\label{sec:theory_materials}
V aplikaci Blender lze definovat vzhled objektů pomocí materiálů. Každý objekt jich může mít několik, kde každý může být aplikován na vybrané vrcholy či polygony. Také mohou být sdíleny mezi objekty. Uživatel v~aplikaci Blender materiály definuje pomocí editoru grafů.\gap

\begin{figure}
\centering
\begin{subfigure}[b]{\linewidth}
    \includegraphics[width=\linewidth]{obrazky-figures/theory/material-example.pdf}
    \caption{Graf vykresleného materiálu. Využívá procedurální texturu \texttt{Noise} pro posun mapování druhé textury. Výsledek je převeden na barvy pomocí uzlu \texttt{Color Ramp} a~vykreslen uzlem \texttt{Emission}.}
    \label{fig:blender_materials_used}
\end{subfigure}\gap
\begin{subfigure}[b]{0.35\linewidth}
    \includegraphics[width=\linewidth]{obrazky-figures/theory/abstract.jpg}
    \caption{Vykreslený objekt}
    \label{fig:blender_material_render}
\end{subfigure}
    \caption{Příklad Blender materiálu s~deformovanou procedurální texturou}
    \label{fig:blender_materials}
\end{figure}
%gandalf was here
Vlastnosti povrchu jsou v~grafu materiálu stavěny spojováním různých typů uzlů. Každý má definované vstupy a~výstupy, jež jsou barveny dle jejich datového typu. Při spojení uzlů je datový typ řádně kontrolován, aplikace ale dovoluje i~automatické převody mezi některými typy. Příkladem je převod vektoru na barvu či naopak.\gap

Nabízených uzlů je mnoho a~pokrývají širokou škálu vstupů a~operací. Základním prvkem pro vykreslování jsou takzvané shader uzly, které přímo definují typ povrchu, jež zahrnuje například difůzní, metalické a~další. Rozsáhlou podporu také poskytuje barevným operacím, jako jsou různé typy míchání barev, úpravy HSL hodnot nebo invertování. S~barvami také souvisí mnohé procedurální textury přístupné v~materiálech a~nástroje pro jejich mapování. Příklad struktury materiálu, převodů a~výsledku lze vidět v~ilustraci~\ref{fig:blender_materials}.\gap

Rovněž lze provádět libovolné výpočty užitím skalárních, vektorových i~Booleovských matematických operací. Je-li výpočet příliš složitý i~pro dané uzly, pak lze využít skriptovacího prvku. Zde může uživatel vložit libovolný program napsaný v~jazyce Open Shading Language, zkracovaného jako OSL. Vykreslování je ale limitováno na použití procesoru.\gap

Další uzel, jež bude v~tomto projektu zmiňován, vytváří efekt zvaný \textit{bump} mapování. Užitím textury napojené na daný uzel lze docílit iluze deformace povrchu. Výstup materiálu navíc zahrnuje možnost skutečného posunu vrcholů objektu, v~případě že je použito vykreslování Cycles. Daný proces se nazývá \textit{displacement} mapování.\par
Důležité jsou také vstupní uzly, které poskytují informace nejen o~samotném objektu, ale také o~jeho geometrii, povrchu nebo například o~vlastnostech vykreslovaného paprsku. Tyto prvky je možné použít ke komplexnímu mapování textur na objekty, nebo změně směru výše zmiňovaných deformací.\gap

Uzly uvnitř materiálu lze vytvářet, spojovat i~pozicovat zcela skrze Blender API, je tedy možné procedurálně a~automaticky přidávat i~měnit materiály dle potřeb rozšíření.

\subsubsection{Modifikátory}
\label{sec:theory_modifiers}
Pro nedestruktivní úpravu objektů, neboli bez permanentní změny jejich skutečné geometrie, nabízí aplikace Blender prvky zvané modifikátory. S~jejich pomocí lze snadno duplikovat, deformovat nebo i~animovat 3D modely. Úpravy samotné geometrie se pak okamžitě projeví ve výsledném povrchu.\gap

Mezi nejčastější modifikátory patří \texttt{Subdivision Surface}, jež štěpí polygony povrchu, čímž přídává modelu větší detail. Dále je možné použít \texttt{Array}, jež vytvoří řadu duplikátů modelu, buď se specifikovaným posunem, nebo dle pomocného objektu. Lze tak snadno vytvářet komplexní útvary, nebo libovolné $n$-úhelníky. Příklad tohoto modifikátoru lze vidět v~ilustraci~\ref{fig:blender_modifiers}. S~tímto prvkem také souvisí \texttt{Mirror}, jež zrcadlí objekt dle dané osy či objektu.\gap

Další úpravou využitou v~tomto projektu je \texttt{Displace} modifikátor, jež deformuje povrch dle poskytnuté textury. Posun, rotaci a~škálování dané textury na povrch lze provádět využitím pomocného objektu. Tato nastavení lze rovněž ovládat skrze Blender API, včetně vytváření nových úprav, nebo přeskupování již existujících.\gap

\begin{figure}[H]
\centering
\begin{subfigure}[b]{0.48\linewidth}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/theory/modifier.png}
    \caption{Transformace čtverce na komplexní útvar}
    \label{fig:blender_modifiers_result}
\end{subfigure}
\begin{subfigure}[b]{0.48\linewidth}
    \centering
    \includegraphics[width=0.75\linewidth]{obrazky-figures/theory/modifiers.pdf}
    \caption{Použité modifikátory}
    \label{fig:blender_modifiers_used}
\end{subfigure}
    \caption{Příklad modifikátorů s~použitím \textit{Freestyle} vykreslovací funkce pro zviditelnění. Levé ploše je přidána tloušťka a~posun objektu je definován neviditelným objektem \texttt{Empty}.}
    \label{fig:blender_modifiers}
\end{figure}

\subsubsection{Shape Keys}
\label{sec:shape_keys}
Další metodou nedestruktivní úpravy je použití funkcionality zvané \textit{shape keys} pro daný model. Jedná se o~způsob přídání variace nebo oprav modelu pomocí posunu jednotlivých vrcholů. Ty jsou definovány vůči vrstvě základního modelu, zvané báze. Také nabízí možnost násobit tento posun, je tedy možné snížit nebo zvýšit vliv těchto úpravy. Příklad použití Shape Keys ilustruje obrázek~\ref{fig:blender_shapekey}.\gap

Vytvářet vrstvy lze přímo z~modifikátorů a~vrstev lze takto udělat několik. Jejich vlivy je tak následně možné kombinovat. Rozdíl mezi modifikátory a~shape keys je ten, že modifikátory upravují libovolnou vstupní geometrii, zatímco shape keys definují pro každý vrchol specifickou pozici. Modifikátory, které mění počet vrcholů tedy nejde jako shape keys aplikovat.\gap

\begin{figure}
    \centering
    \begin{subfigure}[b]{0.40\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/theory/shapekey0.jpg}
         \caption{Bázový model}
         \label{fig:blender_shapekey_A}
     \end{subfigure}
     \begin{subfigure}[b]{0.40\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/theory/shapekey1.jpg}
         \caption{Poloviční vliv úpravy}
         \label{fig:blender_shapekey_B}
     \end{subfigure}
     \begin{subfigure}[b]{0.40\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/theory/shapekey2.jpg}
         \caption{Plný vliv}
         \label{fig:blender_shapekey_C}
     \end{subfigure}
    \caption{Příklad a~srovnání použití Shape Keys pro termální erozi. Zbarveno dle normál povrchu pro lepší viditelnost.}
    \label{fig:blender_shapekey}
\end{figure}

\subsection{OpenGL}
\label{sec:opengl}
OpenGL je víceplatformní grafické API s~podporou jak pro 2D, tak 3D vykreslování. Využití nachází v~široké škále aplikací, od jednoduchých nástrojů či her, tak v~CAD návrhu, datové vizualizaci nebo virtuální realitě. OpenGL dovoluje programátorovi využít grafickou kartu a~hardwarové urychlení výpočtů a~poskytuje vysoce upravitelný systém a~nástroje.\gap

Řetězec kroků vykreslování, anglicky zvaný \textit{rendering pipeline}, se dělí na specifické fáze, jež se s~postupným vývojem OpenGL dále rozšiřují a~obohacují. Obrázek~\ref{fig:opengl_pipeline} danou strukturu ilustruje. Základní fáze, jež budou dále zmiňovány, jsou následující:\par
\begin{enumerate}
    \item Aplikační
    \item Geometrická
    \item Rasterizace
    \item Fragmentová
    \item Výstupní
\end{enumerate}\gap

\noindent Aplikační fáze zahrnuje práci prováděnou na CPU. Zde skrze knihovnu OpenGL dochází k~nastavení scény a~objektů. Voláním z~aplikační fáze dochází k~zahájení vykreslení. Zobrazované prvky se skládají z~vrcholů, jež nejprve procházejí geometrickou fází.\gap

V geometrické fázi je možné modely transformovat pomocí matic, či libovolných matematických operací. Kombinací různých matic pak lze například dosáhnout deformace povrchu, pozicování objektu ve scéně nebo perspektivního zobrazení. OpenGL také umožňuje povrch modelu dále modifikovat tvorbou nových vrcholů, nebo štěpením vstupních prvků (proces zvaný \textit{teselace}).\gap

Po dokončení transformace modelu dochází na fázi rasterizace. V~této části vykreslování dojde k~převodu grafických primitiv na jednotlivé fragmenty a~vyřazení částí mimo viditelnou oblast. Data, jež vrcholy vstupní geometrie nesou, se také interpolují mezi jednotlivými fragmenty. Například určením texturových souřadnic pro jednotlivé vrcholy je pak umožněno snadné vykreslování obrázků v~prostoru.\gap

Vytvořené fragmenty a~interpolovaná data využívá následující fragmentová fáze. Ta zpracovává rasterizované pixely na jejich finální barvu. Součástí tedy může být osvětlování, stínování nebo mapování textur. Před dokončením vykreslení mohou být ještě výsledné fragmenty testovány vůči již vykreslenému obsahu, nebo s~ním mohou být smíchány. Součástí tohoto vyhodnocení bývá často vyřazení fragmentů na základě hloubky, čímž je možné vykreslovat překrývající se objekty.\gap

OpenGL nabízí mnoho způsobů jak jednotlivé fáze dále přizpůsobit, včetně různých vykreslovacích modelů, mapování nebo světelných efektů. Také je možné psát vlastní shadery v~jazyce OpenGL Shading Language, neboli GLSL.\gap

Nezávislou fází v~OpenGL je takzvaný výpočetní shader. Daný fáze slouží pro obecné výpočty na grafické kartě, na rozdíl od výše zmíněného přístupu zaměřeného čistě na vykreslování. Daný program je spuštěn paralelně s~více vlákny, kde každé z~nich pracuje nad blokem dat. Fáze se nachází po výpočtu geometrie, ale před výpočtem fragmentů. Výstup může být navázán na další fáze, nebo může být vrácen zpět procesoru.\gap

Pro vykreslování je třeba s~pomocí OpenGL vytvořit několik objektů. Pole dat je nejdříve nutné převádět na takzvané buffer objekty. Pro vykreslení modelu se bude jednat o~pole vrcholů a~popřípadě jejich indexů, jež slouží k~deduplikaci dat. Tyto objekty se následně kombinují ve \texttt{Vertex Array Object}, jež je zkracován jako VAO. Do daného objektu je zahrnutý i~shader program. V~tomto projektu také bude použito vykreslování do textury, jež využívá takzvaný \texttt{Frame Buffer Object}, čili FBO. Ten může zahrnovat i~několik různých textur.\gap

Pro účely implementace je také nutné zmínit, že OpenGL vykresluje pouze vrcholy, jež se nachází v~krychli o~souřadnicích $\left[-1,1\right]$. Tento prostor se nazývá \textit{Normalized Device Coordinates} a~zkracuje se jako NDC. Pro jakékoliv zobrazení, ať už perspektivní nebo kolmé, musí být veškeré modely transformovány do tohoto rozmezí.\gap

\begin{figure}
\centering
    \includegraphics[width=\linewidth]{obrazky-figures/theory/pipeline.png}
    \caption{OpenGL proces vykreslování. Zdrojem je \href{https://learnopengl.com/Getting-started/Hello-Triangle}{LearnOpenGL.com}}
    \label{fig:opengl_pipeline}
\end{figure}

\subsection{GLSL}

OpenGL Shading Language, neboli GLSL, je vysokoúrovňový programovací jazyk zaměření na grafické zpracování v~OpenGL. Byl navržen k~psaní vykreslovacích programů spustitelných na grafické kartě bez znalosti assembly jazyka ARB, jež GLSL předcházel.\gap

Syntaxe a~datové typy GLSL vychází z~jazyka C, navíc ale přímo poskytuje matematické funkce, vektory, matice a~další. Také je možné v~programu použít zabudované proměnné, jež obsahují další informace o~vrcholech či fragmentech, jež jsou právě zpracovávány.\gap

Pomocí klíčových slov \textit{in} a~\textit{out} lze definovat vlastní vstupy a~výstupy jednotlivých programů a~předávání vlastních dat mezi fázemi vykreslování. Naopak externí parametry lze dodat programu skrze takzvané \textit{uniform} proměnné, jež zahrnují i~textury nebo pole. Pro textury je možné pomocí speciálních funkcí provádět i~zápis, čehož tato práce silně využívá.\gap

\subsection{ModernGL}
\label{moderngl}
ModernGL je Python knihovna, jež zaobaluje OpenGL. Jejím cílem je poskytnout rozhraní a~syntaxi blížší jazyku Python (anglicky je přístup označován slovem \textit{Pythonic}). Tímto přístupem se liší od knihoven jako jsou PyOpenGL nebo OpenTK (pro jazyk C\#), jež se snaží o~přesné zachování zaobalených funkcí.\gap

Rozhraní je navíc usnadněno seskupením navazujících operací ve společná volání. Například texturu je možné vytvořit a~nastavit pomocí argumentů jediné funkce, na rozdíl od jednotlivých kroků vytvoření, navázání a~nastavení, jež je typický pro OpenGL. Ke všem nastavením a~nástrojům OpenGL má ale s~knihovnou uživatel stále přístup.\gap

Mezi další výhody knihovny patří automatická správa OpenGL zdrojů skrze objekty v~Pythonu, což redukuje riziko úniků paměti a~dalších chyb, a~vylepšení zpracování chyb a~diagnostiky aplikací. Velká část knihovny je navíc již zkompilována v~jazyce C++, což vede k~urychlení programu a~redukuje velikost knihovny. Důležitou funkcionalitou knihovny pro tuto práci je schopnost se napojit na již \textbf{existující OpenGL kontext}, jako například uvnitř aplikace Blender.\gap

\newpage
\section{Existující rozšíření}
V současnosti jsou již rozšíření, jež se erozí povrchu zabývají. Díky tomu, že jsou spuštěny přímo v~aplikaci Blender, je možné, aby pracovali přímo nad tvořenými objekty a~lze je využít ve spojení s~další funkcionalitou aplikace Blender. Alternativní řešení skrze externí programy jsou probrány v~další kapitole~\ref{sec:external_apps}. Tato část uvede vlastnosti dvou vybraných příkladů.

\subsection{A.N.T. Landscape}

Součástí instalace aplikace Blender je již od základu rozšíření A.N.T. Landscape, jež obsahuje funkci pro erozi povrchu. Jeho hlavním zaměřením je tvorba terénů na základě kombinací procedurálních textur, lze ale také vytvářet planety a~jednoduché vodní plochy\footnote{Popis rozšíření byl získán z~\href{https://docs.blender.org/manual/en/latest/addons/add_mesh/ant_landscape.html}{dokumentace rozšíření na stránkach Blender.org} a~experimentováním s~programem.}.\gap

Daný zásuvný modul vytváří objekty, jež ukládají vlastní parametry. Mezi ně patří například rozlišení objektu, použitá procedurální funkce, oblast, kde se aplikuje, typ stratifikace a~další. Díky uložení těchto nastavení je lze následně měnit, tím tedy i~terén samotný.\gap

Nad rovinnými terény vytvořenými daným rozšířením je také poskytována simulace eroze. Jako příklad výsledku je uvedena ilustrace~\ref{fig:ant_demo}. Eroze se v~rozšíření skládá ze zvoleného počtu iterací tří různých algoritmů, kde každý má dále vlastní počet opakování.\gap

Prvním je difůze materiálu do okolních buněk s~nastavitelnou silou, kde velký vliv vede k~uhlazení povrchu. Dále nabízí termální erozi s~maximálním úhlem povrchu a~silou vlivu jako parametry. Poslední komponentou je vodní eroze, jež jako argumenty poskytuje například množství a~variaci deště, sílu eroze a~depozice, nebo sedimentovou kapacitu vody.\gap

Oproti navrhovanému projektu je možné dané rozšíření použít pouze nad terény, jež samo vygenerovalo. Dalším rozdílem je rychlost eroze. Rozšíření A.N.T. Landscape běží na procesoru, pro větší rozlišení terénu tedy proces může výrazně trvat.\par

\begin{figure}[H]
    \centering
    \includegraphics[width=0.75\linewidth]{obrazky-figures/theory/antLandscape.png}
    \caption{Kombinovaná vodní a~termální eroze povrchu vytvořeného rozšířením A.N.T. Landscape}
    \label{fig:ant_demo}
\end{figure}

\subsection{Erosion Add-on}

Pro erozi je také možné použít placené rozšíření Erosion Add-on přístupné na stránkách Blender Market. Tento zásuvný modul poskytuje vlastní algoritmus jak 2D, tak prostorové eroze s~podporou převisů\footnote{Popis a~ilustrace získány ze stránek rozšíření na \href{https://blendermarket.com/products/erosion-add-on}{blendermarket.com}}.\gap

Erozi lze provádět nad libovolným objektem a~její průběh je možné přizpůsobit pomocí křivek profilů terénu. Kromě eroze také nabízí mapy několika typů toků. Výsledek eroze je také možné snadno kombinovat s~částicovým systémem aplikace Blender. Plná verze rovněž nabízí tvorbu modelů řek a~jezer. Příklad krajiny vytvořené rozšířením ilustruje obrázek~\ref{fig:erosion_demo}.\gap

Navrhovaný projekt nabízí oproti danému rozšíření urychlení na grafické kartě, algoritmus termální eroze a~přímou erozi obrázků. Dané rozšíření také pracuje pouze přímo s~vrcholy oproti texturovému přístupu navrhovaného projektu.

\begin{figure}[H]
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/theory/erosion-addon-promo.jpg}
    \caption{Terén vygenerovaný rozšířením Erosion Add-on.}
    \label{fig:erosion_demo}
\end{figure}

\section{Externí aplikace}
\label{sec:external_apps}
Mimo rozšíření, jež jsou přímo spustitelná v~aplikaci, existuje i~řada samostatných programů pro úpravu terénu. Díky vysoké flexibilitě exportu i~importu aplikace Blender lze dané nástroje použít pro vývoj modelů, i~přes relativně složitější postup oproti zásuvným modulům. Jako reprezentativní příklady jsou zde uvedeny aplikace Wilbur, pracující na základě textur, a~Terragen, jež je schopna i~vlastního vykreslování.

\subsection{Wilbur}

Wilbur je aplikace pro tvorbu terénu s~dlouholetou historií. Poskytovaná funkcionalita se zaměřuje na práci s~výškovými mapami. Nabízená je jak generace terénů pomocí různých procedurálních funkcí, tak jejich následná úprava řadou metod\footnote{Program Wilbur byl získán ze stránky \href{http://www.fracterra.com/software.html}{fracterra.com}. Popis funkcí byl získán experimentováním s~programem.}.\gap

Důležitými úpravami v~kontextu této práce jsou funkce vodní eroze, jež jsou v~programu dvojího typu. Model zvaný \textit{Percipiton} nabízí pouze jeden parametr pro sílu, dá se ale nastavit typ okolí buňek v~modelu, opakování mapy na okrajích i~vliv moře v~určité výšce. Jednotlivé iterace lze mezi sebou nastavitelně míchat a~k výsledku přidávat šum. Výstupem je detailní a~tenké zvrásnění povrchu.\gap

Druhý model eroze je zvaný \textit{Incision} a~oproti předchozímu algoritmu tvoří rozsáhlejší rysy povrchu. Jako parametry využívá množství toku a~sílu rozmazání povrchu před a~po dané operaci. Příklad eroze terénu je ilustrován v~obrázku~\ref{fig:wilbur_demo}.\gap

\begin{figure}[H]
    \centering
    \begin{subfigure}[b]{0.45\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/theory/wilburA.png}
         \caption{Původní terén}
         \label{fig:wilburA}
     \end{subfigure}
     \begin{subfigure}[b]{0.45\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/theory/wilburB.png}
         \caption{Terén po erozi}
         \label{fig:wilburB}
     \end{subfigure}
    \caption{Aplikace obou metod eroze programem Wilbur}
    \label{fig:wilbur_demo}
\end{figure}

\noindent Program lze získat zdarma a~je stále vyvíjen. Mapy vytvořené v~této aplikaci lze uložit v~mnoha formátech a~dvou bitových hloubkách jako obrázky, nebo přímo vyexportovat jako model.

\subsection{Terragen}
Terragen je placená aplikace pro vytváření terénů. Jejím cílem je kromě generování i~plné vykreslování realistických světů. Současná verze Terragen 4 disponuje řadou metod tvorby od velikosti několika kamínků až po celé planety a~na terén lze aplikovat prakticky neomezený fraktální detail. Pracovní postup aplikace využívá grafů pro specifikaci terénů, materiálů i~způsobu vykreslování. Uživatel tedy aplikuje změny vytvářením a~spojováním uzlů podobně jako v~aplikaci Blender\footnote{Popis funkcí aplikace Terragen byl získán z~přehledu na \href{https://planetside.co.uk/terragen-overview/}{oficiálních stránkách}.}.\gap

Jeden ze zabudovaných uzlů grafu terénu slouží pro erozi výškové mapy. Jako parametry podporuje délku toku, rozděluje sílu eroze a~depozice a~zahrnuje i~sesuv půdy pro maximální úhel terénu. Výstupem uzlu může být vytvořená výšková mapa, nebo rozdíl oproti původnímu povrchu\footnote{Přehled parametrů lze najít na \href{https://planetside.co.uk/wiki/index.php/Heightfield_Erode_v3}{wiki stránkách} aplikace.}. Příklad eroze povrchu tímto uzlem je ilustrován v~obrázku~\ref{fig:terragen_demo}.\par

\begin{figure}[H]
    \centering
    \begin{subfigure}[b]{0.495\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/theory/terragenA.jpg}
         \caption{Původní terén}
         \label{fig:terragenA}
     \end{subfigure}
     \begin{subfigure}[b]{0.495\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/theory/terragenB.jpg}
         \caption{Terén po erozi}
         \label{fig:terragenB}
     \end{subfigure}
    \caption{Příklad výsledků funkce eroze. Zdrojem obrázků jsou \href{https://planetside.co.uk/wiki/index.php/Heightfield_Erode_v3}{wiki stránky} aplikace}
    \label{fig:terragen_demo}
\end{figure}

\noindent Aplikace Terragen také nabízí rozšíření funkcionality přes zásuvné moduly. Jedním z~nich je \textit{Classic Erosion}, jež oproti zabudovanému řešení přidává parametr škály terénu, experimentální erozi řekami a~nastavení oblasti pomocí objektů, kde se bude eroze provádět\footnote{Přehled možností rozšíření \textit{Classic Erosion} lze najít na stránkách autora: \url{https://daniilkamperov.com/}}. Uvedené rozšíření je placené, stejně jako Terragen ale nabízí rovněž omezenou verzi zdarma. Pro použití s~aplikací Blender lze výškové mapy z~programu vyexportovat. Příklad eroze terénu je ukázán v~ilustraci~\ref{fig:terragen_plugin_demo}.\par

\begin{figure}[H]
    \centering
    \includegraphics[width=0.8\textwidth]{obrazky-figures/theory/classicErosion.jpg}
    \caption{Příklad výsledků rozšíření. Zdrojem jsou \href{https://daniilkamperov.com/}{stránky autora}.}
    \label{fig:terragen_plugin_demo}
\end{figure}

\chapter{Návrh řešení}
\label{navrh}

V této kapitole je představen zamýšlený pracovní postup při použití aplikace, jež bere v~potaz požadavky výše zmíněných algoritmů a~vlastnosti i~limitace dostupných prostředků aplikace Blender. Dále se kapitola zabývá uživatelským rozhraním, jež bylo na daný postup orientováno s~cílem dynamického zobrazení. V~poslední řadě jsou zde prezentovány požadavky na funkcionalitu, jež je třeba implementovat. Výsledný projekt byl pojmenován \textit{Hydra}, dle čehož jsou odvozeny uživatelské prvky, adresář aplikace i~prefixy funkcí a~tříd zmíněných později v~části implementace.


\section{Zacházení s~rozšířením}
\label{gui_workflow}
Cílem projektu je rozšíření aplikace Blender schopné simulace vodní a~termální eroze na libovolné vstupní geometrii, reprezenetované objektem ve 3D scéně, nebo na libovolném obrázku výškové mapy. Uživatel má také možnost erozi aplikovat vícenásobně.\gap

Principem rozšíření je převod buď obrázku, nebo zvoleného objektu, na výškovou mapu, která je následně zvětrána. Výslednou texturu pak rozšíření zobrazí nebo nanese zpět na objekt. Navrhovaný pracovní postup eroze, jež je ilustrován v~obrázku~\ref{fig:workflow_schema_simple}, se skládá z~následujících kroků:\par

\begin{enumerate}
    \item Automatické vygenerování výškové mapy
    \item Vodní nebo termální eroze
    \item Automatické zobrazení výsledku
    \item Aplikování nebo exportování výsledku
    \item Uvolnění dat
\end{enumerate}\gap

\begin{figure}[H]
    \centering
    \includegraphics[width=0.55\linewidth]{obrazky-figures/design/gui_workflow_simple.pdf}
    \caption{Navrhovaný pracovní postup vodní a~termální eroze}
    \label{fig:workflow_schema_simple}
\end{figure}

Při prvním spuštění eroze je vygenerována výšková mapa zvolené velikosti. Daná velikost je pak pro objekt \textbf{neměnná} a~udává rozměry eroze. Jak pro erozi obrázků, tak geometrie, je navržen stejný systém výškových map, jež se dělí na dvě různé textury:\par

\begin{enumerate}
    \item Zdrojová mapa --- textura, ze které bude vycházet eroze.
    \item Současná mapa --- výsledek simulace eroze.
\end{enumerate}\gap

Zdrojová mapa figuruje jako záchytný bod spjatý s~objektem. Je-li následně volána několikrát funkce eroze, pak vždy vychází z~dané textury, čímž má uživatel možnost zkoušet různé parametry. Chce-li uživatel dále pracovat již s~výsledkem eroze, pak je schopný nastavit současnou mapu jako zdrojovou. Tímto způsobem lze také následně aplikovat termální erozi a~naopak.\gap

Je možné znovu vygenerovat zdrojovou mapu, pokud se chce uživatel vrátit, nebo pokud došlo ke změně vstupu. Daným postupem tvorby a~uchovávání výškové mapy se odděluje potenciálně náročný výpočet povrchu od samotné eroze, u~které lze předpokládat, že bude prováděna vícekrát se stejným terénem.\gap

Při prvním vytvoření zdrojové mapy je také uložena její kopie, dále označovaná jako modelová mapa. Vstupní objekty nebo obrázky pak nemusí být znovu převáděny na výškové mapy při aplikování výsledku, kde je daná textura potřeba.

\subsection{Aplikování výsledku}

Výsledkem eroze je současná výšková mapa, pro kterou je automaticky generován náhled. Při práci s~objektem jsou rovněž umožněny další způsoby, jak simulovanou erozi na objekt nanést. Pracovní postup včetně systému výškových map a~možností aplikování výsledku je zobrazen v~ilustraci~\ref{fig:workflow_schema}. Navrhované řešení nabízí aplikování skrze modifikátory a~materiály zmíněné v~teoretické sekci~\ref{sec:theory_modifiers}.\gap

Výše zmíněné úpravy je rozšíření schopno zcela automaticky generovat, přepisovat a~adaptovat na materiály i~modifikátory již vytvořené uživatelem. Výstupem může také být převod výškové mapy na obrázek v~aplikaci Blender.\par

\begin{figure}[H]
    \centering
    \includegraphics[width=0.75\linewidth]{obrazky-figures/design/gui_workflow.pdf}
    \caption{Ilustrace systému výškových map s~možnostmi aplikování výsledku. Eroze ze vstupů na pravo umí vytvořit automaticky zdrojovou mapu. Ze zdrojové mapy se dále erozí tvoří současná mapa. Pro erozi současné mapy ji lze nastavit jako zdroj. Jako způsoby aplikování současné mapy jsou zde uvedeny převody na modifikátor, na materiál a~na obrázek.}
    \label{fig:workflow_schema}
\end{figure}

\subsection{Uvolnění zdrojů}

Závěrečným krokem pro erozi je čištění dat. Díky rozdělení terénu a~jeho výškové mapy jsou vytvořené textury uchovávány v~rozšíření. Dokončil-li uživatel práci, nebo potřebuje-li uvolnit paměť, pak lze vytvořené textury vymazat vždy dostupnou operací. Jelikož velikost textury u~objektu je po prvním vytvoření neměnná, je také možné touto operací textury uvolnit a~zvolit jiné rozlišení.\gap

\section{Návrh funkcionality}
Mimo obecné požadavky, tedy kromě samotné eroze, by mělo rozšíření nabízet i~další operace, jež jsou s~použitými algoritmy spjaty. Uživatel pak bude schopný vygenerovat přídavná data týkající se povrchu a~pohybu vody --- specificky sedimentaci, hloubku eroze a~koncentraci toků v~jednotlivých bodech. Neboť tvorba výškové mapy je nutnou funkcí rozšíření, tak lze poskytovat generování přímo do samostatného obrázku jako samostatnou operaci dostupnou k~užití. Zmíněné výstupy ilustruje obrázek~\ref{fig:gui_other_maps}. Požadavky, které z~daných operací vzcházejí, jsou uvedeny v~následujících podkapitolách.\gap

\begin{figure}
    \centering
    \begin{subfigure}[b]{0.45\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/design/sediment.png}
         \caption{Mapa sedimentace}
         \label{fig:gui_sediment}
     \end{subfigure}
     \begin{subfigure}[b]{0.45\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/design/depth.png}
         \caption{Mapa hloubky eroze}
         \label{fig:gui_depth}
     \end{subfigure}
     \begin{subfigure}[b]{0.45\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/design/flow.png}
         \caption{Mapa koncentrace toků}
         \label{fig:gui_flow}
     \end{subfigure}
     \begin{subfigure}[b]{0.45\textwidth}
         \centering
         \includegraphics[width=\textwidth]{obrazky-figures/design/heightmap.png}
         \caption{Výšková mapa}
         \label{fig:gui_heightmap}
     \end{subfigure}
    \caption{Ilustrace dalších výstupů rozšíření.}
    \label{fig:gui_other_maps}
\end{figure}

\subsection{Transformace objektů a~tvorba výškové mapy}

Pro maximální využití výškové mapy je nejdříve třeba transformovat vybraný objekt tak, aby zaplňoval co nejvíce její plochy. Navrženým řešením je vytvoření kvádrové obálky kolem výběru. Na základě jejích rozměrů je možné získat střed útvaru a~matici jak pro posun, tak pro škálování do tvaru textury. Transformaci objektu ilustruje obrázek~\ref{fig:gui_bounding_box}.\gap

\begin{figure}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/design/scaling.pdf}
    \caption{Příklad obálky objektu a~škálování do ilustrovaných rozměrů. Výsledný povrch je v~rozmezí specifikovaném v~podkapitole OpenGL~\ref{sec:opengl}. Nejnižší bod povrchu je mapován na hodnotu~0 a~nejvyšší na hodnotu~1.}
    \label{fig:gui_bounding_box}
\end{figure}

\subsection{Aplikování výsledku eroze}

Jak bylo zmíněno v~sekci~\ref{gui_workflow} pracovního postupu, mezi způsoby aplikování eroze nabízí rozšíření i~úpravu materiálu objektu. V~tomto případě je ale třeba řešit již uživatelem vytvořené prvky, nebo potenciálně předchozí běhy eroze.\gap

Není-li materiál definován, pak je rozšíření schopné vytvořit nový. Jinak je procházen a~musí být vytvářeny všechny uzly, jež chybí pro správnou funkcionalitu materiálu. Příklad přidaných prvků je zobrazen v~obrázku~\ref{fig:gui_material}.\gap

\begin{figure}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/design/material-abstract.pdf}
    \caption{Možnosti automatického doplnění materiálu vyznačeny obdélníky. Ilustrované uzly jsou vysvětleny v~teoretické části~\ref{sec:theory_materials}.}
    \label{fig:gui_material}
\end{figure}

\subsection{Transport barev a~textury}

Ne vždy je třeba upravit samotný model pro reálně vypadající krajiny, jako například u~vzdálených kopců nebo zalesněných ploch. Potřeby uživatele může zde splňovat i~barevná textura, jež pouze indikuje směr toku vody a~mísení uvolněných materiálů. Za tímto účelem navržené rozšíření implementuje transport barev procesem eroze.\gap

Myšlenkou rozšíření existujících algoritmů je dodání textury uživatelem a~v průběhu procesu buď načítat barvu při erozi, nebo při sedimentaci na mapu nesenou barvu nanášet. Možný výsledek ilustruje obrázek~\ref{fig:gui_colors}.\gap

Další funkcionalitou spjatou s~texturami je převod barevného prostoru obrázků v~aplikaci Blender. Při načítání a~následném generování nesprávného formátu může dojít k~ztmavení či zesvětlení textury. V~případě eroze obrázku to má za následek i~tvorbu nesprávné výškové mapy. Rošíření tedy musí být schopné různé barevné prostory rozlišit a~navzájem převádět.

\begin{figure}[H]
    \centering
    \begin{subfigure}{0.48\linewidth}
         \centering
         \includegraphics[width=\linewidth]{obrazky-figures/design/colorA.png}
         \caption{Původní textura}
         \label{fig:colorA}
     \end{subfigure}
     \begin{subfigure}{0.48\linewidth}
         \centering
         \includegraphics[width=\linewidth]{obrazky-figures/design/colorB.png}
         \caption{Upravená textura}
         \label{fig:colorB}
     \end{subfigure}
    \caption{Ukázka transportu barev na modelu s~$30{,}000$ polygony.}
    \label{fig:gui_colors}
\end{figure}

\subsection{Preference a~instalace závislostí}

Navrhované rozšíření vyžaduje externí závislosti. Aby byl projekt pro uživatele přívětivý, měl by být schopen automaticky dané externí knihovny stáhnout a~nainstalovat. Aplikace Blender nabízí možnost tvorby vlastní stránky v~seznamu rozšíření, kde bude navržená operace stažení umístěna. Zde budou také uvedeny obecné preference projektu.

\section{Uživatelské rozhraní}
\label{sec:gui_placement}
První volbou v~návrhu rozhraní je celkové umístění v~rámci aplikace. Například na rozdíl od rozšíření A.N.T. Landscapes, jež pro nastavení eroze využívá dočasného okna, byla zvolena vlastní záložka \textit{Hydra} v~pravém kontextovém menu. Návrh struktury záložek je ilustrován v~obrázku~\ref{fig:gui_schema}.\gap

Jelikož se jedná o~prvek rozhraní, jež není navázán přímo na určitou akci, tak samotné provedení operací bude spouštěno tlačítkem. Dané řešení dovoluje oddělit úpravu parametrů od zahájení s~nimi spjaté operace, jež bude výpočetně náročná. Tím se také dá předejít zamrznutí a~případnému pádu při posuvné uprávě parametrů, která by akci spouštěla mnohokrát.\gap

Kromě eroze by mělo rozšíření nabízet další operace, jež mají rozdílné vstupy a~kontexty. Funkce rozšíření jsou tedy rozděleny do několika samostatných panelů. Akce vázané přímo s~objekty pak lze zobrazovat pouze tehdy, když je určitý objekt vybrán, například vyčištění alokované paměti je ale možné vždy.\gap

Neboť rozšíření tvoří výstupy napříč mnoha editory a~seznamy uvnitř aplikace Blender, tak musí být brán zřetel na informování uživatele a~navigaci mezi výsledky. Příklad rozhraní, jež takovou funkcionalitu bude poskytovat, je ilustrován v~obrázku~\ref{fig:gui_links}.\gap

\begin{figure}
    \centering
    \includegraphics[width=0.3\linewidth]{obrazky-figures/design/gui_layout.pdf}
    \caption{Ilustrace struktury uživatelského rozhraní a~přehled návrhu funkcionality}
    \label{fig:gui_schema}
\end{figure}

\begin{figure}
    \centering
     \includegraphics[width=0.5\linewidth]{obrazky-figures/design/gui_linking.pdf}
    \caption{Návrh propojení výstupů. Seznam vytvořených textur je nabízen přímo v~rozhraní a~dovoluje zobrazit jednotlivé položky.}
    \label{fig:gui_links}
\end{figure}

\chapter{Implementace}
\label{implementace}

V této kapitole je představeno řešení výše navržené funkcionality. Nejdříve je zde zmíněn souhrn inicializace a~základní struktura rozšíření. Dále kapitola zachází do detailu uživatelského rozhraní a~operátorů, jež jsou vstupní body jednotlivých algoritmů. Dalším bodem je generování výškových map, implementace jednotlivých typů eroze a~přídavných operací. V~poslední řadě je představeno řešení aplikování výsledků a~navigace k~nim.\gap

\section{Inicializace a~struktura rozšíření}

Tato kapitola zahrnuje registraci rozšíření v~aplikaci, načítání a~inicializaci modulů a~základní strukturu aplikace.

\subsection{Registrace}

Prvním krokem spuštění rozšíření je vyhledání externí knihovny ModernGL, bez které nemůže rozšíření fungovat. Veškeré načítání uživatelských prvků a~dalších modulů se v~inicializaci odvíjí od přítomnosti této knihovny.\gap

Je-li ModernGL nainstalováno se zjišťuje pokusným importováním v~inicializačním souboru rozšíření. Ošetření případné výjimky pak nastavuje příznak neplatného spuštění, dle čehož se dále řídí uživatelské rozhraní. Není-li knihovna nainstalovaná, pak se načte pouze okno preferencí, jež uživatele provede instalací. Jinak se zbytek spuštění skládá z~následujících kroků:\gap
\begin{enumerate}
    \item Registrace tříd uživatelského rozhraní
    \item Vytvoření globálních dat a~jejich inicializace
    \item Napojení kontextu OpenGL
    \item Načtení a~překlad shader programů
    \item Vytvoření globálních nastavení scény
    \item Vytvoření individuálních nastavení entit
\end{enumerate}\gap

\noindent Třídy uživatelského rozhraní jsou registrovány individuálně pomocí funkce \texttt{register\_class} z~knihovny \texttt{bpy.utils}. Seznam tříd, jež se mají registrovat, uchovávají jednotlivé moduly v~konstantních seznamech \texttt{EXPORTS}.\gap

Pro získání OpenGL kontextu je využita schopnost ModernGL se napojit na již existující kontext aplikace Blender. Naopak vytvoření samostatného kontextu vede okamžitě k~\textbf{pádu aplikace}. Získaný objekt je uložen do globální proměnné \texttt{common.data}, skrze kterou je k~němu následně přistupováno.

\subsubsection{Odregistrace}
Seznam tříd uživatelského rozhraní je nejprve v~opačném pořadí odregistrován, následně jsou smazána globální i~objektová nastavení, jež by jinak mohla přetrvávat v~souboru, a~potom, pokud byla načtena knihovna ModernGL, dojde k~uvolnění veškerých dat OpenGL.

\subsection{Společná data}

Ústředním prvkem rozšíření je modul \texttt{common}, jež slouží pro uchovávání alokovaných textur, vytvořených shader programů a~předávání zpráv nebo chyb uživatelskému rozhraní. Ostatním modulům jsou tyto prvky poskytovány globální proměnnou \texttt{data}.\gap

Mezi alokované textury patří především výškové mapy, jež jsou uchovávany ve slovníku. Proměnná \texttt{data} skrze metody zprostředkovává tvorbu map, jejich mazání a~přístup k~nim. Rovněž obsahuje seznamy řetězců a~funkci na jejich zobrazení. Je tak možné při konání operací agregovat zprávy pro uživatele. Jako klíče výškových map slouží náhodné UUID.\gap

\subsection{Nastavení rozšíření}

Aby nebylo třeba vždy znovu zadávat nastavení operací, tak je třeba někde uchovávat jejich hodnoty. Rozšíření definuje dvě skupiny nastavení pomocí třídy \texttt{types.PropertyGroup}, jež se ukládají v~souboru Blender projektu.\gap

Objekty a~obrázky sdílejí stejnou skupinu nastevní. Jejich třídám je přiřazena jako vlastnost skrze typ \texttt{props.PointerProperty}. Hodnoty nastavení jsou nezávislé a~unikátní pro každou instanci. K~nastavením lze v~rozšíření přistoupit skrze vlastnost \texttt{hydra} obou typů objektů.\gap

Důležitými vlastnostmi entit jsou výškové mapy, jež jsou řetězcové hodnoty UUID a~které slouží jako odkazy do slovníku map zmíněném výše. Jejich hodnoty jsou upravitelné pouze rozšířením.\gap

Další unikátní nastavení entit, jež nesouvisí se vstupy algoritmů a~které bude dále zmiňováno, je pravdivostní hodnota \texttt{is\_generated}. Vlastnost indikuje, že entita byla vytvořena rozšířením a~může být v~budoucnu přepsána. Rozšíření nedovoluje u takto označených entit provádět erozi nebo vytvářet textury. Je ale nabízena operace, jež danou entitu osamostatní, čímž je znovu povolena veškerá funkcionalita rozšíření.\gap

Rozšíření také vyžaduje nastavení, jež nemá smysl uchovávat pro každý objekt. Jedním z~nich je rozlišení přímého exportu výškové mapy, jež je nezávislé na ostatních operacích. Aby byla hodnota nastavitelná uvnitř rozhraní, tak musí být někde definována jako vlastnost. Stejně jako u objektu byla tedy vytvořen ukazatel v~typu \texttt{bpy.types.Scene}.\gap

\section{Uživatelské rozhraní a~operátory}

V této kapitole je uvedeno obecné rozložení uživatelského rozhraní, získání a~ošetření možných vstupů při práci s~obrázky i objekty, a~dále princip volání dalších částí rozšíření.\gap

Jak bylo zmíněno v~kapitole návrhu~\ref{sec:gui_placement}, rozhraní bylo umístěno v~bočním panelu okna. Prvky rozhraní jsou typu \texttt{Panel} a~je nutné je individuálně registrovat při inicializaci. Každý panel zaobaluje jednotlivé funkce rozšíření.\gap

V případě eroze bylo nutné řešit velké množství vstupů a~zobrazených dat. Tento prvek je tedy dále dělen na několik menších záložek, jež jsou také typu \texttt{Panel}. Dané rozložení ilustruje obrázek~\ref{fig:erosion_subpanels}. Stejně jako rodičovský prvek je nutné tyto panely individuálně registrovat. Zabalení prvků do sebe lze docílit nastavením vlastnosti \texttt{bl\_parent\_id} na identifikátor obklopujícího prvku.\gap

\begin{figure}
    \centering
    \includegraphics[width=0.35\linewidth]{obrazky-figures/design/gui_layout.pdf}
    \caption{Ilustrace dělení panelu eroze na záložky}
    \label{fig:erosion_subpanels}
\end{figure}

\subsection{Rozhraní objektů a~obrázků}

Rozhraní pro objekty bylo umístěno do okna 3D scény. Specificky je zobrazováno pouze v~základním režimu daného okna zvaném \texttt{objectmode}. V~jiných režimech nemusí být veškerá funkcionalita rozšíření proveditelná. Například při úpravě geometrie nelze aplikovat modifikátory.\gap

Pro práci s~texturami bylo rozhraní umístěno do editoru obrázků. U jednotlivých operací zde nedochází ke změně vstupu, režim okna tedy nemá na rozšíření vliv a~není brán v~potaz.

\subsection{Získání a~ošetření vstupů}

Při implementaci uživatelského rozhraní bylo dbáno na zobrazení prvků pouze v~případě, že jsou opravdu použitelné, ne se všemi objekty a~texturami je rozšíření totiž schopné pracovat.\gap

Podmínečné zobrazení panelů je řešeno skrze třídní metodu \texttt{poll}, která vrací pravdivostní hodnotu, má-li být panel zobrazen. Společnou kontrolou ve většině panelů je určení, jestli byl objekt vygenerován tímto rozšířením. To určuje vlastnost \texttt{is\_generated} v~nastaveních objektu.\gap

\subsubsection{Objekty}

Aktivní objekt lze kdykoliv získat z~kontextu aplikace ve vlastnosti \texttt{active\_object}. Kontext je také automaticky předáván vykreslovací funkci panelu jako argument. Všechny panely rozhraní, jež pracují s~geometrií, ale potřebují kontrolovat, zda-li objekt skutečně geometrii má.\gap

Prvním krokem je kontrola existence objektu, neboť výše zmíněná vlastnost může vracet prázdnou hodnotu. K~tomu může dojít například krátce po smazání objektu. Aplikace Blender dále nabízí různé typy objektů, jež jsou rozlišitelné vlastností \texttt{type}. Typ, nad kterým je rozšíření schopné pracovat, se nazývá \texttt{MESH}. Objekt ale může mít stále prázdnou geometrii. Dále tedy kontrolují panely počet vrcholů, jež je přístupný skrze vlastnost objektu \texttt{data.vertices}. Tento seznam pro zvolený typ objektu vždy existuje. V~případě prázdného seznamu se panely nezobrazí.

\subsubsection{Obrázky}

Aktivní obrázek není přímo definovaný v~kontextu aplikace, ale náleží oknu editoru obrázků, ve kterém bylo rozhraní umístěno. K~obrázku je přistupováno skrze vlastnost \texttt{image} proměnné aktivního okna, tedy \texttt{area.spaces.active}. Vlastnost může ale mít \textbf{prázdnou hodnotu}, jež je kontrolována. Příkladem toho je základní textura \texttt{Render Result}, dokud do ní není zakresleno.\gap

\subsection{Operátory}

Funkce rozšíření jsou z~uživatelského rozhraní spouštěny skrze takzvané operátory. Celý algoritmus, jež má být takto proveden, probíhá zcela v~metodě operátoru \texttt{invoke}. Zodpovědností operátoru je tedy provedení přípravy, spuštění a~následného úklidu požadované funkcionality pomocí modulů, jež jsou rozebrány v~následujících kapitolách.\gap

Obecný postup operace se skládá z~volání příslušných modulů a~navigace k~výsledkům. Společnou součástí operátorů je také resetování zpráv v~modulu \texttt{common} a~po dokončení provádění i jejich výpis.

\subsubsection{Aplikování výsledků}

Většina operátorů pro aplikování výsledných map je stejná jak pro práci s~obrázky, tak s~objekty. Neboť musí ale získávat vstupní entity jiným způsobem, tak je u daných operátorů definovaná pravdivostní hodnota, dle které vstupy a~postupy rozlišuje.\gap

Tato hodnota je implementována vlastností operátoru a~přistupuje se k~ní ve vykreslovací funkci rozhraní. Pro přidání operátoru lze použít Blender metodu \texttt{operator}. Ta přidá tlačítko a~zároveň vrací objekt, přes který lze operátoru předávat další vstupy skrze nastavení vlastností.\gap

Pro všechny obrázky vytvořené rozšířením dále platí, že jsou zabaleny do souboru projektu Blender. Toho lze docílit voláním metody \texttt{pack}. Bez zabalení do souboru může dojít ke \textbf{smazání dat} při načtení obrázků.

\subsection{Preference}

Rozšíření nabízí dvě globální možnosti v~preferencích, jež jsou směr dělení oken a~přeskočení indexace. Směr dělení je aplikován při navigaci k~výsledku v~sekci~\ref{list:nav_split} a~přeskočení indexace ovlivňuje generaci výškové mapy, což je rozebráno v~kapitole \ref{sec:heightmap}. Tento proces je rozebrán v~kapitole~\ref{alg:indexing}.\gap

Pro čtení preferencí je třeba přistoupit k~vlastnosti \texttt{preferences} kontextu a~zde vybrat ze seznamu správné rozšíření. V~daném objektu je pak seznam nastavení znovu pod názvem \texttt{preferences}. Pro zkrácení zápisu byl přístup implementován jako funkce v~modulu \texttt{common}.\gap

\section{Výškové mapy}
\label{sec:heightmap}

V této kapitole je detailně uveden proces získání výškových map ze vstupních entit. Nejprve je uveden převod z~obrázků a~následně algoritmus vykreslení geometrie a~nutných transformací.\gap

Modul výškových map slouží nejen k~přímé tvorbě obrázku, ale je také součástí přípravných fází veškeré eroze. Ústřední funkcí je zde \texttt{prepareHeightmap}, jež je volána v~případě, kdy objekt nemá vytvořenou zdrojovou výškovou mapu, ze které další algoritmy čerpají. \gap

Výsledkem funkce je kolmá projekce na texturu podél osy $Z$, kde černá barva má nejnižší výšku a~bílá nejvyšší. Mapa je tedy normalizována.

\subsection{Generování z~obrázku}
Pro vytváření textury z~obrázků je převeden seznam pixelů na \texttt{numpy} vektor desetinných čísel. Pixelová data v~obrázcích aplikace Blender vždy obsahují tři barevné složky a~alfa kanál. Výběrem každého čtvrtého prvku, počínaje prvním, je následně extrahován pouze červený kanál textury, jež rozšíření považuje za výškovou složku. V~různobarevných obrázcích tedy další kanály nejsou brány v~potaz, stejně jako alfa kanál obrázku.\gap

Výsledek je následně funkcí \texttt{copy} převeden na nový vektor, neboť vytvářená textura vyžaduje, aby vstupní data byla \textbf{spojitě uložena v~paměti}. Z~vektoru je pak vytvořena ModernGL textura.\gap

Problém, jež musí být dále řešen v~implementaci, je barevný prostor obrázku. Pokud vstup využívá celočíselná data, tedy neplatí \texttt{img.is\_float}, pak je barevný prostor obrázku sRGB. Hodnoty jeho pixelů bez správného převodu nemusí odpovídat výškám, jež byly do textury původně uloženy. Funkce linearizace je zobrazena v~algoritmu~\ref{alg:srgb}. Daná funkce je implementována jako výpočetní shader. Neboť výpočet není závislý na okolí pixelu, tak je funkce volána nad již vytvořenou texturou, kterou rovnou přepisuje.\gap

\begin{algorithm}
\caption{Linearizace kanálu barvy \cite{sRGB}\label{alg:srgb}}
\eIf{$channel \leq 0.04045$} {
    \Return $channel \div 12.92$
}{
    \Return $\left[\left(channel + 0.055\right)\div 1.055\right]^{2.4}$
}
\end{algorithm}

\subsection{Generování z~objektu}
Pro objekty je převod na výškovou mapu, ilustrovaný v~obrázku~\ref{fig:example-heightmap}, složitější a~sestává z~následujících kroků:
\begin{enumerate}
    \item Získání povrchu objektu
    \item Transformace povrchu
    \item Nastavení pomocných vlastností objektu
    \item Vykreslení do textury
\end{enumerate}\gap

\begin{figure}
    \centering
    \begin{subfigure}[t]{0.48\textwidth}
        \centering
        \includegraphics[height=6.5cm]{obrazky-figures/implementation/cmp-heightmapB.png}
        \caption{Původní objekt}
    \end{subfigure}
    \begin{subfigure}[t]{0.48\textwidth}
        \centering
        \includegraphics[height=6.5cm]{obrazky-figures/implementation/cmp-heightmap.png}
        \caption{Odpovídající výšková mapa}
    \end{subfigure}
    \caption{Příklad převodu objektu na výškovou mapu. Objekt obsahuje překrývající se geometrii, kterou je algoritmus schopný správně zpracovat. Objekt je také trochu deformován do čtvercové textury.}
    \label{fig:example-heightmap}
\end{figure}

\subsubsection{Získání povrchu}

Jako skutečný povrch tělesa je brán ten, který právě vidí uživatel, tedy včetně modifikátorů a~dalších úprav. Kvůli zvolenému způsobu získání geometrie je \textbf{ignorována lokální transformace} objektu. Specificky není brána v~potaz jeho rotace, neboť posun a~škálování dále upravuje vytvořený algoritmus. Průmět modelu na texturu je tedy prováděn pouze na lokální ose~$Z$.\gap

Získání dat z~objektu \texttt{obj} je definováno v~algoritmu~\ref{alg:vertex_eval}. V~daném algoritmu \texttt{depsgraph} uchovává informace ohledně současné scény, pomocí kterých lze povrch tělesa vyhodnotit. V~proměnné \texttt{mesh} pak lze najít seznam vrcholů objektu.\gap

\lstset{
  xleftmargin=.1\textwidth,
  caption={Algoritmus vyhodnocení geometrie $mesh$ vstupního objektu $obj$ pomocí stromu závislostí Blender scény $depsgraph$.},
}
\begin{lstlisting}[language=Python, label={alg:vertex_eval}]
depsgraph = bpy.context.evaluated_depsgraph_get()
eval = obj.evaluated_get(depsgraph)
mesh = bpy.data.meshes.new_from_object(eval)
\end{lstlisting}\gap

Neboť povrch tělesa může sestávat i~ze složitějších polygonů, tak před vykreslením do výškové mapy jsou polygony ještě explicitně rozděleny na trojúhelníky. Toho lze dosáhnout vytvořením \texttt{bmesh} objektu a~funkcí \texttt{bmesh.ops.triangulate}. Podobně jako stejná uživatelská operace nabízí různé způsoby štěpení, ty jsou ale ponechány na základním, tedy \texttt{BEAUTY}\footnote{Dokumentace: \url{https://docs.blender.org/api/current/bmesh.ops.html\#bmesh.ops.triangulate}}.\gap

Vytvořený objekt \texttt{bmesh} a~seznam vrcholů jsou následně použity k~převodu do OpenGL kontextu. Zde se algoritmus dle operačního systému (zjištěného funkcí \texttt{platform.system}) dělí na \textbf{dvě větve}. V~obou případech je cílem vytvořit seznam trojic vrcholů jež trojúhelníky tvoří. Povrch tak může být tvořen libovolným počtem nespojitých ploch a~polygony mohou mít libovolné pořadí. Tento přístup je také nutný, neboť aplikace Blender žádné pořadí polygonů nezaručuje. Daný způsob uložení vrcholů odpovídá formátu \texttt{TRIANGLES}, jež bude specifikován při vykreslování.\gap

Na platformě Windows lze pro zefektivnění vykreslování využít indexace vrcholů. Souřadnice vrcholů jsou nalezeny ve vlastnosti \textit{co} jednotlivých prvků seznamu vrcholů. Indexy pak lze získat algoritmem~\ref{alg:indexing} nad dříve vytvořeným \texttt{bmesh} objektem. Procedůře \texttt{Append} zde přidává argument na konec seznamu indexů.\gap

\begin{algorithm}
\setstretch{1.15}
\caption{Získání seznamu indexů\label{alg:indexing}}
\SetKwFunction{Append}{Append}
\For{$face$ in $bmesh.faces$} {
    \For{$vertex$ in $face.verts$} {
        \Append{indices, vertex.index}
    }
}
\end{algorithm}

Při testování na platformě Ubuntu a~v prostředí WSL knihovna ModernGL vykazovala neočekávané chování při využití indexace. Problém je více rozebrán v~sekci~\ref{limitace}. Zde je tedy využit celý seznam vrcholů s~duplicitními prvky. Postup je stejný jako algoritmus~\ref{alg:indexing}, akorát se akumulují přímo pozice vrcholů.\gap

Výsledné seznamy pak slouží k~vytvoření objektu \texttt{VertexArray}, jež potřebuje jako vstupy ModernGL typ \texttt{Buffer}. Oba seznamy jsou nejprve převedeny na \texttt{numpy} vektory a~pozice vrcholů ještě na desetinná čísla o~čtyřech bytech (formát \texttt{f4}). Následně jsou konvertovány na byty, z~nichž lze vytvořit \texttt{Buffer} objekty. Celý převod tedy vypadá následovně:\gap

\begin{lstlisting}[language=Python]
ctx.buffer(data=np.array(vertices).astype('f4').tobytes())
\end{lstlisting}

\subsubsection{Transformace}
Posledním prvkem potřebným k~výpočtu mapy je transformační matice objektu. Cílem dané operace je tvarovat objekt tak, aby zaplnil co nejvíce výsledné textury. To tedy znamená, že musí být v~OpenGL transformován do krychle o~souřadnicích od $-1$ do $1$. Pro jednoduchost následného výpočtu je souřadnice $Z$ rovnou převedena do rozmezí od $-1$ do $0$, vyšší terén je tedy blíže k~pozorovateli. To také dovoluje snímat překrývající povrch, jelikož nižší (a tedy vzdálenější) fragmenty budou zahozeny.\gap

K vytvoření matice tranformace využívá modul kvádrového obalu tělesa \texttt{bound\_box} počítaného aplikací Blender. Jedná se o~matici obsahující souřadnice jeho osmi vrcholů. Střed daného kvádru je pak průmerem souřadnic opačných stěn a~škálovací vektor $v$ je pak dán vzorcem~\ref{eq:scaling}.\par

\begin{equation}
\begin{split}
s_x & = \frac{2}{\left(v_x^+ - v_x^-\right)} \\
s_y & = \frac{2}{\left(v_y^+ - v_y^-\right)} \\
s_z & = \frac{1}{\left(v_z^+ - v_z^-\right)}
\end{split}
\label{eq:scaling}
\end{equation}

V dané rovnici platí $v_{x,y,z}^+ > v_{x,y,z}^-$. Jsou-li strany kvádru pronásobeny odpovídajícími prvky vektoru, pak je celý model v~mezích uvedených výše. Dále je třeba započíst posun objektu. Pro střed kvádru $c$ a~škálovací vektor $s$ je pak transformační matice dána vzorcem:\par
\begin{equation}
M = \begin{pmatrix}
s_x & 0 & 0 & -c_x \cdot s_x\\
0 & s_y & 0 & -c_y \cdot s_y\\
0 & 0 & -s_z & 0{,}5 + c_z \cdot s_z\\
0 & 0 & 0 & 1
\end{pmatrix}
\end{equation}\gap

\noindent Důvodem záporného znaménka u~osy $Z$ je překlopení směrem ke kameře, jež je v~záporném směru. Společně s~výpočtem dané matice se \textbf{nastavuje poměr stran} objektu --- dvě proměnné v~datech objektu ve směrech $XY$ a~$Z$, jež jsou následně využity v~algoritmech eroze. Jejich výpočet je dán:\par
\begin{equation}
\begin{split}
d_{xy} & = \frac{s_x}{s_y}\\
d_z & = \frac{s_x}{s_z}
\end{split}
\label{eq:object_aspect}
\end{equation}\gap

\subsubsection{Volání shaderu}
Nyní jsou již připravena data pro vykreslení. Následovně je vytvořen \texttt{Framebuffer} objekt (dále zvaný FBO) s~dvěma napojenými texturami --- hloubkovou, jež dovoluje překrývání v~modelu, a~barevnou, jež bude výsledná výšková mapa. Nejprve je ale třeba izolovat vykreslování od zbytku aplikace.\gap

Aby nebylo ovlivněno rozhraní programu, tak je z~daného FBO vytvořen ještě objekt zvaný \texttt{Scope}\footnote{Ukázka práce s~objektem: \url{https://moderngl.readthedocs.io/en/latest/reference/scope.html}}, ve kterém samotné vykreslení proběhne. Jemu je nastaven příznak \texttt{DEPTH\_TEST}, jež povoluje zahazování fragmentů na základě hloubky. Příznak \texttt{CULL\_FACE}, jež zahazuje odvrácené polygony, nastaven není, orientace polygonů v~Blenderu tedy neovlivní jejich vykreslení. Možnost takto nezobrazovat polygony přímo v~Blenderu tedy také není brána v~potaz a~vyhodnocený porvch může vypadat jinak, než jak ho vidí uživatel.\gap

Nastavení příznaků lze i~mimo daný objekt, vede to ale k~\textbf{zneviditelnění} většiny uživatelského rozhraní. Nápodobně použití \texttt{FBO} napřímo vede k~\textbf{uzamčení} modrého a~zeleného kanálu celé aplikace, neboť použitá textura má pouze červený. Tyto změny \textbf{nelze vrátit}, leda restartováním aplikace.\gap

Samotné vykreslení se skládá ze dvou částí --- transformace modelu ve vertex shaderu a~následné uložení výšky ve fragment shaderu. Vykreslování je voláno s~parametrem \texttt{TRIANGLES}, jež udává výše zmíněný formát vstupních vrcholů po trojicích.\gap

První fáze tedy převádí pozice vrcholů na homogenní souřadnice (typ \texttt{vec4}) a~následně je násobí transformační maticí, jež přijímá jako \textit{uniform} proměnnou. Výslednou pozici ukládá jak do \texttt{gl\_Position} tak do vstupu fragment shaderu. Neboť výšky jsou v~tomto bodě záporné, tak je výsledná barva (její první komponenta $red$), nastavena následovně:\par
\begin{equation}
red = 1 - pos_z
\end{equation}\gap

\noindent Tím je zápis do textury dokončen a~nyní uchovává mapu modelu.\gap

\subsection{Výsledné nastavení}
Po vytvoření samotné textury výškové mapy je třeba ji ještě uložit do entity. Základní mapa objektu je uvolněna a~na její místo je dosazena nová textura. Neexistuje-li základní mapa pro entitu před nastavením, pak dojde i~k~uvolnění zdrojové mapy a~nahrazením kopií nové textury.

\section{Eroze}
Hlavní funkcionalitou rozšíření je právě eroze, jež je v~samostatných modulech rozdělena na erozi termální a~vodní. Oba typy mají stejnou strukturu, jež se dělí na tři funkce:\par
\begin{enumerate}
    \item Příprava eroze
    \item Provedení
    \item Uložení a~úklid
\end{enumerate}\gap

\noindent Vstupem všech tří funkcí je buď objekt, nebo obrázek, na které se eroze bude aplikovat. Zbytek potřebných dat je přístupný buď globálně, nebo skrze tyto entity. Důvodem rozdělení na tři funkce je potenciální rozšíření na responzivní uživatelské rozhraní, kdy fáze \textit{provedení} by byla volána několikrát, v~současném stavu ale tato funkcionalita není implementována.\gap

Společná pro přípravné funkce obou typů je kontrola existence \textit{modelové} mapy odkazované objektem. Není-li nalezena, pak ještě nebyla vytvořena, nebo je neplatná. V~tom případě je voláno generování výškové mapy probrané v~sekci~\ref{sec:heightmap}. Součástí inicializace je také tvorba textur a~jejich uložení do globální proměnné \texttt{common.data}, neboť musí přetrvat napříč zmíněnými funkcemi.\gap

Společný výstup obou modulů je přímé nastavení \textit{současné} mapy entity a~případné uvolnění přepisované textury. Následující podkapitoly zacházejí do detailu jednotlivých algoritmů eroze.

\subsection{Vodní eroze}

Model vodní eroze použitý v~rozšíření je založený na simulaci částicemi. Tato kapitola se bude zaměřovat na odlišnosti oproti typu simulace popsaném v~teoretické části. Tato kapitola se nejprve zaměří na vstupy modelu a~až dále na proces simulace včetně napojení na rozšíření. Příklad výsledku vodní eroze ilustruje obrázek~\ref{fig:example-water-erosion}.\gap

\begin{figure}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/implementation/cmp-water.png}
    \caption{Ilustrace výsledku vodní eroze. Vlevo je původní povrch, vpravo je výsledná geometrie po erozi.}
    \label{fig:example-water-erosion}
\end{figure}

\subsubsection{Vstupy modelu}

Simulační algoritmus byl obohacen o~další výstupy týkající se procesu eroze, zavádí tedy několik dalších nastavení. Veškeré konstanty modelu jsou nastavitelné externě jako \textit{uniform} proměnné:\par
\begin{itemize}
    \item Počet iterací (životnost kapky)
    \item Síla eroze
    \item Síla depozice
    \item Maximální rychlost
    \item Odpor
    \item Faktor kapacity
    \item Kontrast eroze
    \item Kontrast depozice
    \item Síla zbarvení
\end{itemize}\gap

\noindent Veškeré hodnoty zde \textbf{musí být kladné}. Pro síly eroze a~sedimentace platí, že musí být menší než 0,5, Vyšší hodnoty mohou způsobit oscilaci povrchu a~nestabilitu eroze. Dále odpor je zde \textbf{násobitel rychlosti}, tedy platí $drag <= 1$. Má-li kapka například v~každé iteraci ztratit 20~\% rychlosti, musí být proměnná odporu nastavena na 0,8.\gap
Pro faktor kapacity platí, že by měl být řádově v~setinách, naopak kontrasty jsou řádově v~desítkách. Síla zbarvení je znovu násobitel, tedy menší než $1$. Hodnota maximální rychlosti může být v~podstatě libovolná a~její základní hodnota je nastavena na 2. Zrychlení nápodobně může mít i~vyšší hodnoty, ale nejlépe by měla být menší než 1. Porovnání vlivu různých vstupů na výslednou mapu lze vidět v~ilustraci~\ref{fig:exmaple-erosion-inputs}.\gap

\begin{figure}
    \centering
    \begin{subfigure}[t]{0.49\linewidth}
        \centering
        \includegraphics[width=\linewidth]{obrazky-figures/implementation/f-accel.png}
        \caption{Simulace s vysokým zrychlením}
    \end{subfigure}
    \begin{subfigure}[t]{0.49\linewidth}
        \centering
        \includegraphics[width=\linewidth]{obrazky-figures/implementation/f-capacity.png}
        \caption{Simulace s vysokou kapacitou}
    \end{subfigure}
    \begin{subfigure}[t]{0.49\linewidth}
        \centering
        \includegraphics[width=\linewidth]{obrazky-figures/implementation/f-short.png}
        \caption{Simulace s krátkou životností kapek}
    \end{subfigure}
    \begin{subfigure}[t]{0.49\linewidth}
        \centering
        \includegraphics[width=\linewidth]{obrazky-figures/implementation/f-smooth.png}
        \caption{Simulace s vysokou sílou eroze}
    \end{subfigure}
    \caption{Příklady vlivu různých parametrů na výslednou výškovou mapu.}
    \label{fig:exmaple-erosion-inputs}
\end{figure}

\noindent Vstupní textury algoritmu jsou následující:\par
\begin{itemize}
    \item Výšková mapa
    \item Hloubková mapa (množství eroze)
    \item Mapa sedimentu
    \item Mapa barev
\end{itemize}\gap

\noindent Tyto textury jsou typu \texttt{r32f}, tedy s~pohyblivou řádovou čárkou a~jedním kanálem, až na barevnou texturu, jež má čtyři. Společně s~těmito texturami jsou ještě definovány dva pravdivostní vstupy --- povolení zápisu barvy a~povolení zápisu sedimentace či množství eroze. Není-li tedy požadován odpovídající výstup uživatelem, pak není ani simulován. V~případě zákazu přesunu barvy se pak jedná o~znatelné zrychlení algoritmu.\gap

\subsubsection{Simulace}

První fází simulace je inicializace proměnných kapky. Každá částice začíná s~nulovou rychlostí, kapacitou a~nasycením. V~případě transportu barev je také načtena barva z~pixelu v~počáteční pozici. Pak následuje cyklus života kapky, jenž je limitovaný vstupním počtem iterací. Postup algoritmu je následující:\par
\begin{enumerate}
    \item Zrychlení částice
    \item Normalizace rychlosti
    \item Eroze a~sedimentace
    \item Posun částice
    \item Kontrola polohy
\end{enumerate}\gap

V každé iteraci jsou na začátku získány výšky sousedních buněk ve čtyřokolí. Pro účely dalších výpočtů je ještě zjištěno jejich minimum a~maximum. U výšek okolních buněk nedochází k~interpolaci, počítá se pouze se zaokrouhlením současné pozice kapky na nejbližší texel. Stejně je získána i~výška přímo pod kapkou.\gap

Proces zrychlení kapky je pak odlišný od modelu zmíněného v~teoretické části~\ref{sec:particle_theory}. Náklon povrchu je uvažován \textbf{jen ve směru pohybu} kapky a~to v~nezávisle v~osách $X$ a~$Y$. Pro výšku kapky $h$ na souřadnicích $x,y$, rychlost $v$ a~konstantu zrychlení $a$ je rychlost přepočítána dle algoritmu~\ref{alg:erosion_acceleration}.\gap

\begin{algorithm}
\setstretch{1.15}
\caption{Výpočet zrychlení částice\label{alg:erosion_acceleration}}
\uIf{$v_x > 0$ and $\left(h - h_{+x}\right) \leq drop_{max}$} {
    $v_x \gets v_x + a~\cdot \left(h - h_{+x}\right)$
} \ElseIf{$\left(h - h_{-x}\right) \leq drop_{max}$} {
    $v_x \gets v_x - a~\cdot \left(h - h_{-x}\right)$
}
\gap
\uIf{$v_y > 0$ and $\left(h - h_{+y}\right) \leq drop_{max}$} {
    $v_y \gets v_y + a~\cdot \left(h - h_{+y}\right)$
} \ElseIf{$\left(h - h_{-y}\right) \leq drop_{max}$} {
    $v_y \gets v_y - a~\cdot \left(h - h_{-y}\right)$
}
\gap
\If{$h < min_h$} {
    $v \gets 0$
}

\end{algorithm}

Je-li skok mezi současnou a~následující buňkou příliš velký, pak rychlost zůstane nezměněna. To zabraňuje tvorbě artefaktů na okrajích nebo vedle prázdných prostor textury. Velikost přijatelného sestupu $drop_{max}$ kapky je nastavitelná uživatelem.\gap

Závěr algoritmu zastaví kapku, nachází-li se v~prohlubni, tedy je-li současná výška nižší než celé okolí. Tento krok omezuje vytváření prohlubní pod strmými povrchy při silněji nastavených vstupech.\gap

Následujícím krokem je nastavení kapacity a~normalizace rychlosti, aby kapka nepřeskočila texely při pohybu. Nulová rychlost je ponechána jako nulová. Pro maximální rychlost $v_{max}$ a~faktor kapacity $f_c$ je postupováno dle algoritmu~\ref{alg:erosion_normalization}.\par

\begin{algorithm}
\caption{Normalizace rychlosti a~výpočet kapacity\label{alg:erosion_normalization}}
$capacity \gets f_c \cdot |v|$\gap
\If{$|v| \neq 0$} {
    $v \gets v_{max} \cdot v~/ |v|$
}
\end{algorithm}

\subsubsection{Eroze a~sedimentace}

\noindent Stejně jako v~modelu z~teoretické části, následující krok eroze a~sedimentace se odvíjí od nasycení a~kapacity. Je-li kapacita větší než nasycení, pak dojde k~erozi, jinak je přebytek upuštěn na terén. Síla eroze a~sedimentace zde pouze násobí množství materiálu, jež je takto přesunuto. Dále oba procesy mají přídavnou podmínku. Sedimentace \textbf{nemůže proběhnout}, pokud je současný bod výše než zbytek okolí. Množství uloženého sedimentu je také omezeno do výšky nejvyššího souseda. Nápodobně eroze nemůže prohloubit bod pod minimum okolí.\gap

Sedimentace probíhá pouze přímo v~bodě pod částicí (zaokrouhleným na nejbližší pixel), jak bylo zmíněno v~kapitole~\ref{sec:particle_theory}. Množství sedimentu je v~této fázi také potenciálně přičteno do textury depozice. Dané množství je násobeno konstantou kontrastu, aby byla změna viditelná.\gap 

Eroze je naopak aplikovaná na nejbližší čtyři pixely ke kapce a~relativní vliv je získán interpolací mezi buňkami. Pro polohu kapky $pos$, požadované množství materiálu $m$ a~minimum okolí $h_{min}$ je eroze provedena dle algoritmu~\ref{alg:erosion_interp}. Výstupy algoritmu jsou také množství erodovaného materiálu $amt$ v~jednotlivých buňkách.\gap

\begin{algorithm}
\setstretch{1.1}
\caption{Interpolace eroze\label{alg:erosion_interp}}
$corner \gets pos - \left(0.5, 0.5\right)$
$f \gets corner - \lfloor corner\rfloor$ \tcp{Souřadnice v~rozmezí $[0,1)$}
\gap
\If{$h > h_{min}$} {
    \tcp{Množství zvětraného materiálu pro danou buňku}
    $amt \gets m \cdot \left(1 - f_x\right) \cdot \left(1 - f_y\right)$\\
    $h \gets h - amt$
}\gap
\tcp{Soused v~kladném směru osy $X$}
\If{$h_{+x} > h_{min}$} {
    $amt_{+x} \gets m \cdot f_x \cdot \left(1 - f_y\right)$\\
    $h_{+x} \gets h_{+x} - amt_{+x}$
}\gap
\If{$h_{+y} > h_{min}$} {
    $amt_{+y} \gets m \cdot \left(1 - f_x\right) \cdot f_y$\\
    $h_{+y} \gets h_{+y} - amt_{+y}$
}\gap
\If{$h_{+xy} > h_{min}$} {
    $amt_{+xy} \gets m \cdot f_x \cdot f_y$\\
    $h_{+xy} \gets h_{+xy} - amt_{+xy}$
}\gap
\end{algorithm}\gap

Proměnná $corner$ v~algoritmu~\ref{alg:erosion_interp} slouží k~získání nejbližší čtveřice buněk ke kapce. Zaokrouhlením pozice kapky by byla získána buňka, ve které se nachází. Zaokrouhlením pozice posunuté o~polovinu buňky je získán nejnižší střed, jež je ke kapce blíže než $1$ v~obou souřadnicích.\gap

Neboť vzdálenosti buněk jsou vždy rovny jedné, tak následným odečtením lze přímo získat váhy dané čtveřice buněk. Podmínečné vyhodnocení jednotlivých sousedů je dále znovu za účelem, aby nemohla kapka vytvářet díry do povrchu. K~nasycení je následně přičtena suma zvětraného množství materiálu, tedy:\par
\begin{equation}
saturation \gets saturation + amt + amt_{+x} + amt_{+y} + amt_{+xy}
\end{equation}\gap

\noindent Závěr iterace přičítá normalizovanou rychlost k~pozici kapky. Zde je také kontrolována pozice částice, jestli není záporná. Pokud ano, cyklus je rovnou ukončen. Důvodem k~této kontrole je transport barev, jež je rozebrán dále. Při záporných hodnotách pozice může docházet k~tvorbě vizuálních artefaktů na okraji textury.

\subsubsection{Volání z~rozšíření}

Algoritmus eroze byl ponechán jako fragment shader, neboť přepsání na výpočetní shader nevedlo ke znatelnému zrychlení. Při každém volání funkce \textit{provedení} musí být znovu vytvořeno VAO. Je-li ponecháno v~proměnné zatímco aplikace Blender znovu převezme kontrolu nad kontextem, pak při znovupoužití již nebude správně fungovat.\gap

Než je možné začít vykreslení, je nejprve nutné mapovat správně hodnoty vstupů. Rozsahy prezentované uživateli byly nastaveny obecně do rozsahu $[0,1]$, aby bylo rozhraní přivětivé. Tento rozsah je ale třeba transformovat na povolené hodnoty zmíněné výše ve vstupech algoritmu. V~případě eroze se jedná pouze o~násobení zmíněnými hodnotami a~v případě odporu odečtení od hodnoty $1$, aby s~vyšší hodnotou správně klesal násobitel rychlosti.\gap

Jako vertex shader algoritmu slouží soubor zvaný \texttt{identity.vert}, jež nijak nemění pozice vrcholů. Vstupní model se skládá ze dvou trojúhelníků, jež tvoří čtverec o~souřadnicích od $-1$ do $1$, tedy zabírající celé okno. Souřadnice ve zpracovávané textuře je získána přímo ze zabudované proměnné \texttt{gl\_FragCoord}.\gap
Neboť simulace \textbf{neřeší synchronizaci} kapek a~časů zápisu nebo čtení textur, tak může dojít k~\textbf{vadným přepisům} map. Aby se zmírnil vliv částic mezi sebou, tak simulace začíná vždy jen na podmnožině textury. V~základním nastavení je kapka vytvořena na každém čtvrtém řádku a~sloupci, tedy jedna na každý čtverec 4 pixelů. Velikost tohoto dělení je zde značena $subdiv$. Různé terény potřebují různé odstupy kapek a~menší hodnoty vedou k~rychlejší simulaci, hodnota je tedy nastavitelná uživatelem. Jako vstup algoritmu tedy figuruje dvourozměrný vektor posunu \texttt{off} a~uvnitř kódu \texttt{GLSL} je počáteční pozice kapky počítána následovně:\par
\begin{equation}
base = off + subdiv \cdot gl\_FragCoord_{XY} + \left(0.5, 0.5\right)
\end{equation}\gap

\noindent Samotné volání vykreslení tedy probíhá ve třech cyklech dle algoritmu~\ref{alg:erosion_drawing}.\par

\begin{algorithm}
\setstretch{1.1}
\SetKwFunction{SetUniform}{SetUniform}
\SetKwFunction{Render}{Render}
\caption{Cyklus vykreslení\label{alg:erosion_drawing}}
\For{$i$ from $0$ to $iterations - 1$} {
    \For{$y$ from $0$ to $subdiv-1$} {
        \For{$x$ from $0$ to $subdiv-1$} {
             \SetUniform{off, x, y}
             \Render{TRIANGLES}
        }
    }
}
\end{algorithm}\gap

\noindent Kvůli implementaci jako fragment shader je také v~přípravné funkci potřeba vytvořit FBO, do kterého se bude vykreslení provádět. Data ve výsledné textuře nemají žádný význam, pouze pro potenciální ladění, a~v použitém kódu je výsledná barva nastavena na černou. Kvůli provádění vykreslování po částech jsou rozměry FBO děleny a~zaokrouhleny nahoru, tedy pro rozměry výškové mapy $w_H$ a~$h_H$ platí:
\begin{equation} \label{eq_aspect}
\begin{split}
w_{FBO} & = \left\lceil\frac{w_H}{subdiv}\right\rceil\\
h_{FBO} & = \left\lceil\frac{h_H}{subdiv}\right\rceil
\end{split}
\end{equation}\gap

\noindent Objekt FBO může přetrvat mezi funkcemi na rozdíl od vytvořeného VAO. Zakončení prováděcí funkce tedy také zahrnuje uvolnění VAO.

\subsubsection{Uložení a~úklid}

Jak bylo zmíněno na začátku kapitoly, po simulaci eroze je nastavena současná mapa a~případně je uvolněna existující textura. Mapy tvořené vodní erozí rozšíření označuje základním názvem \texttt{Particle 1}, pro rozlišení od automaticky tvořené mapy nebo termální eroze. Index nové textury se dále odvíjí od názvu zdrojové mapy.\gap

Neboť výškové mapy jsou čistě pod správou rozšíření a~není dovoleno jejich názvy měnit, tak odvození indexu lze jednoduše implementovat regulárním výrazem. V~názvu zdroje je hledáno číslo na konci řetězce, tedy výrazem \verb|\d+$|. Je-li nalezeno, pak je následně parsováno, inkrementováno a~přidáno na konec nového názvu. Jinak je použito základní jméno pro typ eroze.\gap

Mimo nastavení výškové mapy vodní eroze také vytváří až tři přídavné textury --- hloubku, sedimentaci a~transportovanou barvu. Další nakládání s~těmito texturami po jejich vytvoření je už mimo kompetenci modulu, tudíž jsou vráceny jako seznam o~pevné délce. Nejsou-li některé generovány, pak je na jejich pozici hodnota \texttt{None}. Finální kroky funkce pak spočívájí v~uvolnění FBO i~\texttt{Scope} objektů.

\subsection{Transport barev}
\label{sec:color_transport}

Rozšíření jako součást vodní eroze také nabízí transport barev, ale jelikož textury poskytnuté uživatelem nejsou nějak omezeny rozlišením a~mohou být zcela nezávislé na zvětrávaném objektu, tak jejich zpracování vyžaduje navíc krok překreslení. Ukázka transportu barev je v~ilustraci~\ref{fig:example-color}.\gap

\begin{figure}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/implementation/cmp-color.png}
    \caption{Ilustrace transportu barev. Vlevo je původní textura, vpravo je výsledek po transportu erozí. Výška povrchu je nezměněna.}
    \label{fig:example-color}
\end{figure}

\subsubsection{Překreslení}
Jak bylo zmíněno v~generování výškové mapy, obrázky v~aplikaci Blender vždy vrací čtyři kanály jako souvislý seznam pixelů. V~případě barevné mapy tedy není třeba seznam filtrovat a~je rovnou převeden na ModernGL texturu. Následně je vytvořen FBO o~stejné velikosti, na kterém je překreslovací program spuštěn. Jako vertex shader algoritmu slouží znovu soubor zvaný \texttt{identity.vert}. Ten pro další fázi vykreslování vypočítává \texttt{UV} souřadnice z~pozic vrcholů $pos_{x,y}$:\par
\begin{equation}
\begin{split}
u & = \frac{1}{2}pos_x + \frac{1}{2} \\
v & = \frac{1}{2}pos_y + \frac{1}{2}
\end{split}
\end{equation}\gap

\noindent Mapování obrázku na texturu o~správné velikosti a~jeho interpolace je zde provedena automaticky díky OpenGL. Obrázek je předán jako typ \texttt{sampler2D}, ze kterého jsou následně funkcí \texttt{texture} na UV souřadnicích čteny pixely.\gap

Podobně jako u~výškové mapy musí být dále v~implementaci řešen barevný prostor obrázku. Veškeré textury vytvořené rozšířením mají lineární barevný prostor a~využívají čísla s~pohyblivou řádovou čárkou. Při použití sRGB obrázku jako vstupu by výsledek byl znatelně tmavší po zpětném převodu. V~tomto případě je provedena linearizace jednotlivých kanálů rovnou při mapování obrázku. Proces je tedy stejný jako u~výškové mapy v~algoritmu~\ref{alg:srgb}.\gap

\subsubsection{Simulace}
Transport barev je v~kódu eroze implementován tak, že každá částice uchovává svou aktuální barvu jednoduše reprezentovanou vektorem. Její hodnota je inicializovaná na barvu texelu, kde částice začíná. Dojde-li v~iteraci k~erozi materiálu, pak je přímo pod kapkou získána barva povrchu z~textury a~ta je přičtena k~současné barvě. Množství, jež je nahrazené, ovládá vstupní proměnná, zde dále značená $f_{col}$. Výpočet nové barvy částice je následující:\par
\begin{equation}
color = f_{col} \cdot map_{col}\left(pos\right) + color \cdot \left(1 - f_{col}\right)
\end{equation}\gap

\noindent Barva je při erozi snímána jen z~nejbližšího texelu. Naopak při sedimentaci dochází k~interpolaci mezi sousedními buňkami. Proces transportu barev se touto volbou liší od procesu eroze, kde dochází k~sedimentaci pouze přímo pod částicí. Oblasti naneseného materiálu a~míchané barvy tedy nebudou odpovídat. Přístup byl ale zvolen pro vytvoření jemnější výsledné textury.\gap

Proces nanesení barvy je podobný erozi okolí zmíněné výše v~algoritmu~\ref{alg:erosion_interp}. V~algoritmu~\ref{alg:color_interp} jsou nejdříve získány váhy okolních texelů a~následně je vypočítán vliv na jednotlivé buňky, zde značený jako $m$. Množství nahrazené barvy $f_{col}$, jež je stejné jako pro zbarvení kapky, je pak vlivem násobeno.\par

\begin{algorithm}
\setstretch{1.15}
\caption{Interpolace barvy\label{alg:color_interp}}
$corner \gets pos - \left(0.5, 0.5\right)$\\
$f \gets corner - \lfloor corner\rfloor$ \tcp{Souřadnice v~rozmezí $[0,1)$}
\gap
$m \gets f_{col} \cdot \left(1 - f_x\right) \cdot \left(1 - f_y\right)$\\
$map \gets map \cdot \left(1 - m\right) + color \cdot m$
\gap
$m_{+x} \gets f_{col} \cdot f_x \cdot \left(1 - f_y\right)$\\
$map_{+x} \gets map_{+x} \cdot \left(1 - m_{+x}\right) + color \cdot m_{+x}$
\gap
$m_{+y} \gets f_{col} \cdot \left(1 - f_x\right) \cdot f_y$\\
$map_{+y} \gets map_{+y} \cdot \left(1 - m_{+y}\right) + color \cdot m_{+y}$
\gap
$m_{+xy} \gets f_{col} \cdot f_x \cdot f_y$\\
$map_{+xy} \gets map_{+xy} \cdot \left(1 - m_{+xy}\right) + color \cdot m_{+xy}$
\end{algorithm}\gap

\subsection{Termální eroze}

Algoritmus termální eroze je rozdělen na dvě části, které jsou implementovány skrze výpočetní shadery. Na rozdíl od vodní eroze simuluje erozi pomocí celulárních automatů.\gap

Mezi fázemi výpočtu je předávána pomocná textura. Zde je uchováváno množství, jež každá buňka vyžaduje od svého okolí, nebo jež je schopná poskytnout. Na základě dané textury je pak každá buňka schopna nezávisle vypočítat svou novou výšku bez ztráty materiálu. Hodnoty v~této textuře jsou dále označovány jako \textit{žádosti}. Ukázka termální eroze je v~ilustraci~\ref{fig:example-thermal}.\gap

\begin{figure}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/implementation/cmp-thermal.png}
    \caption{Ilustrace simulace termální eroze. Vlevo je původní povrch, vpravo je výsledek eroze.}
    \label{fig:example-thermal}
\end{figure}

\subsubsection{Fáze výpočtu}
V této fázi jsou prozkoumány sousední buňky a~následně je vyplněna textura žádostí. V~dané implementaci je uvažováno pouze čtyřokolí, textura tedy obsahuje čtyři kanály.\gap

Prvním krokem je získání množství materiálu, jež by mělo být předáno okolí, zde značeno $supply$, a~jež by mělo být sesunuto na zkoumanou buňku, značeno $demand$. Pro výšku buňky $h$ a~konstantu $T_\alpha$, jež specifikuje maximální náklon povrchu jako první derivace výšky, je proces zkoumání okolí ilustrován algoritmem~\ref{alg:thermal_requestA}.\gap

Výraz $T_\alpha \cdot l_n$ v~tomto algoritmu určuje maximální rozdíl výšek, při kterém bude náklon povrchu menší nebo roven sypnému úhlu. Dále vytvořený vektor $demand$ obsahuje pouze kladná čísla a~vektor $supply$ je naopak zcela záporný. Proměnné $mx$ a~$mn$ tedy určují největší rozdíly výšek nahoru a~dolů.\gap

\begin{algorithm}[H]
\setstretch{1.15}
\caption{Prozkoumání okolí\label{alg:thermal_requestA}}
$supply \gets \left[0,0,0,0\right]$\\
$demand \gets \left[0,0,0,0\right]$\gap

\For{$n$ in $neighbors$} {
    \If(\tcp*[h]{$l_n$ je vzdálenost k~buňce}){$|h_n - h| > T_\alpha \cdot l_n$} {
        \eIf{$h_n > h$} {
            $demand_n \gets h_n - h - T_\alpha \cdot l_n$
        } {
            $supply_n \gets h_n - h + T_\alpha \cdot l_n$
        }
    }
}\gap

$mx \gets max\left(demand\right)$\\
$mn \gets min\left(supply\right)$
\end{algorithm}\gap

Hodnoty $mn$ a~$mx$ jsou považovány za množství materiálu, jež je buňka maximálně schopná ztratit či získat. Vytvořené vektory jsou následně škálovány tak, aby dané množství přerozdělily mezi sousední buňky. Tento postup specifikuje algoritmus~\ref{alg:thermal_requestB}, jež dále využívá konstantu $f_s$, která specifikuje sílu eroze. Funkce \texttt{Clamp}, jež zde figuruje, omezí vstup na specifikované hranice. Je-li vstup roven \texttt{NaN}, k~čemuž by došlo v~případě nulových vektorů, pak je výstup roven nižší hranici. Komponenty výsledného vektoru jsou \textbf{záporné}, má-li být materiál přemístěn \textbf{do sousední buňky}. V~případě \textbf{kladné} hodnoty dojde k~přesunu \textbf{do zkoumané buňky}.\gap

\begin{algorithm}[H]
\setstretch{1.15}
\SetKwFunction{Clamp}{Clamp}
\caption{Výpočet žádostí\label{alg:thermal_requestB}}
    $C_d \gets f_s \cdot mx \div \sum_{d \in demand} d$\\
    $C_d \gets$ \Clamp{$C_d$, 0, 1}\gap
    
    $C_s \gets f_s \cdot mn \div \sum_{s \in supply} s$\\
    $C_s \gets$ \Clamp{$C_s$, 0, 1}\gap
    
    $request \gets supply \cdot C_s + demand \cdot C_d$
\end{algorithm}

\subsubsection{Fáze přesunu}

Tato fáze je spuštěna až po celkovém dokončení předchozí fáze. Každá buňka zde nezávisle přepočítá a~uloží svoji výšku. Část tohoto procesu je ilustrována v~algoritmu~\ref{alg:thermal_move}. Proměnná $r_{A \to B}$ zde značí hodnotu žádosti ze směru $A$ směrem k~$B$. Vektor žádostí zkoumané buňky je dále značen $request$ a~její výška $h$.\gap

V algoritmu dochází k~porovnávání poskytovaného a~požadovaného materiálu. Přičítána a~odečítána je pak vždy nižší z~daných hodnot, aby bylo zachováno maximální přesunutelné množství, jež si každá buňka stanovila. Daný proces je opakován pro všechny sousedy.\gap

\begin{algorithm}
\caption{Přesun materiálu z~levého souseda\label{alg:thermal_move}}
\setstretch{1.15}
\SetSideCommentLeft
\eIf(\tcp*[h]{Soused poskytuje materiál}){$r_{L\to R} < 0$} {
    \eIf(\tcp*[h]{Žádosti mají opačné znaménko}){$-r_{L\to R} > request_L$} {
        $h \gets h + request_L$
    } {
        $h  \gets h - r_{L\to R}$
    }
} (\tcp*[h]{Soused vyžaduje materiál}) {
    \eIf{$-r_{L\to R} < request_L$} {
        $h  \gets h + request_L$
    } {
        $h  \gets h - r_{L\to R}$
    }
}
\end{algorithm}

\subsubsection{Volání z~rozšíření}

Jak bylo zmíněno v~úvodu kapitoly, programy jsou implementovány jako výpočetní shadery. Vykreslování vyžaduje tři textury --- výškovou mapu, mapu žádostí a~volnou texturu, jež se s~výškovou mapou střídá.\gap

Výpočet je možné provádět jak pro osy $X$ a~$Y$, tak pro diagonály. Uživatel je schopný směr eroze nastavit, včetně možnosti střídání směrů v~každé druhé iteraci. Aby byl správně zachován sypný úhel, tak jsou délky mezi buňkami pro diagonály násobeny odmocninou ze dvou. Dané délky jsou programu předávány jako vstupní proměnné a~jsou rozlišeny na osy $X$ a~$Y$ (případně na hlavní a~vedlejší diagonálu).\gap

Algoritmus také respektuje poměr stran objektu, jež může být jiný než poměr stran textury. Délka mezi buňkami na ose $X$ je vždy nastavena na hodnotu $1$ a~pro osu $Y$ je využit poměr stran $d_{xy}$ vypočítáný při vytvoření výškové mapy.\gap

Funkce výškové mapy také vytváří vertikální poměr stran vzhledem k~ose $X$ značený $d_z$. Ten je brán v~potaz při převodu sypného úhlu na vstupní konstantu $T_\alpha$. Pro šířku textury $width$ a~sypný úhel $\alpha$ ve stupních je výpočet dán vzorcem~\ref{eq:t_alpha}. Specifikace poměrů stran je uvedena ve vzorci~\ref{eq:object_aspect} v~kapitole generování výškové mapy.

\begin{equation}
T_\alpha = \frac{\tan\left(\frac{\pi}{180} \cdot \alpha\right)}{width \cdot d_z}
\label{eq:t_alpha}
\end{equation}

\section{Aplikování výsledků}

Tato kapitola se zabývá nanesením výsledné výškové mapy po erozi na vstupní objekt, týká se tedy pouze práce s~objekty. Při erozi obrázků je uživateli jenom zobrazena výsledná textura.\gap

První a~společnou částí aplikování textury je převod na rozdíl mezi výslednou mapou a~původním modelem. Při zpětném nanesení textury tak bude odpovídat výsledné textuře. Operace je prováděna klonováním textury a~použitím výpočetního shaderu nad tímto duplikátem. Výsledná mapa reprezentuje nulový rozdíl hodnotou 0{,}5. Maximální záporný rozdíl je zakreslen černou barvou a~největší kladný rozdíl bílou.\gap

Dále zmiňované metody nanesení textury jsou limitovány na osu $Z$, neboť posun v~textuře je pouze výškový. Bez tohoto nastavení by došlo k~deformaci dle normály povrchu, jež může mít libovolný směr. Také by mohlo docházet k~vytváření převisů a~dalších artefaktů.

\subsection{Modifikátory}

Jednou z~možností deformace povrchu je takzvaný \texttt{Displacement} modifikátor. Výsledek eroze je díky modifikátoru okamžitě vyhodnocen a~je možné změny povrchu kombinovat s~dalšími modifikátory, jako je například teselace nebo vyhlazování geometrie. Jako vstup vyžaduje Blender texturu, do které lze nastavit vytvořený obrázek. Implementovaná funkce vytvoření modifikátoru se tedy skládá z~následujících kroků:\gap
\begin{enumerate}
    \item Použitá textura je zapsána do obrázku, čímž je i~aktualizován
    \item Je získán seznam modifikátorů
    \begin{enumerate}
        \item Je-li seznam prázdný, pak je generován nový \texttt{Displacement} modifikátor
        \item Není-li poslední prvek vytvořený rozšířením, pak je generován nový modifikátor
        \item Jinak je vybrán poslední prvek seznamu
    \end{enumerate}
    \item Pokud je již vytvořena Blender textura, tak je vybrána
    \item Jinak je textura vytvořena a~napojena
    \item Textuře je nastaven vytvořený obrázek
    \item Modifikátoru jsou nastaveny hodnoty
    \item Pokud již existuje pomocný objekt, pak je vybrán
    \item Jinak je vytvořen prázdný objekt
    \item Pomocný objekt je transformován a~nastaven modifikátoru
    \item Pomocný objekt je nastaven jako potomek erodovaného objektu
\end{enumerate}\gap

Limitování modifikátoru na osu $Z$ lze docílit přímo nastavením vlastnosti směru. Další vlastností jež musí být změněna je zdroj souřadnic. Vytvořenou Blender texturu není možné přímo přesouvat a~škálovat, rozšíření toho tedy dosahuje pomocným objektem.\gap

Nastavení transformace objektu je identické s~výpočtem~\ref{eq:scaling} při vytváření výškové mapy. Pozice objektu je nastavena dle středu obálky terénu a~rozměry dle šířek ve vodorovné ploše. Osa $Z$ objektu je nezměněna, neboť nemá na texturu žádný vliv.\gap

Jelikož použitá textura je normalizována, pak musí být nastavena správná síla modifikátoru. Vertikální škálování objektu je uloženo ve vlastnosti zmíněné v~rovnici výškové mapy~\ref{eq:object_aspect}. Díky převodu na rozdílovou mapu, jež změnší hodnoty na polovinu, je ale třeba brát dvojnásobek této vlastnosti, tedy:\par

\begin{equation}
strength = 2 \cdot d_z
\end{equation}

\subsection{Náhled}

Náhled výškové mapy je pro objekty implementován také přes modifikátor. Rozdílem je sdílení textury a~pomocného objekt, jež jsou stejné pro všechny náhledy. Při vytvoření nového náhledu je pomocný objekt přemístěn a~přetransformován. Náhled výsledku eroze je ilustrován obrázkem~\ref{fig:preview_example}.\gap

Pokud nahlížený objekt již má modifikátor vytvořený rozšířením, pak je zneviditelněn. Předpokladem je, že nahlížená eroze je nezávislá na předchozí operaci. Při rušení náhledu je naopak druhý modifikátor zpětně zviditelněn. V~globálních datech rozšíření je uchováván poslední objekt, jež měl vytvořený náhled. Jeho jméno slouží ke smazání modifikátoru daného objektu při vytváření nového náhledu. Při přepsání sdílené textury by jinak došlo k~neočekávaným změnám povrchu starého objektu.\gap

Operace jež mohou současnou mapu objektu smazat automaticky náhled ruší. Při rušení je zcela smazán dočasný obrázek, pomocný objekt, modifikátor i~Blender textura. Při odstranění je navíc ošetřeno potenciální přejmenování starého objektu, neboť uchovávané jméno by již nebylo platné. Je-li uchovávané jméno nesprávné, pak funkce prochází celý seznam objektů obsahujících náhledový modifikátor a~následně jej odstraní.\gap

\begin{figure}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/implementation/modifier_comp.png}
    \caption{Příklad modifikátoru a~náhledu eroze. U pravého terénu je vidět pomocný objekt jako černý kříž.}
    \label{fig:preview_example}
\end{figure}

\subsection{Materiály}

Dalším způsobem nanesení eroze na objekt je využití materiálů. Pro tento účel jsou použitelné dva uzly, jež aplikace Blender nabízí, a~to \texttt{Bump} mapování a~\texttt{Displacement} mapování. Oba způsoby, jež jsou zde dále rozebrány, se pokouší o~adaptovatelnost na uživatelem vytvořené materiály a~jejich struktury.\gap

Při implementaci byl také kladen důraz na vizuální jednoduchost výsledku. Společnou funkcí použitou pro oba způsoby je proto minimalizace uzlů materiálu. U vytvářených uzlů zabírajících velkou plochu nebo s~mnoha nezapojenými vývody, jako je například uzel texturových souřadnic, jsou dané vývody schovány. Tento proces spočívá v~nastavení vlastnosti \texttt{hide} jak uzlu samotného, tak všech jeho vstupů a~výstupů. Již zapojené vlastnosti zůstanou automaticky viditelné.\gap

Za účelem úklidu modifikovaného materiálu jsou také existující uzly přesouvány, aby pro nové prvky bylo místo. V~případě displacement mapování je posunut výstup materiálu vpravo. Posun ilustruje obrázek~\ref{fig:preview_reordering}.\gap

\begin{figure}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/implementation/material-shift.pdf}
    \caption{Ilustrace přesunu uzlů v~materiálu. Výstupní prvek je posunut vpravo aby bylo místo pro nové prvky.}
    \label{fig:preview_reordering}
\end{figure}

Dalším důležitým bodem jsou textury materiálu. Jako zdroj jejich mapování jsou napojeny generované souřadnice, jež pochází z~uzlu \texttt{Texture Coordinates}. Důvodem implementace je kompatibilita s~obecnými objekty a~s terény rozšíření A.N.T. Landscape. Dané souřadnice odpovídají těm použitým při tvorbě výškové mapy, výsledek je tedy správně mapován na terén, i~když nemá definovanou UV mapu. Například ve zmíněném rozšíření by jinak docházelo ke zobrazení pouze prvního pixelu textury napříč celým objektem.\gap 

\subsubsection{Bump mapování}

Tento způsob spočívá v~užití \texttt{Bump} uzlu, jež musí být napojen jako vstupní normála libovolného  \texttt{BSDF} uzlu, jež je podporuje. Výsledná deformace povrchu je pouze vizuální a~funguje jak pro Cycles, tak pro EEVEE vykreslování. Postup této metody se skládá z~následujících kroků:\par

\begin{enumerate}
    \item Použitá textura je zapsána do obrázku, čímž je i~aktualizován
    \item Nemá-li objekt materiál, pak je vytvořen
    \item První materiál v~seznamu je vybrán
    \item Proces je ukončen, je-li vytvořený \texttt{Bump} uzel již v~materiálu
    \item Nemá-li materiál výstup, pak je vytvořen
    \item Nemá-li shader, pak je přidán \texttt{Principled BSDF} a~napojen
    \item Proces je ukončen, má-li BSDF jiný vektorový vstup než \texttt{Bump}
    \item Pokud neexistuje, pak je vytvořen \texttt{Bump} uzel a~napojen
    \item Proces je ukončen, má-li \texttt{Bump} uzel zapojený vstup
    \item Je vytvořena textura a~napojena
    \item Textura je napojena na generované souřadnice
\end{enumerate}\gap

Dané kroky jsou také ilustrovány v~obrázku~\ref{fig:bumpmap}. \texttt{Principled BSDF} uzel byl zvolen, neboť se jedná také o~základní materiál tvořený aplikací. Uživateli také poskytuje mnoho možností jak materiál dále upravit. Zmíněné hledání a~vytvoření výstupu se dále dělí na podkroky dle vyhodnocovaného materiálu. Blender dovoluje specifikovat, pro který vykreslovací engine má být použit. Pořadí hledání je následující:\par
\begin{enumerate}
    \item Pro oba
    \item Jen pro Cycles
    \item Jen pro EEVEE
\end{enumerate}\gap

\begin{figure}[H]
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/implementation/bump-example.pdf}
    \caption{Ilustrace konfigurace pro bump mapování s~očíslovanými kroky tvorby uzlů}
    \label{fig:bumpmap}
\end{figure}

\subsubsection{Displacement mapování}

Druhým přístupem skrze materiály je pomocí \texttt{Displacement} uzlu, jež se napojuje přímo na výstup materiálu. Oproti bump mapování nepotřebuje vytvářet \texttt{BSDF} uzel. Kroky, jež jsou dále zobrazeny v~ilustraci~\ref{fig:displacement}, jsou následující:\par

\begin{enumerate}
    \item Použitá textura je zapsána do obrázku, čímž je i~aktualizován
    \item Nemá-li objekt materiál, pak je vytvořen
    \item První materiál v~seznamu je vybrán
    \item Proces je ukončen, je-li vytvořený \texttt{Displacement} uzel již v~materiálu
    \item Nemá-li materiál výstup, pak je vytvořen
    \item Proces je ukončen, má-li výstup jiný vektorový vstup než \texttt{Displacement}
    \item Je vybrán nebo vytvořen \texttt{Displacement} uzel
    \item Pokud byl uzel vytvořen, pak je limitován na osu $Z$
    \item Proces je ukončen pokud má \texttt{Displacement} uzel zapojený vstup
    \item Je vytvořena textura a~napojena
    \item Textura je napojena na generované souřadnice
\end{enumerate}\gap

\noindent \texttt{Displacement} je konfigurován tak, aby byl posun vrcholů pouze vertikální, neboť textura eroze má pouze vertikální rozdíly výšek. To je implementováno skrze vektorový vstup uzlu. Zde je zapojen výstup prvku \texttt{Normal}, bez jakýchkoliv změn jeho nastavení. Přímé zadání vektoru směřujicí v~ose $Z$ je možné, ale nemá správný účinek.\gap

\begin{figure}[H]
    \centering
    \includegraphics[width=0.85\linewidth]{obrazky-figures/implementation/displace-example.pdf}
    \caption{Ilustrace konfigurace pro displacement mapování s~očíslováním kroků tvorby uzlů}
    \label{fig:displacement}
\end{figure}

\subsection{Přímé zapsání a~Shape Keys}

Přímý zápis eroze do modelu je nabízen v~případě, kdy je zapnutý náhled eroze, nebo je vytvořený modifikátor. Zápis spočívá v~tom, že je procházen seznam modifikátorů až po položku vytvořenou rozšířením a~postupně jsou aplikovány. Je-li takových položek více, pak je aplikována pouze první. Modifikátory vytvořené rozšířením se identifikují pomocí předpony \texttt{HYD}.\gap

Podobným způsobem funguje využití shape keys. Zde je vybrán generovaný modifikátor ze seznamu a~operací \texttt{modifier\_apply\_as\_shapekey} z~modulu \texttt{ops.object} je aplikován. Příklad výsledku je ilustrován v~obrázku~\ref{fig:shape_keys}. Pokud již vrstva byla vygenerován, pak je nejdříve ostraněna. Použitý modifikátor je vyjmut ze seznamu. Po použití této operace Blender zabraňuje aplikování modifikátorů, výše zmíněný přímý zápis je poté tedy vypnut rozšířením, dokud vrstvy nejsou odstraněny.\gap

Neboť přímé zapsání změní samotný model, tak současná výšková mapa je zároveň zapsána jako zdrojová i~modelová. Aplikování jako Shape Key zapíše současnou mapu jako zdrojovou, ale ne modelovou, neboť seznam Shape Key stále zachovává původní model jako bázi.

\begin{figure}[H]
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/implementation/shape_comp.png}
    \caption{Ilustrace konfigurace pro Shape Keys. Vrstva vytvořená rozšířením je \texttt{HYD\_Shape}. Pro hodnotu 1 má stejný výsledek jako modifikátor.}
    \label{fig:shape_keys}
\end{figure}

\section{Navigace}
\label{sec:nav}

V~rozšíření je dán důraz na správné informování uživatele. Jsou-li výsledky zobrazitelné uvnitř aplikace, pak se snaží rozšíření k~těmto výsledkům uživatele navigovat. Za tímto účelem bylo třeba implementovat funkci, jež vybere nebo vytvoří okno uvnitř aplikace.\gap

Funkce výběru nebo vytvoření okna se snaží brát ohled na existující rozestavení rozhraní. Pro danou funkci bylo zvoleno pořadí výběru oken uvedené níže. K jednotlivým oknům aplikace lze přistoupit skrze seznam \texttt{screen.areas} uvnitř kontextu.\par
\begin{enumerate}
    \item Existující okno správného typu, jež není aktivní
    \item Rozdělení aktivního okna, je-li správného typu
    \item Rozdělení okna 3D pohledu
    \item Poslední okno v~seznamu, jež není přehled scény nebo okno vlastností
    \item Poslední okno v~seznamu
\end{enumerate}\gap

\noindent Dělení okna záleží na nastavených preferencích rozšíření. Možnosti, které jsou ilustrovány v~obrázku \ref{fig:nav_split}, jsou následující:\par
\label{list:nav_split}
\begin{itemize}
    \item Vždy vodorovně
    \item Vždy vertikálně
    \item Dle delšího rozměru okna
\end{itemize}\gap

\begin{figure}
    \centering
    \begin{subfigure}[t]{0.3\linewidth}
        \centering
        \includegraphics[width=0.8\linewidth]{obrazky-figures/implementation/split-horizontal.pdf}
        \caption{Horizontální dělení}
    \end{subfigure}
    \begin{subfigure}[t]{0.3\linewidth}
        \centering
        \includegraphics[width=0.8\linewidth]{obrazky-figures/implementation/split-vertical.pdf}
        \caption{Vertikální dělení}
    \end{subfigure}
    \begin{subfigure}[t]{0.3\linewidth}
        \centering
        \includegraphics[width=0.8\linewidth]{obrazky-figures/implementation/split-short.pdf}
        \caption{Dělení podle delšího rozměru}
    \end{subfigure}
    \caption{Možnosti rozdělení okna. Číslem~1 je značena část, kde zůstane původní okno. Nové okno bude v~části~2.}
    \label{fig:nav_split}
\end{figure}

Rozdělení okna lze provést funkcí \texttt{area\_split} modulu \texttt{ops.screen}, nejdříve je ale třeba dané okno \textbf{dočasně vybrat}. Toho je dosaženo voláním metody kontextu \texttt{temp\_override} s~nastaveným argumentem \texttt{area}. Okno vybrané uživatelem zůstane po ukončení procesu zachované.\gap

Nově vytvořené okno lze najít na konci seznamu poskytnutého kontextem. Typ okna lze přepínat nastavením vlastnosti \texttt{type} a~v případě grafového editoru je ještě třeba nastavit podtyp, tedy vlastnost \texttt{ui\_type}.\gap

Ve vytvořeném okně nelze přímo nastavovat vlastnosti požadované jednotlivými typy navigace, nejprve je nutné přistoupit k~první položce seznamu \texttt{spaces} okna, jež bude dále označována jako oblast. Tato položka \textbf{vždy existuje}.\gap

Při zobrazení generované krajiny je také přenastaven pohled uživatele, aby byl objekt viditelný. K~vlastnostem kamery v~3D pohledu lze přistoupit skrze vlastnost \texttt{region\_3d} oblasti. Pozice je nastavena přímo na pozici objektu. Z~estetických důvodu byl zvolen izometrický úhel pohledu, perspektivní nastavení pohledu ale zůstává zachováno. Specificky byl zvolen pohled, jež svírá stejný úhel jako úhlopříčka krychle. Ten odpovídá rotaci $\frac{3}{\pi}$ na ose $X$ a~úhlu $\frac{\pi}{4}$ na ose $Z$. Úhly je možné zadat vytvořením objektu \texttt{Euler}. Rotace pohledu přijímá pouze quaterniony, jež lze následně vytvořit metodou \texttt{to\_quaternion} daného objektu.\gap


\section{Mapa toků}

Principem mapy toků je zakreslování tras pohybu kapek po povrchu. Pro výpočet pohybu kapek je využito stejného algoritmu~\ref{alg:erosion_acceleration} jako pro vodní erozi, nekontroluje ale maximální sestup kapek. Na rozdíl od eroze také neprovádí více iterací. Neboť algoritmus je pro dostatečné odstupy kapek deterministický, tak každá iterace by vytvářela stejnou mapu. Další odlišností je, že algoritmus je implementován skrze výpočetní shader.\gap

\begin{figure}
    \centering
    \includegraphics[width=\linewidth]{obrazky-figures/implementation/flow-steps.pdf}
    \caption{Ilustrace zakreslování pohybu kapek. Červenou je zakreslena kapka a~její trasa pohybu. Místa, kde se více tras překrývá, jsou světlejší.}
    \label{fig:flow_example}
\end{figure}

Vzorec změny koncentrace je podobný jako u~transportu barev. Cílem je, aby se pro libovolně velké množství částic výsledná hodnota pouze blížila jedné. Pro konstantu kontrastu $f_c$ je vzorec nového toku $w_{t+1}$ následující:\par
\begin{equation}
w_{t+1} = w_t \cdot (1-f_c) + f_c
\end{equation}\gap

Zmenšení konstanty $f_c$ vede k~temnějšímu výsledku, užším tokům a~většímu kontrastu. Konstanta je v~uživatelském rozhraní reprezentována posuvníkem od $0$ do $1$, dané hodnoty ale ovlivňují výsledek nelineárně. Mezi uživatelem zvolenou hodnotou $contrast$ a~použitou konstantou $f_c$ byl zaveden převod tak, aby stejný posun hodnoty vedl k~podobně velké vizuální změně. Subjektivně, skrze testování hodnot, byl zvolen vzorec~\ref{eq:contrast_calc}. Její graf je zobrazen v~ilustraci~\ref{gr:contrast}.\gap

\pgfplotsset{
    ylabel style={rotate=-90},
    yticklabel style={/pgf/number format/fixed}
}
\begin{figure}
    \centering
    \begin{tikzpicture}
        \begin{axis}[domain = 0:1,
        width=0.45\linewidth,
        xmin = 0, xmax = 1,
        ymin = 0, ymax = 0.2,
        xlabel = {contrast},
        ylabel = {\(f_c\)}]
            \addplot[samples = 100, smooth, thick, blue]{0.2 * exp(-6.61 * x)};
        \end{axis}
    \end{tikzpicture}  
    \caption{Graf převodu uživatelské proměnné $contrast$ na vstupní konstantu kontrastu $f_c$}
    \label{gr:contrast}
\end{figure}

\begin{equation}
    f_c = 0{,}2 \cdot e^{-6{,}61 \cdot contrast}
    \label{eq:contrast_calc}
\end{equation}\gap

Co se týče dalších vstupů algoritmu, jsou vyžadovány dvě textury --- výšková mapa, jež je pouze čtena, a~mapa toků, do které je přímo zapisováno. Parametry simulace jsou sdílené s~erozí. Je-li tedy provedena vodní eroze, pak následující mapa toků bude simulovat stejný pohyb kapek. Simulace toků ale pracuje s~vlastní mezerou mezi počátečními pozicemi, neboť je obecně vyžadována vyšší než u~eroze.\gap

Neboť pro vytvoření textury toků je vyžadována výšková mapa, tak je podobně jako u~eroze dle potřeby automaticky vytvořena. V~případě, že již objekt výškové mapy má, je hledána nejdříve \textit{současná} mapa. Pokud neexistuje, bere algoritmus \textit{zdrojovou} mapu.\gap

Algoritmus pro velmi malé deformace povrchu může vytvořit nežádoucí černé pixely. Po generování mapy toků je tedy přidán krok zprůměrování černých pixelů s~okolními buňkami. Krok je také implementován jako výpočetní shader přímo nad výslednou texturou.\gap

\section{Generování terénů}

Při práci s~obrázky rozšíření také nabízí možnost vygenerovat odpovídající krajinu jako objekt. Tento terén je následně umístěn na 3D kurzor. Daná operace může sloužit jak pro importované výškové mapy tak pro obrázky vygenerované z~modelu uvnitř aplikace, neboť výsledný terén lépe zobrazí detail textury.\gap

Geometrie vytvořená operací se skládá ze čtvercové mřížky na základě rozlišení vybrané textury, zde značené $width$ a~$height$. Jelikož vytvoření vrcholu pro každý pixel nemusí být třeba, tak je nabízen dělitel tohoto rozlišení $sub$. Výsledné rozlišení $res$ je následně zaokrouhleno nahoru:\par

\begin{equation}
    \begin{split}
        res_x & = \lceil width \div sub \rceil \\
        res_y & = \lceil height \div sub \rceil \\
    \end{split}
    \label{eq:gen_subdiv}
\end{equation}\gap

Pro vytvoření terénu je využita funkce \texttt{ops.mesh.primitive\_grid\_add}, která přidá do scény objekt mřížky. Při volání této funkce je možné zadat rozlišení geometrie objektu. Funkce následně automaticky vybere vytvořený objekt, je tedy možné ho získat z~kontextu aplikace. Objekt je přejmenován dle názvu vstupní textury a~je mu nastavena vlastnost rozšíření \texttt{is\_generated}. To zabraňuje erozi objektu pro případ, že by byl přepsán opětovným generováním terénu.\gap

Krajina vytvářená rozšířením používá hladké stínování povrchu. Toho lze docílit nastavením vlastnosti \texttt{use\_smooth} pro všechny polygony vytvořeného povrchu. Daný seznam je přístupný skrze vlastnost \texttt{polygons}.\gap

Pro nanesení textury na vytvořený objekt je využit \texttt{Displace} modifikátor. Pro něj je vytvořena Blender textura a~obrázek s výškovou mapu. Modifikátor je okamžitě aplikován a~textura i obrázek jsou vymazány.

\section{Instalace ModernGL}
Neboť rozšíření vyžaduje externí balíček pro jazyk Python, je třeba vyřešit jeho instalaci. Využitím nástroje PIP, který jsou součástí instalace aplikace Blender, lze automaticky stáhnout i~aktualizovat externí knihovny. Zde představený kód je převzatý od autora Roberta Gützkowa~\cite{Gutzkow}. K instalaci knihovny slouží následující příkaz:

\lstset{
  xleftmargin=.15\textwidth,
  caption={}
}
\begin{lstlisting}
sys.executable -m pip install --upgrade moderngl
\end{lstlisting}\gap

Příkaz je volán jako podproces pomocí knihovny \texttt{subprocess}. Je mu také nastaven argument prostředí, kde je povolen parametr \texttt{PYTHONNOUSERSITE}\footnote{Detail prostředí: \url{https://docs.python.org/3/using/cmdline.html\#envvar-PYTHONNOUSERSITE}}. Díky němu instalace ignoruje uživatelské balíčky. Jinak by instalace neproběhla, pokud by už uživatel v~systému ModernGL měl, přestože ve skriptech by Blender ke knihovně neměl přístup.\gap

Pro daný postup je nejspíše třeba spuštění aplikace s~vyššími oprávněními. Například základní instalce Blender ve Windows se nachází ve chráněné složce. Při nedostatečném oprávnění volání podprocesu vytvoří výjimku. Při jejím ošetření je pak v~rozšíření nastaven text preferencí na patřičnou zprávu uživateli.\gap

Po úspěšné instalaci je třeba aplikaci restartovat. Funkce knihovny jsou následně při normálním spuštění přístupné všem skriptům. Existující příklad podobného procesu instalace závislostí obsahuje zásuvný modul \textit{DeepBump}\footnote{Popis instalace je uveden na stránce projektu: \url{https://github.com/HugoTini/DeepBump}}.\gap

\subsection{Odinstalace}
Nástroj PIP je také schopný odinstalace balíčků, ale při spuštění z~aplikace Blender je zcela neodstraní, pouze změní prefix jejich složek. Odstranění balíčků je tedy možné pouze manuálně ze složky \texttt{site-packages} v~adresářové struktuře aplikace Blender.

\chapter{Měření a~limitace}
\label{sec:stats}
V této kapitole jsou představeny výsledky měření časové náročnosti jednotlivých operací rozšíření a~následně zjištěné limitace implementovaného projektu.\gap


\section{Měření}
Projekt byl testován na dvou grafických kartách --- RTX 3080 a~GTX 745. Pro měření byly algoritmy spouštěny mimo aplikaci Blender a~vstupy byly předpřipravené textury. Pokud není jinak řečeno, pak je vodní eroze nastavena na 50 iterací a~50 kroků životnosti částice. Každé měření bylo zprůměrováno z~50 běhů.\gap

Doba provedení simulace je uvažována od prvního volání ModernGL vykreslení do ukončení veškerého vykreslování, tedy po dokončení funkce \texttt{finish} ModernGL kontextu.\gap

\subsection{Velikost textury}

Implementovaný algoritmus simuluje na každý pixel textury jednu kapku. Velikostí textury je tedy silně ovlivněna doba simulace. V~tabluce \ref{tab:size_4_total} jsou uvedena měření celkové doby simulace v~závislosti na velikosti textury. Odstup částic při simulaci byl nastaven na hodnotu~4. V~tabulce~\ref{tab:size_4} jsou doby přepočtené na jednu iteraci milionu částic.\gap

\begin{table}[H]
    \centering
    \begin{tabular}{|c||c|c|c|c|}
        \hline
        Rozlišení textury & 128 px & 256 px & 512 px & 1024 px\\\hline\hline
        RTX 3080 12GB & 3 ms & 9 ms & 20 ms & 72 ms\\\hline
        GTX 745 4GB & 38 ms & 172 ms & 804 ms & 3575 ms\\\hline
    \end{tabular}
    \caption{Tabulka doby simulace 50 iterací. Odstup částic byl nastaven na~4~pixely.}
    \label{tab:size_4_total}
\end{table}

\begin{table}[H]
    \centering
    \begin{tabular}{|c|c|c|c|c|}
        \hline
        Rozlišení textury & 128 px & 256 px & 512 px & 1024 px\\\hline\hline
        RTX 3080 12GB & $3{,}46$ ms & $2{,}75$ ms & $1{,}54$ ms & $1{,}38$ ms\\\hline
        GTX 745 4GB & 46 ms & 52 ms & 61 ms & 68 ms\\\hline
    \end{tabular}
    \caption{Tabulka doby jedné iterace pro milion částic. Odstup částic byl nastaven na~4~pixely.}
    \label{tab:size_4}
\end{table}

\noindent Při simulaci na větší textuře je více času stráveného výpočtem na grafické kartě. RTX 3080 s větším množstvím paměti toho využívá a~výpočet se pro pevný počet částic zrychluje. Starší karta GTX 745 naopak zpomaluje.\gap

\subsection{Interpolace}

Pro vodní erozi je možnost interpolace eroze mezi buňkami v~okolí částice. Každá iterace pak vyžaduje více kroků. Tabulka~\ref{tab:interp} ilustruje závislost celkové doby simulace na povolení interpolace pro různé velikosti textur.\gap

\begin{table}[H]
    \centering
    \begin{tabular}{|c|c||c|c|c|c|}
        \hline
        \multicolumn{2}{|c||}{Rozlišení textury} & 128 & 256 & 512 & 1024\\\hline\hline
        \multirow{2}{*}{RTX 3080 12GB} & Bez interpolace & 23 ms & 38 ms & 48 ms & 203 ms\\\cline{2-6}
        & S interpolací & 23 ms & 62 ms & 83 ms & 344 ms\\\hline
        \multirow{2}{*}{GTX 745 4GB} & Bez interpolace & 72 ms & 282 ms & 1301 ms & -\\\cline{2-6}
        & S interpolací & 103 ms & 407 ms & 1915 ms & -\\\hline
    \end{tabular}
    \caption{Tabulka celkové doby simulace 50 iterací. Odstup částic byl nastaven na~16~pixelů.}
    \label{tab:interp}
\end{table}

\subsection{Odstup částic}

V algoritmu vodní eroze je použitý odstup částic, aby se předešlo interferenci mezi nimi. Následující měření se zabývají vlivem velikosti odstupu na dobu simulace. Také byl měřen vliv odstupu pro různé velikosti textury. Tabulka~\ref{tab:square_256} ilustruje měření pro rozlišení 256~pixelů a~tabulka~\ref{tab:square_512} pro rozlišení~512 pixelů. Tabulky jsou také zobrazeny v~grafech~\ref{fig:square_3080} a~\ref{fig:square_745}.\gap

\begin{table}[H]
    \centering
    \begin{tabular}{|c||c|c|c|c|c|c|}
        \hline
        Odstup částic & 1 px & 2 px & 4 px & 8 px & 16 px & 32 px\\\hline\hline
        RTX 3080 12GB & $5{,}55$ ms & $6{,}80$ ms & 9 ms & 16 ms & 40 ms & 90 ms\\\hline
        GTX 745 4GB & 120 ms & 142 ms & 184 ms & 236 ms & 285 ms & 334 ms\\\hline
    \end{tabular}
    \caption{Tabulka celkové doby simulace. Rozlišení textury je 256 na 256 pixelů.}
    \label{tab:square_256}
\end{table}

\begin{table}[H]
    \centering
    \begin{tabular}{|c||c|c|c|c|c|c|}
        \hline
        Odstup částic & 1 px & 2 px & 4 px & 8 px & 16 px & 32 px\\\hline\hline
        RTX 3080 12GB & 9 ms & 11 ms & 20 ms & 42 ms & 48 ms & 202 ms\\\hline
        GTX 745 4GB & 516 ms & 617 ms & 836 ms & 1082 ms & 1281 ms & 1414 ms\\\hline
    \end{tabular}
    \caption{Tabulka celkové doby simulace. Rozlišení textury je 512 na 512 pixelů.}
    \label{tab:square_512}
\end{table}

\begin{comment}
\begin{table}[H]
    \centering
    \begin{tabular}{|c||c|c|c|c|c|c|}
        \hline
        Odstup částic & 1 & 2 & 4 & 8 & 16 & 32\\\hline\hline
        RTX 3080 12GB & 34 ms & 40 ms & 72 ms & 132 ms & 209 ms & 228 ms\\\hline
    \end{tabular}
    \caption{Tabulka celkové doby simulace. Rozlišení textury je 1024 na 1024 pixelů.}
    \label{tab:square_1024}
\end{table}
\end{comment}

\noindent Z~měření je vidět, že pro větší odstupy se doba simulace drasticky zvyšuje. Čím větší je odstup částic, tím více volání algoritmu eroze je provedeno a~tím více času je stráveného přepínáním kontextu mezi grafickou kartou a~procesorem. Správný odstup kapek je tedy nejmenší, se kterým ale nedochází k~interferenci kapek. Může tedy být pro každý porvch jiný.\gap

\pgfplotsset{
    ylabel style={rotate=90}
}
\begin{figure}[H]
    \centering
    \begin{tikzpicture}
        \begin{axis}[width=0.48\linewidth,
        xlabel = {Odstup [px]},
        ylabel = {Doba simulace [s]}]
        \addplot [color=blue, mark=o]
         table[x =x, y =avg]{tests/3080/square256.dat};
        \end{axis}
    \end{tikzpicture}
    \hfill
    \begin{tikzpicture}
        \begin{axis}[width=0.48\linewidth,
        xlabel = {Odstup [px]},
        ylabel = {Doba simulace [s]}]
        \addplot [color=blue, mark=o]
         table[x =x, y =avg]{tests/3080/square512.dat};
        \end{axis}
    \end{tikzpicture}\gap
    \caption{Grafy závislosti doby simulace na velikosti odstupu pro kartu RTX 3080. Vlevo je graf pro texturu o~rozlišení 256 a~vpravo pro rozlišení 512.}
    \label{fig:square_3080}
\end{figure}

\begin{figure}[H]
    \centering
    \begin{tikzpicture}
        \begin{axis}[width=0.48\linewidth,
        xlabel = {Odstup [px]},
        ylabel = {Doba simulace [s]}]
        \addplot [color=blue, mark=o]
         table[x =x, y =avg]{tests/745/square256.dat};
        \end{axis}
    \end{tikzpicture}
    \hfill
    \begin{tikzpicture}
        \begin{axis}[width=0.48\linewidth,
        xlabel = {Odstup [px]},
        ylabel = {Doba simulace [s]}]
        \addplot [color=blue, mark=o]
         table[x =x, y =avg]{tests/745/square512.dat};
        \end{axis}
    \end{tikzpicture}\gap
    \caption{Grafy závislosti doby simulace na velikosti odstupu pro kartu GTX 745. Vlevo je graf pro texturu o~rozlišení 256 a~vpravo pro rozlišení 512.}
    \label{fig:square_745}
\end{figure}

\subsection{Termální eroze}

Hlavním faktorem doby simulace pro termální erozi je velikost textury. V~tabulce~\ref{tab:thermal} je uvedeno měření závislosti celkové doby simulace na rozlišení vstupní výškové mapy.\gap

\begin{table}[H]
    \centering
    \begin{tabular}{|c||c|c|c|c|c|}
        \hline
        Rozlišení textury & 128 px & 256 px & 512 px & 1024 px & 2048 px\\\hline\hline
        RTX 3080 12GB & 1.80 ms & 5.75 ms & 19 ms & 79 ms & 318 ms\\\hline
        GTX 745 4GB & 22 ms & 85 ms & 427 ms & 1708 ms & 11054 ms\\\hline
    \end{tabular}
    \caption{Tabulka celkové doby simulace termální eroze po dobu 50 iterací.}
    \label{tab:thermal}
\end{table}

\section{Limitace}
\label{limitace}
Při testování na operačním systému Fedora nebyla knihovna ModernGL schopna najít OpenGL kontext aplikace Blender. Vytvoření samostatného kontextu stále způsobilo pád aplikace, na operačním systému tedy není možné rozšíření použít.\gap

Obecně pro operační systém Linux také knihovna ModernGL vykazuje neočekávané chování při indexaci vrcholů. Vykreslování možné je, ale dochází k~zahazování polygonů v~zásvislosti na přesném pořadí a~pozici vrcholů. Ze všech permutací indexů pro každý trojúhelník obvykle funguje pouze jedna. Neboť jiné metody vykreslení, jež přidávají polygon s~každým dalším vrcholem nejsou pro libovolný vstupní model použitelné, byla indexace u~jiných operačních systémů než Windows vypnuta.\gap

V implementovaném rozšíření dále existuje vazba objektů na jejich výškové mapy, opačný vztah ale není kontrolován. Při duplikaci objektů tedy dochází i~ke sdílení vnitřně uchovávaných map, mohou tedy být nekorektně měněny. Již vytvořené obrázky ale zůstavají zachovávány a~následující výstupy budou správně generovány dle nového jména objektu.

\chapter{Závěr a~budoucí práce}
\label{ch:end}
Výsledkem této práce je rozšíření schopné jak vodní, tak termální eroze libovolného terénu uvnitř aplikace Blender. Pro zrychlení výpočtu plně využívá grafické karty a~schopností OpenGL. Rovněž nabízí mnoho způsobů, jak výsledné mapy aplikovat a~usnadňuje práci s~nimi. Rozšíření také klade důraz na automatizaci kroků a~zpětnou vazbu uživateli, včetně navigace mezi vytvářenými výsledky.\gap

Kromě práce nad objekty jsou veškeré operace přístupné i~pro textury. Každý parametr algoritmů je upravitelný uživatelem a~to s~ohledem na stabilní výsledky pro libovolný vstup. Rozšíření je použitelné jak se špičkovou grafickou kartou, tak se starým GPU.\gap

Vytvořený projekt je dále rozšiřitelný. Dalším plánovaným krokem je implementace eroze pomocí sil a~rour zmíněné v~teoretické části. Pro práci s~obrázky je rovněž možné rozšířit algoritmy na vícevrstvou erozi.\gap

Dalším možným rozšířením je responzivní rozhraní při erozi. Kód obou typů eroze je již připravený na inkrementální provádění, včetně možnosti přerušení uprostřed simulace.\gap

