diff --git a/reports/RelatorioFase2.tex b/reports/RelatorioFase2.tex index ee190147..ee176969 100644 --- a/reports/RelatorioFase2.tex +++ b/reports/RelatorioFase2.tex @@ -1,6 +1,7 @@ \documentclass[12pt, a4paper]{article} \usepackage{amsmath} +\usepackage{bm} \usepackage{array} \usepackage{amsmath} \usepackage[portuguese]{babel} @@ -85,7 +86,164 @@ \section{Modelo estático do sistema solar} \section{Extras} -\textbf{\color{red} TODO - extras} +\section{\emph{Frustum culling}} + +Cada \emph{draw call} tem um custo elevado para o desempenho da aplicação. Logo, procurando reduzir +o número de \emph{draw calls}, foi implementado \emph{frustum culling}, para apenas ser requisitada +à GPU a renderização das entitidades totalmente ou parcialmente no \emph{view frustum} da câmara. + +Seria muito computacionalmente intensivo verificar se a geometria de um modelo se encontra dentro ou +fora do \emph{view frustum}, pelo que se encapsulam todos os modelos em esferas que, devido à sua +geometria simples, permitem uma verificação rápida da sua visibilidade no \emph{view frustum}. No +entanto, visto que estas esferas podem ser um pouco maiores do que os modelos em si, é possível que +algumas entidades fora do ecrã sejam desenhadas, visto que parte das suas esferas ainda podem +intersetar os planos do \emph{view frustum}. Para mitigar este problema, formas geométricas +encapsuladoras mais complexas poderiam ser utilizadas, visto que estas se poderiam adaptar melhor à +geometria dos modelos. No entanto, o uso destas formas complexas conduziria a testes de visibilidade +mais caros, possivelmente anulando os benefícios de desenhar um menor número de entidades. + +Quando um modelo é carregado, é necessário calcular a esfera que o encapsula. Em primeiro lugar, o +seu centro é calculado como o centro de massa de todos os pontos, como mostra a expressão abaixo, +onde $M$ é o modelo, uma sequência de pontos tridimensionais: + +$$ +C = \frac{1}{|M|} \sum_{p \in M} p +$$ + +Depois, o raio da esfera pode ser determinado como a distância entre o centro da esfera e o ponto +mais longínquo do mesmo, como mostra a expressão abaixo, onde $d$ é a função de distância cartesiana +entre dois pontos: + +$$ +r = \max \left \lbrace d(C, p) \mid p \in M \right \rbrace +$$ + +É também necessário saber como uma esfera encapsuladora é afetada quando o objeto que encapsula +sofre uma transformação no mundo. Considere-se uma matriz de transformação aplicada ao objeto (em +coordenadas do mundo), originada através da aplicação de translações, rotações, e escalas. A matriz +será 4x4 e terá o seguinte aspeto: + +$$ +\bgroup + T = + \begin{bmatrix} + \vec \imath & \vec \jmath & \vec k & \vec t \\ + 0 & 0 & 0 & 1 + \end{bmatrix} +\egroup +$$ + +Para calcular o centro da esfera após a transformação da entidade, basta multiplicar a matriz de +transformação pela posição do centro da esfera: + +$$ +C' = T C +$$ + +Depois, para calcular o novo raio da esfera, não é necessário ter em conta as transformações de +rotação, visto que as esferas são simétricas em todos os eixos possíveis. No entanto, é necessário +ter em conta a escala aplicada ao modelo. Por exemplo, na matriz $T$, a escala da entidade pelo +eixo $x$ é $\lVert \vec \imath \rVert$, e o mesmo se tem para o eixo $y$ e +$\lVert \vec \jmath \rVert$, e para $z$ e $\lVert \vec k \rVert$. Logo, o raio da esfera +transformada é: + +$$ +r' = + \max + \left ( \lVert \vec \imath \rVert, \lVert \vec \jmath \rVert, \lVert \vec k \rVert \right ) + \cdot + r +$$ + +É possível tirar proveito da estrutura hierárquica da cena para otimizar o processo de +\emph{frustum culling}. Por exemplo, caso um grupo contenha várias entidades ou subgrupos, pode +construir-se uma esfera que encapsula a totalidade do grupo. Caso essa esfera não esteja no +\emph{view frustum}, pode-se evitar fazer os testes de visibilidade para as esferas dos objetos +individuais que compõem o grupo. Caso contrário, é na mesma necessário realizar esses testes. + +O processo para determinar as características de uma esfera que encapsula todos os objetos de um +grupo é semelhante ao da construção de esferas com base no conjunto de pontos de um modelo. Em +primeiro lugar, para determinar o centro da esfera, calcula-se o centro de massa do conjunto de +pontos formado pelos centros de todas as esferas, $C$. De seguida, para cada subesfera, calcula-se +a sua distância máxima a $C$, o raio da subesfera adicionado à distância entre $C$ e o centro da +subesfera. Depois, a maior destas distâncias é escolhida para ser o raio da nova esfera, como mostra +a expressão abaixo, onde $S$ representa o conjunto de subesferas: + +$$ +r' = \max \left \lbrace d(C', C) + r \mid (C, r) \in S \right \rbrace +$$ + +Depois de saber como determinar as esferas encapsuladoras das entidades, é necessário determinar +o \emph{view fustum} da câmara, para se poder verificar a posição das esferas em relação aos planos +do \emph{view fustum}. Para determinar o \emph{view frustum}, é necessário obter alguns vetores +importantes da câmara \cite{lighthouse3d-frustum-planes}: + +\textbf{\color{red} TODO - com a fusão das partes do relatório, referenciar vetores da câmara livre} + +Além destes vetores, é também necessário conhecer as dimensões dos planos \emph{near} e \emph{far}. +Apesar de, matematicamente, planos não terem uma altura e uma largura, utiliza-se esta linguagem +para se referir às dimensões dos retângulos nestes planos que constituem o \emph{view frustum}. Na +expressão abaixo, mostra-se como se pode calcular a altura ($H_\text{near}$) e a largura +($W_\text{near}$) do plano \emph{near}. O processo para o plano \emph{far} é semelhante. Com o FOV +da câmara ($\theta$), a distância ao plano \emph{near} ($d_\text{near}$) e o \emph{aspect ratio} +(A), podem calcular-se as dimensões deste plano \cite{lighthouse3d-frustum-distances}: + +$$ +H_\text{near} = 2 d_\text{near} \tan \left ( \frac{\theta}{2} \right ) +\hspace{1cm} +W_\text{near} = H_\text{near} A +$$ + +Com estes valores, é possível determinar as coordenadas dos pontos dos retângulos do +\emph{view frustum}. Os quatro pontos do plano \emph{near} (a amarelo na figura abaixo) podem ser +calculados do seguinte modo, e o método utilizado para o plano \emph{far} é semelhante +\cite{lighthouse3d-frustum-planes}: + +$$ +F = P + + d_\text{near} \; \widehat{d} \; \pm + \frac{H_\text{near}}{2} \; \widehat{up} \; \pm + \frac{W_\text{near}}{2} \; \widehat{r} \; +$$ + +\begin{figure}[H] + \centering + \includegraphics[width=0.4\textwidth]{res/phase2/ViewFrustum.pdf} + \caption{\emph{View Frustum}.} +\end{figure} + +Com os oito pontos do \emph{view frustum}, é possível determinar as equações cartesianas de cada +um dos seus planos, considerando três pontos da sua superfície. Em primeiro lugar, determina-se o +vetor normal ao plano. Com os três pontos, $P_1$, $P_2$ e $P_3$, determinam-se dois vetores, a +partir dos quais se calcula um produto externo, determinando-se assim um vetor perpendicular ao +plano \cite{lighthouse3d-plane}: + +$$ +n = \overrightarrow{P_1 P_2} \times \overrightarrow{P_1 P_3} +$$ + +Depois, com este vetor normalizado, é possível determinar a constante na equação cartesiana do plano +com base nas coordenadas de um dos três pontos dados \cite{lighthouse3d-plane}: + +\begin{align*} + & \alpha x + \beta y + \gamma z + \delta = 0 \\ + \Leftrightarrow \; & \widehat{n} \cdot P + \delta = 0 \\ + \Leftrightarrow \; & \delta = -\widehat{n} \cdot P +\end{align*} + +Durante a renderização de cada \emph{frame}, verificam-se que esferas estão totalmente ou +parcialmente dentro do \emph{view frustum}. Para uma esfera estar no \emph{view frustum} $F$, é +necessário que a distância assinada entre o centro da esfera e cada um dos planos do +\emph{view frustum} não seja inferior ao simétrico do seu raio, ou seja \cite{lighthouse3d-sphere}: + +$$ +\forall_{p \in F} \left ( \widehat{n} \cdot C + \delta \ge - r \right ) +$$ + +Uma vez que é necessário calcular distâncias assinadas, é imperativo que os vetores normais de todos +os planos do \emph{view frustum} apontem para o seu interior, para que o conteúdo no seu interior (e +não no seu exterior) seja desenhado. \cite{lighthouse3d-frustum-planes} Por este motivo, a ordem em +que os pontos $P_1$, $P_2$ e $P_3$ são especificados é relevante. \section{Resultados obtidos} @@ -100,8 +258,22 @@ \section{Bibliografia} \renewcommand{\section}[2]{} \begin{thebibliography}{9} - \bibitem{exemplo} - \href{https://youtu.be/dQw4w9WgXcQ}{Um item de exemplo na bibliografia} + \bibitem{lighthouse3d-frustum-planes} + ``Geometric Approach -- Extracting the Planes.''. Lighthouse3d.com. Accessed: + Mar. 29, 2025. [Online.] Available: + \url{https://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-extracting-the-planes/} + \bibitem{lighthouse3d-frustum-distances} + ``View Frustum’s Shape.''. Lighthouse3d.com. Accessed: + Mar. 29, 2025. [Online.] Available: + \url{https://www.lighthouse3d.com/tutorials/view-frustum-culling/view-frustums-shape/} + \bibitem{lighthouse3d-plane} + ``Plane.''. Lighthouse3d.com. Accessed: + Mar. 29, 2025. [Online.] Available: + \url{https://www.lighthouse3d.com/tutorials/maths/plane/} + \bibitem{lighthouse3d-sphere} + ``Geometric Approach -- Testing Points and Spheres.''. Lighthouse3d.com. Accessed: + Mar. 29, 2025. [Online.] Available: + \url{https://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-points-and-spheres/} \end{thebibliography} \endgroup diff --git a/reports/res/phase2/ViewFrustum.pdf b/reports/res/phase2/ViewFrustum.pdf new file mode 100644 index 00000000..8ba2d1e4 Binary files /dev/null and b/reports/res/phase2/ViewFrustum.pdf differ diff --git a/scripts/formatlatex.sh b/scripts/formatlatex.sh index ed41686d..b11b8ef0 100755 --- a/scripts/formatlatex.sh +++ b/scripts/formatlatex.sh @@ -24,7 +24,9 @@ grep_error_message() { # shellcheck disable=SC2266 find reports -type f -name "*.tex" | while IFS="" read -r file; do - grep -PHn '.{101,}$' "$file" | grep_error_message "Column exceeds 100 characters" + grep -PHn '.{101,}$' "$file" | \ + grep -Pv 'http' | \ + grep_error_message "Column exceeds 100 characters" grep -PHn '\t$' "$file" | grep_error_message "Use of tabs" grep -PHn '\s+$' "$file" | grep_error_message "Trailing whitespace" done |