Romain VERGNE
visualisation non-photoréaliste de scènes urbaines sur
terminaux mobiles
août 2007
Encadrant : Xavier GRANIER
INRIA Futurs,
LABRI, Domaine Universitaire, 351, cours de la Libération, 33405 TALENCE
Contexte et objectifs du stage
L’objectif de ce stage est d’améliorer le rendu de façades stylisées de Quillet et al. [QTM05, QTG+06]
dans le cadre d’un contrat avec France Télécom. Leur travail consiste à utiliser les techniques de rendus
non photoréalistes pour détecter et afficher les lignes des façades sur un grand modèle 3D urbain. Il s’agit
d’un plugin de la plateforme Elkano [Mar04] dont le but est de visualiser rapidement une grande quantité de
données sur terminaux mobiles avec une approche client serveur. Leur méthode est la suivante :
1. détection des arêtes sur les textures des façades des batiments (précalculs),
2. vectorisation de ces arêtes : création de couples de points définissant le point d’origine et le point
d’arrivé de chaque ligne (précalculs),
3. pendant l’affichage, le serveur envoie ces couples sur le réseau,
4. le client reçoit les points et affiche les lignes correspondantes.
FIG. 1: Pipeline utilisé par Quillet et al. [QTM05, QTG+06].
Les points forts
Une faible quantité de données transite sur le réseau. les lignes sont envoyées à la place d’une texture et
cela peut diminuer la taille des données à envoyer d’un facteur de 10.
leur méthode est progressive. Le serveur n’envoit pas toutes les lignes d’un seul coup. L’affichage des
lignes coté client se fait donc petit à petit.
Ils utilisent une approche multirésolution. Suivant la distance d’une façade par rapport à l’observateur,
le nombre de lignes affichées ne sera pas le même. Plus la façade est proche, plus il y aura de détails et
inversement.
Les points faibles
Les lignes reçues par le client ne sont pas affichées sous forme de texture, mais avec des traits dans
l’espace 3D. Ils sont placés à coté des façades (car cela provoque des erreurs de gestion de profondeurs en
les positionnant exactement sur les murs), il y a donc un espace entre les façades et les lignes. Il en résulte
aussi un problème lié aux faces arrières. Lorsqu’on est positionné derrière un bâtiment, ses façades ne
s’affichent pas forcément, mais les traits le sont obligatoirement. Il apparait donc parfois les lignes d’un
bâtiment que l’on ne voit pas.
Leur méthode est limitée à l’affichage des lignes. Elle ne permet pas de faire d’autres types de rendu
non-photoréalistes.
2
Objectifs du stage
Généraliser les travaux de Quillet et al. [QTM05, QTG+06] en utilisant des textures vectorielles [Gro03].
Ces textures ont la particularité d’être indépendantes de la résolution souhaitée et sont généralement beau-
coup moins volumineuses que les textures matricielles.
Utiliser la spécification d’OpenVG [wg07] qui permettra d’obtenir un rendu rapide avec les clients dotés
d’un processeur graphique vectoriel.
Créer de nouveaux rendus pour illustrer la généricité de la méthode.
Fonctionnement
Vue d’ensemble
La plateforme Elkano lit des fichiers vrml [vrm97] et fonctionne avec un graphe de scène. Il est possible de
personnaliser les noeuds du graphe de scène comme on l’a fait ici pour afficher des textures vectorielles.
Prenons l’exemple d’un fichier vrml simple :
DEF objet Transform {
children Shape {
appearance Appearance {
texture ImageTexture {
url "grid.svg"
}
}
geometry Box { size 3 3 3 }
}
translation 1 0 0
}
Un visualiseur quelconque ne pourrait pas lire ce fichier car il ne connait pas le format SVG pour une
texture. Nous avons mis en place un plugin permettant de les lire. Celui-ci est alors automatiquement appelé
lorsqu’une telle texture est trouvée. Le pipeline utilisé est illustré par la Figure 2 :
FIG. 2: Pipeline (simplifié) utilisé pour le plugin de rendu de textures vectorielles
Le serveur lit le fichier SVG (avec la bibliothèque libsvg [lib05]), récupère chacun des éléments dans un
tableau, puis les envoit au client (qui peut lui en demander seulement un certain nombre). Le client utilise
alors la biblothèque OpenVG [wg07] pour afficher les éléments dans une texture qui est ensuite plaquée sur
les façades des bâtiments.
3
Principales méthodes
La classe TextureVecNodeCreator contient les méthodes qui associent la plateforme Elkano à notre plugin
(PLGTextureVec). La méthode getExtensions permet de dire pour quel type de fichier un noeud TextureVec-
Node doit être créé. Il est aussi possible d’aller chercher des informations dans les fichiers de configuration.
Nous permettons au client d’influencer la taille des packets qui transitent sur le réseau car nos textures sont
progressives (fichier Magellan/Scripts/{Linux|Win32|WinCE}/client.cfg), nous y reviendrons plus tard.
La classe TextureVecNode contient les méthodes principales pour lire coté serveur et afficher coté client.
Voici une description des principales méthodes publiques utilisées :
computeVS (héritée de MGFNode) : méthode appelée à chaque rendu et utilisée par le client pour deman-
der un certain nombre d’éléments SVG au serveur.
settleInPVS (héritée de MGFNode) : méthode utilisée pour créer et initialiser la texture qui sera affichée
(PVS=Potentially Visible Set). Au cas où on y passe plusieurs fois, on dispose d’une variable qui permet
de savoir si la texture concernée est déjà visible (et dans ce cas, pas besoins de la créer de nouveau).
removeFromPVS (héritée de MGFNode) : destruction de la texture.
serialize (héritée de MGFNodeRemote) : le serveur utilise cette méthode pour transmettre des données au
client via le réseau.
unserialize (héritée de MGFNodeRemote) : le client reçoit les données du serveur.
mergeImport (héritée de MGFProgressiveNode) : si ce n’est pas la première fois que le client reçoit des
données du serveur, alors le noeud du graphe de scène qui reçoit ces données n’est pas le client mais un
noeud temporaire. Cette méthode est donc utilisée par le noeud temporaire pour récupérer les variables
nécessaires au calcul de la progression dans le véritable client. Nous l’utilisons ici pour récupérer le
contexte EGL, obligatoire pour créer des éléments OpenVG. Cette fonction est bloquante, il ne faut donc
pas trop mettre de calculs à l’intérieur.
mergeCompute (héritée de MGFProgressiveNode) : on vient de récupérer les variables avec la méthode
précédente ; on peut donc s’en servir ici. On l’utilise pour activer le contexte EGL associé aux éléments
que l’on veut créer (celui qui correspond au noeud du “vrai” client).
mergeExport (héritée de MGFProgressiveNode) : méthode opposée à mergeImport. Le noeud temporaire
va envoyer les changements au client. Il demande au client de créer les éléments OpenVG qu’il a reçu
(fonction bloquante).
activate (héritée de MGFTextureNode) : activation de la texture par le client.
inactivate (héritée de MGFTextureNode) : désactivation de la texture par le client.
refreshResident (héritée de MGFResidentNode) : méthode appelée à chaque rendu et utilisée par le client
pour raffraichir la texture (seulement si nécessaire : si on a desssiné de nouveaux éléments).
Seule la fonction serialize est utilisée par le serveur. Toutes les autres sont spécifiques au client.
Déroulement
Lorsqu’une texture SVG est détectée dans le fichier vrml, deux noeuds TextureVecNode sont créés : le pre-
mier pour le serveur et le second pour le client. Ces noeuds sont créés par le biais de la classe TextureVec-
NodeCreator qui va au préalable chercher la taille des paquets qui transitent sur le réseau dans le fichier de
configuration du client.
La fonction serialize du serveur est alors appelée pour envoyer les premières données au client. La première
fois que l’on passe dans cette fonction, le fichier SVG est parcouru grâce à la bibliothèque libsvg [lib05].
4
On dispose alors d’un graphe composé d’éléments svg. Ces élements sont placés dans un tableau (fonction
serializeRec) pour faciliter leur parcours. La méthode findSizeMinMax est ensuite utilisée pour calculer les
dimensions de la texture SVG : largeur, hauteur et taille totale en octets. En effet, une texture vectorielle
n’est pas forcément centrée sur l’origine. Une fois ces paramètres calculés, ils sont envoyés au client qui les
reçoit avec la fonction unserialize.
Celui-ci calcule le nombre d’éléments SVG qui doit être envoyé par le serveur dans chacun des paquets.
La client demandera toujours à recevoir au minimum un élément, même si la taille moyenne d’un élément
est plus grande que la taille d’un paquet. Il ne sert a rien de demander la moitié d’un élément puisqu’il ne
pourrait pas être affiché correctement. Le contexte EGL [wg05a] qui permet de mettre en place une surface
de dessin pour les méthode d’OpenVG [wg07] est alors créé. EGL permet de dessiner sur plusieurs types de
surfaces :
dans une fenêtre existante (comme glut),
dans un “pbuffer” qui, par exemple, peut être une image OpenVG ou une texture OpenGL ES,
dans un “pixmap” (une grille).
On se sert ici d’un pixmap qui est simple d’utilisation et qui permet de transformer la grille en texture
OpenGL facilement, mais il faudra surement essayer les pbuffer pour dessiner directement dans une texture
(puisque c’est ce qu’on veut au final). Pour le moment il y a encore une petite transition entre le pixmap et
la texture que nous verrons plus loin. Le contexte ainsi créé doit enfin être activé. A noter qu’un élément
OpenVG créé dans un contexte ne peut pas être dessiné sur une surface qui est associée à un autre contexte.
Il faut donc penser à activer le contexte courant du noeud sur lequel on travaille avant d’utiliser les méthodes
OpenVG (un nouveau contexte est créé pour chacune des textures SVG du fichier vrml).
Si la façade du bâtiment est visible, la fonction settleInPVS est appelée. On y crée la texture OpenGL et
on l’associe au pixmap. C’est aussi dans cette méthode que l’on dit à Elkano que le noeud est résident,
de manière à ce que la fonction refreshResident soit appelée à chaque rendu (pas la peine de raffraichir la
texture si elle n’a pas encore été créée). La fonction activate est aussi appelée à chaque rendu pour activer la
texture qui correspond au noeud courant.
La méthode suivante est computeVS dans laquelle le client demande au serveur de lui envoyer des éléments,
par rapport au nombre d’éléments contenus dans un paquet et à ceux qui ont déjà été reçus. C’est ici que
le client recharge le noeud courant, de manière à ce que la méthode serialize du serveur soit appelée de
nouveau (et ceci, jusqu’à ce que tous les éléments soient reçu).
Coté serveur, c’est la seconde fois que la fonction serialize est appelée. On envoie donc le nombre d’éléments
souhaité par le client sur le réseau (fonctions serializeTable et serializeStyle). Une des contraintes du stage
a été de ne pas utiliser d’autres bibliothèques que OpenVG et OpenGL du coté du client pour que le plugin
puisse être utilisé par le plus grand nombre de clients possible. Il faut donc convertir les éléments SVG
du serveur (qui sont propres à la bibliothèque libsvg) avant de les envoyer. Chacun des éléments SVG est
associé à un style (taille des traits, couleur des traits, couleur de remplissage, ...) qui est aussi envoyé au
client. Pour le moment, nous avons mis en place un style minimal (couleurs et tailles des traits) et nous
traitons seulement les chemins et les rectangles pour les éléments.
Comme on l’a vu tout à l’heure, ce n’est pas le client qui reçoit ces éléments, mais un noeud temporaire (car
ce n’est pas la première fois que l’on passe dans la fonction unserialize). On crée alors un tableau d’élé-
ments SVG avec une structure temporaire (voir fichier Inc/Plugin/svgData.h). On pourrait vouloir construire
directement les éléments OpenVG, mais cela est impossible car on ne connait pas le contexte qui doit leur
être associé. En effet, les fonctions relatives aux noeuds progressifs qui nous auraient permis de récupérer ce
5
1 / 9 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !