Skip to content
This repository was archived by the owner on Jun 11, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 131 additions & 3 deletions reports/RelatorioFase4.tex
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,36 @@ \section{\emph{Generator}}

\subsection{Formato \texttt{.3d}}

{\color{red} TODO - Humberto}
O formato \texttt{.3d} exportado pelo \texttt{generator} e utilizado pela \texttt{engine} é o
Wavefront OBJ \cite{wavefront-obj}. Apenas uma pequena fração das funcionalidades deste formato
são suportadas e, nesta fase, foram necessárias adições aos mecanismos de escrita e leitura de
ficheiros Wavefront OBJ para suportar coordenadas de textura e normais. Este formato é textual, onde
cada linha pode ser um comentário, uma posição, uma coordenada de textura, uma normal, ou uma face
triangular, como mostra o exemplo abaixo, na ordem apresentada:

\begin{lstlisting}

# Comment
v 0.5 0.5 1
vt 0.3 0.3
vn 0 1 0
f 1/2/3 4/5/6 7/8/9
\end{lstlisting}

Quando uma linha começa com \texttt{v}, \texttt{vt} ou \texttt{vn}, devem seguir-se as coordenadas
de uma posição, de uma textura, ou de um vetor normal, respetivamente. Quando uma linha começa com
\texttt{f}, deve seguir-se uma face triangular, ou seja três pontos. O \texttt{generator} e a
\texttt{engine} suportam dois tipos de ponto:

\begin{itemize}
\item Apenas um número, um índice de uma posição, ou seja, um elemento do tipo \texttt{v}
(começando a contar em 1);
\item Da forma \texttt{v/t/n}, onde estão presentes três índices, um para uma posição, um para
uma coordenada de textura, e outro para um vetor normal.
\end{itemize}

Como o \emph{parser} de ficheiros Wavefront OBJ foi reimplementado na fase anterior com base em
expressões regulares, foi trivial adicionar o suporte para coordenadas de textura e vetores normais.

\subsection{Plano Horizontal}

Expand Down Expand Up @@ -109,7 +138,11 @@ \subsection{\emph{Torus}}

\subsection{Outras Figuras}

{\color{red} TODO - Humberto}
Para as restantes figuras, devido à sua complexidade e ao pouco tempo disponível para a conclusão
desta fase do trabalho prático, não foram adicionadas nem coordenadas de textura nem normais. No
entanto, a \texttt{engine} ainda é capaz de importar estes modelos e de os desenhar com iluminação,
graças a um algoritmo de geração automática de normais implementado e descrito posteriormente neste
relatório.

\subsection{Sistema Solar}

Expand All @@ -119,7 +152,99 @@ \section{\emph{Engine}}

\subsection{Geração Automática de Normais}

{\color{red} TODO - Humberto}
A \texttt{engine} é capaz de carregar modelos que não tenham informação sobre coordenadas de
texturas ou normais. Caso não haja informação sobre as coordenadas de textura de um modelo, é
possível desenhá-lo a uma cor sólida, mas é necessário que se tenha informação sobre as suas normais
para o iluminar corretamente. Como esta nem sempre está presente, foi implementado um algoritmo para
gerar normais de modelos automaticamente.

Este algoritmo considera o modelo inteiro como um único \emph{smoothing group}, e calcula a normal
de cada vértice como a média das normais dos triângulos a que este pertence, pesada pela área dos
triângulos. Logo, é necessário, em primeiro lugar, uma forma de calcular a normal de um triângulo.
Para um triângulo $[ABC]$, esta pode ser calculada do seguinte modo:

$$
\hat{n}_{[ABC]} = \frac{
\overrightarrow{AB} \times \overrightarrow{AC}
}{
\lVert \overrightarrow{AB} \times \overrightarrow{AC} \rVert
}
$$

Depois, a área de cada triângulo, $A$, pode ser calculada pela fórmula de Heron:

