221 lines
9.0 KiB
TeX
221 lines
9.0 KiB
TeX
|
\part{Streaming de modèle 3D}
|
||
|
Le but ultime de ce projet est de biaiser l'utilisateur avec les
|
||
|
recommandations de sorte à être capable de prévoir ses déplacements futurs, et
|
||
|
ainsi précharger les parties du modèle qui vont être vues. Cette section
|
||
|
présente le travail qui a été réalisé dans le domaine du chargement de modèle.
|
||
|
|
||
|
\paragraph{}
|
||
|
Évidemment, cette partie est celle qui comment après la fin de la première
|
||
|
partie : il faut nous seulement connaître l'influence des recommandations sur
|
||
|
l'utilisateur, ensuite être capable de prévoir le comportement de
|
||
|
l'utilisateur, et enfin s'en servir pour précharger les bonnes parties du
|
||
|
modèles. Tout ceci n'étant pas encore possible, le travail qui a été fait est
|
||
|
nettement plus simpliste : il n'y aura aucune prévision du comportement ici.
|
||
|
|
||
|
\section*{Introduction}
|
||
|
Notre problématique ici est de transférer des modèles 3D sur le réseau. Les
|
||
|
modèles sont stockés sur le serveur au format \texttt{.obj} et sont constitués
|
||
|
:
|
||
|
\begin{itemize}
|
||
|
\item des materiaux (\texttt{usemtl}) : cela définit le matériau utilisé
|
||
|
pour les faces qui vont suivre
|
||
|
\item de sommets (\emph{vertices}) : des points 3D
|
||
|
\item de coordonnées de textures : des points en 2D qui référence un point
|
||
|
d'une image
|
||
|
\item de normales : des vecteurs en 3D
|
||
|
\item de faces : une liste de 3 ou 4 sommets (représentés par leurs
|
||
|
indices), avec éventuellement leurs coordonnées de textures et/ou
|
||
|
normales
|
||
|
\end{itemize}
|
||
|
|
||
|
\paragraph{}
|
||
|
La seule contrainte d'ordre des éléments est qu'une face qui contient des
|
||
|
sommets, coordonnées de textures ou normales n'arrive pas avant ses sommets,
|
||
|
coordonnées de textures ou normales dans le fichier : si l'on parcourt les
|
||
|
lignes du fichier, on doit déjà avoir toutes les informations sur la face.
|
||
|
|
||
|
\paragraph{}
|
||
|
Généralement, le fichier \texttt{.obj} vient souvent avec un fichier
|
||
|
\texttt{.mtl} qui contient la définition des matériaux (leurs noms, leurs
|
||
|
textures, leurs constantes...).
|
||
|
|
||
|
|
||
|
\section{Streaming linéaire}
|
||
|
La première étape de cette fonctionnalité a été de faire un système
|
||
|
client-serveur permettant le streaming de modèle 3D. En effet, les
|
||
|
\emph{loaders} de modèles présents dans la libraire \threejs ne permettent pas
|
||
|
le chargement progressif : ils se content d'envoyer une requête vers le fichier
|
||
|
contenant le modèle et à créer un modèle une fois que le fichier est chargé
|
||
|
complètement.
|
||
|
|
||
|
\paragraph{}
|
||
|
Pour commencer, nous avons donc utilisé \socketio, une librairie permettant de
|
||
|
gérer les sockets facilement avec JavaScript et Nodejs, pour faire une première
|
||
|
version simpliste du streaming : on travaillait sur un modèle ne contenant que
|
||
|
des sommets et des faces (donc pas de textures ni de normales) et le protocole
|
||
|
fonctionnait ainsi :
|
||
|
|
||
|
\begin{figure}[H]
|
||
|
\centering
|
||
|
\begin{tikzpicture}[]
|
||
|
\draw (0,0) node[above]{Client};
|
||
|
\draw (0,0) -- (0,-6);
|
||
|
\draw (5,0) node[above]{Serveur};
|
||
|
\draw (5,0) -- (5,-6);
|
||
|
|
||
|
\draw (2.5,-1.3) node[rotate=-12] {Path jusqu'au modèle};
|
||
|
\draw[->] (0,-1) -- (5, -2);
|
||
|
|
||
|
\draw (2.5,-2.3) node[rotate=12] {Des éléments};
|
||
|
\draw[<-] (0,-3) -- (5, -2);
|
||
|
|
||
|
\draw (2.5,-3.3) node[rotate=-12] {ACK};
|
||
|
\draw[->] (0,-3) -- (5, -4);
|
||
|
|
||
|
\draw (2.5,-4.3) node[rotate=12] {D'autres éléments};
|
||
|
\draw[<-] (0,-5) -- (5, -4);
|
||
|
|
||
|
\draw (2.5,-6) node{$\vdots$};
|
||
|
\end{tikzpicture}
|
||
|
\caption{Transmission élémentaire\label{transmission1}}
|
||
|
\end{figure}
|
||
|
|
||
|
\paragraph{}
|
||
|
Le serveur envoyait alors les éléments dans l'ordre dans lequel ils étaient
|
||
|
présents dans le fichier du modèle 3D. Le gros inconvéniant de cette méthode
|
||
|
est que souvent, les sommets sont présents au début du fichier, et les faces
|
||
|
vers la fin : nous recevons donc des informations de sommets au début qui ne
|
||
|
nous permettent rien d'afficher, puis toutes les faces d'un coup, ce qui fait
|
||
|
que le streaming n'est pas aussi progressif que l'on souhaiterais.
|
||
|
|
||
|
\paragraph{}
|
||
|
Dans le cas d'un modèle sans coordonnées de textures et sans normales, la seule
|
||
|
condition pour pouvoir afficher une face est d'avoir envoyé les sommets qui la
|
||
|
composent. On peut donc améliorer la fluidité en réarrangeant le fichier
|
||
|
\texttt{.obj} : il suffit de faire apparaître les faces dès que les sommets
|
||
|
sont disponibles.
|
||
|
|
||
|
\paragraph{}
|
||
|
Dans le cas où l'on souhaite gérer les textures et les normales, utiliser cette
|
||
|
technique est beaucoup plus compliqué puisqu'il faut aussi décider de l'ordre
|
||
|
relatif entre les sommets, coordonnées de textures et normales : en effet, pour
|
||
|
envoyer une face le plus tôt possible, il faut que toutes ces composantes
|
||
|
soient envoyés, et il est donc nécessaire de mélanger les sommets, coordonnées
|
||
|
de texture et normales.
|
||
|
|
||
|
|
||
|
\section{Streaming linéaire amélioré}
|
||
|
La remarque précédente conduit directement à cette méthode. Le principe reste
|
||
|
le même que celui précédent (figure \ref{transmission1}), mais les éléments
|
||
|
seront envoyés différemment : on va en fait parcourir les faces directement.
|
||
|
|
||
|
\paragraph{}
|
||
|
Le serveur va garder en mémoire ce qui a déjà été envoyé et ce qui ne l'a pas
|
||
|
été, et envoyer les faces dans l'ordre : si certains éléments des faces n'ont
|
||
|
pas encore été envoyé, on les enverra juste avant d'envoyer la face en
|
||
|
question.
|
||
|
|
||
|
\paragraph{}
|
||
|
On peut de cette façon à la fois gérer les coordonnées de texture et les
|
||
|
normales, tout en envoyant les faces le plus tôt possible (on peut aussi noter
|
||
|
que si certains sommets / coordonnées de textures / normales sont inutilisés
|
||
|
dans les faces, ils ne seront pas envoyés et on s'évite donc de transférer des
|
||
|
données inutiles).
|
||
|
|
||
|
\paragraph{}
|
||
|
C'est dans cette version que nous avons commencé à nous intéresser à la façon
|
||
|
de gérer les matériaux. Dans \threejs, un objet 3D est lié à un materiau, et
|
||
|
nous sommes donc obligés de créer autant d'objets que de materiaux. Pour cela,
|
||
|
nous avons légèrement modifié notre protocole :
|
||
|
|
||
|
\begin{figure}[H]
|
||
|
\centering
|
||
|
\begin{tikzpicture}[]
|
||
|
\draw (0,0) node[above]{Client};
|
||
|
\draw (0,0) -- (0,-8);
|
||
|
\draw (5,0) node[above]{Serveur};
|
||
|
\draw (5,0) -- (5,-8);
|
||
|
|
||
|
\draw (2.5,-1.3) node[rotate=-12] {Path jusqu'au modèle};
|
||
|
\draw[->] (0,-1) -- (5, -2);
|
||
|
|
||
|
\draw (2.5,-2.3) node[rotate=12] {Liste des matériaux};
|
||
|
\draw[<-] (0,-3) -- (5, -2);
|
||
|
|
||
|
\draw[dashed, ->] (-0.1,-3) -- (-0.1,-4);
|
||
|
|
||
|
\draw (2.5,-3.3) node[rotate=-12] {ACK};
|
||
|
\draw[->] (0,-3) -- (5, -4);
|
||
|
|
||
|
\draw (2.5,-4.3) node[rotate=12] {Des éléments};
|
||
|
\draw[<-] (0,-5) -- (5, -4);
|
||
|
|
||
|
\draw (2.5,-5.3) node[rotate=-12] {ACK};
|
||
|
\draw[->] (0,-5) -- (5, -6);
|
||
|
|
||
|
\draw (2.5,-6.3) node[rotate=12] {D'autres éléments};
|
||
|
\draw[<-] (0,-7) -- (5, -6);
|
||
|
|
||
|
\draw (2.5,-8) node{$\vdots$};
|
||
|
\end{tikzpicture}
|
||
|
\caption{Transmission avec gestion des matériaux}
|
||
|
\end{figure}
|
||
|
|
||
|
\paragraph{}
|
||
|
Les directives de matériau à utiliser (\texttt{usemtl}) seront ignorées, et les
|
||
|
faces seront envoyées avec l'indice de l'objet auquel elles appartiennent, ce
|
||
|
qui permettra au client de savoir dans quel objet (et donc avec quel matériau)
|
||
|
elles doivent être ajoutées.
|
||
|
|
||
|
|
||
|
\section{Streaming intelligent}
|
||
|
C'est la dernière version du streaming qui a été faite sur ce projet. À chaque
|
||
|
transfert, le client envoie sa position au serveur (ainsi que les plans
|
||
|
définissant son \emph{frustum}\footnote{les bords du champ de vision de la
|
||
|
caméra}) et le serveur va parcourir les faces du modèle en cherchant celles qui
|
||
|
apparaissent dans le \emph{frustum}\footnote{dans cette version, on considère
|
||
|
qu'une face apparaît dans le \emph{frsutum} si un de ces sommets y appartient.
|
||
|
Évidemment, une face très grande pourrait appraître dans le \emph{frustum}
|
||
|
sans qu'aucun de ses sommets n'y soit, mais nous n'avons pas traité ce cas
|
||
|
particulier ici.}. On évite ainsi d'envoyer les faces du modèle qui sont
|
||
|
derrière la caméra et que l'utilisateur ne voit pas.
|
||
|
|
||
|
\paragraph{}
|
||
|
Bien sûr, si il n'y a plus de faces dans le \emph{frustum} de la caméra, on va
|
||
|
envoyer les faces en suivant la méthode de la section précédente.
|
||
|
|
||
|
\begin{figure}[H]
|
||
|
\centering
|
||
|
\begin{tikzpicture}[]
|
||
|
\draw (0,0) node[above]{Client};
|
||
|
\draw (0,0) -- (0,-8);
|
||
|
\draw (5,0) node[above]{Serveur};
|
||
|
\draw (5,0) -- (5,-8);
|
||
|
|
||
|
\draw (2.5,-1.3) node[rotate=-12] {Path jusqu'au modèle};
|
||
|
\draw[->] (0,-1) -- (5, -2);
|
||
|
|
||
|
\draw (2.5,-2.3) node[rotate=12] {Liste des matériaux};
|
||
|
\draw[<-] (0,-3) -- (5, -2);
|
||
|
|
||
|
\draw[dashed, ->] (-0.1,-3) -- (-0.1,-4);
|
||
|
|
||
|
\draw (2.5,-3.3) node[rotate=-12] {Caméra / \emph{frustum}};
|
||
|
\draw[->] (0,-3) -- (5, -4);
|
||
|
|
||
|
\draw (2.5,-4.3) node[rotate=12] {Des éléments};
|
||
|
\draw[<-] (0,-5) -- (5, -4);
|
||
|
|
||
|
\draw (2.5,-5.3) node[rotate=-12] {Caméra / \emph{frustum}};
|
||
|
\draw[->] (0,-5) -- (5, -6);
|
||
|
|
||
|
\draw (2.5,-6.3) node[rotate=12] {D'autres éléments};
|
||
|
\draw[<-] (0,-7) -- (5, -6);
|
||
|
|
||
|
\draw (2.5,-8) node{$\vdots$};
|
||
|
\end{tikzpicture}
|
||
|
\caption{Version finale}
|
||
|
\end{figure}
|
||
|
|
||
|
|