$$
S = \frac{
\lVert \overrightarrow{AB} \rVert +
\lVert \overrightarrow{AC} \rVert +
\lVert \overrightarrow{BC} \rVert
}{
2
}
$$

$$
A = \sqrt{
S
\left ( S - \lVert \overrightarrow{AB} \rVert \right )
\left ( S - \lVert \overrightarrow{AC} \rVert \right )
\left ( S - \lVert \overrightarrow{BC} \rVert \right )
}
$$

Logo, sendo $F$ o conjunto de faces triangulares nas quais um ponto está presente, o vetor normal
desse ponto é dado por:

$$
\hat{n} = \frac{
\sum_{f \in F} {A_f \, \hat{n}_f}
}{
\lVert \sum_{f \in F} {A_f \, \hat{n}_f} \rVert
}
$$

Em termos de implementação deste algoritmo, um dicionário é utilizado para armazenar associações
entre posições de pontos e pares normal-área. Iteram-se por todas as faces do modelo e, para
cada face, calcula-se a sua normal e a sua área. Depois, para cada ponto nessa face, adicionam-se
aos valores armazenados de normal e de área $A \, \hat{n}$ e $A$ respetivamente. Após iterar por
todas as faces, itera-se por todas as posições no dicionário, e define-se a normal de cada ponto
como o quociente entre a normal armazenada e a área total. Logicamente, este vetor deve ser
normalizado antes de adicionado ao modelo.

\subsection{VBOs}

Com a adição de coordenadas de textura e normais, foi necessário criar mais VBOs para as armazenar.
Agora, cada modelo passa a ter um VAO associado a três VBOs, como mostra a figura abaixo:

\begin{figure}[H]
\centering
\includegraphics[width=\textwidth]{res/phase4/VAO.pdf}
\caption{Organização do VAO, dos VBOs, e do EBO de um modelo.}
\end{figure}

Pode observar-se que, ao contrário do que acontece nos ficheiros \texttt{.3d}, não pode haver
vértices formados por posições, coordenadas de textura, e normais com diferentes índices. Para isso,
seria necessário mais do que um \emph{buffer} de índices, e isso não é suportado pelo OpenGL. Logo,
após carregar um modelo, é necessário converter o esquema de indexação de um ficheiro Wavefront OBJ
para o de um \emph{index buffer}. Para o fazer, um algoritmo simples pode ser utilizado:

\begin{itemize}
\item Cria-se um \emph{index buffer} e três outros \emph{buffers}, para armazenamento das
posições, das coordenadas de textura, e das normais, inicialmente vazios;

\item Armazena-se um dicionário que associa tuplos posição-c.textura-normal a índices (elementos
do \emph{index buffer});

\item Iteram-se por todos os vértices no modelo. Para cada vértice:
\begin{itemize}
\item Constrói-se o tuplo posição-c.textura-normal associado ao vértice, que se procura
no dicionário;
\item Caso seja encontrado, adiciona-se o índice encontrado ao \emph{index buffer}.
\item Caso contrário, coloca-se o tuplo no dicionário; adicionam-se a posição, a
coordenada de textura e a normal aos seus respetivos \emph{buffers}; e adiciona-se o
índice de um destes elementos ao \emph{index buffer}.
\end{itemize}
\end{itemize}

\subsection{Adição ao \emph{Schema} XML}

Expand Down Expand Up @@ -289,6 +414,9 @@ \section{Bibliografia}
\renewcommand{\section}[2]{}

\begin{thebibliography}{9}
\bibitem{wavefront-obj}
``Wavefront OBJ File Format Summary.''{} FileFormat.Info. Accessed: May 14, 2025. [Online.]
Available: \url{https://www.fileformat.info/format/wavefrontobj/egff.htm}
\bibitem{stb-image}
``stb.'' GitHub. Accessed: May 13, 2025. [Online.] Available:
\url{https://github.com/nothings/stb}
Expand Down
Loading