Rendu Non-Photoréaliste (NPR)
Hachures en Temps Réel
OBJECTIFS
L'objectif de ce projet est la réalisation d'une application
effectuant un rendu hachuré d'un objet 3d. Nous nous sommes
principalement intéressés a la gestion des textures de
hachures ou de points représentant le ton, la composition et la
forme de l'objet. Dans un premier temps, nous avons
généré une tonal art map. Il s'agit d'un tableau
de mip-mapped textures correspondant aux différents tons
présents dans l'image. On utilise plusieurs résolutions
pour chaque ton afin de garder une taille appropriée pour les
hachures. La résolution la plus élevée est de 128
par 128. On construit aussi toutes les résolutions de puissances
de 2 inférieures pour définir les mipmap qu'il faut
fournir a OpenGL. Les différents tons sont utilisés pour
représenter les parties plus ou moins ombragées de
l'objet. On utilise 6 tons.
on obtient au final une tonal art map de 8*6 textures. Ensuite, nous
avons appliqué ces textures à un objet 3d apres calcul
des tons locaux sur celui-ci. Les tons locaux de l'objet sont
déterminés en fonction de la lumière et de la
surface locale correspondante.
ALGORITHME
Génération de la tonal art map
Les tonal art map doivent respecter certaines contraintes de
cohérence:
-Pour un ton donné, toutes les textures doivent avoir le
même niveau de gris moyen.
-Un point ou un trait présent dans une texture donnée
doit être présent dans toutes les textures de
résolution et de ton supérieur.
-les traits ont la même largeur quel que soit la
résolution de la texture et les points le même rayon.
-Un trait a la même longueur (relativement a la résolution
de la texture) dans toutes les textures dans lesquelles il est
présent.
Pour générer la première texture (ton 1 et
résolution 16x16), on ajoute des traits les un apres les autres
dans une image vide jusqu'à obtenir le niveau de gris voulu.
Pour chaque trait ajouté, il y a en fait 100 candidats. On
effectue un produit scalaire entre l'image en construction et chacun
des cents candidats afin de déterminer le meilleur trait en
terme de positionnement dans la texture. A chaque fois qu'on ajoute un
trait dans une texture, on l'ajoute également dans toutes les
textures de tons superieurs et de résolutions superieures.
Cependant pour les textures de résolutions superieures, on
change la longueur du trait
afin qu'elle reste proportionnelle à l'image; la largeur elle
reste toujours la même. Quand cette image est terminée, on
passe à celle de résolution supérieure (32*32) et
de même ton: cette image n'est pas encore assez foncée car
si les traits ont la même longueur relative, leur largeur est
fixe donc leur surface relative est inférieure dans une image
plus grande. On continue ainsi jusqu'à ce que toutes les
textures de ton 1 soient assez foncées. Quand toutes les images
d'un ton sont terminées, on passe au ton supérieur et on
recommence. Enfin les textures de résolution inférieure a
16x16 sont obtenues par sous-échantillonnage. C'est à ce
moment là que l'on perd la propriété de largeur
constante des traits. Ce n'est cependant pas un problème car ces
textures sont utilisées quand l'objet est très
éloigné de la caméra, dans ces conditions il est
difficile d'afficher des traits de trois pixels de large quand l'objet
en entier mesure un dizaine de pixels.
Ci-dessous,un exemple de tonal art map, pour des raisons de
visibilité, on affiche toutes les textures sur un carré
de 128*128 pixels. Le ton j se trouve sur la colonne j et la
résolution 2^(i-1) sur la ligne i.
Lorsqu'on décide de générer une tonal art map, on
a alors le choix entre des traits et des points. Pour les traits, on
peut préciser leurs longueurs minimales et maximales relatives,
leur inclinaison minimale et maximale, leur courbure, leur sens de
courbure, le rang de ton pour lequel on peut ajouter des traits
orthogonaux aux premiers et le rang de ton pour lequel on ajoute des
traits dans les deux directions. On peut aussi définir les
différents niveaux de gris pour chacun des 6 tons.
Application des textures à un objet 3d
Pour obtenir un premier résultat satisfaisant, nous avons choisi
d'appliquer dans un premier temps les textures sur un objet à
surfaces non arbitraires: un icosaèdre. Nous avons défini
à la main les coordonnées de ces vertex ainsi que les
coordonnées de texture. En premier lieu, il a fallu
déterminer le modèle de lumière è utiliser.
N'étant pas des professionnels de l'openGL, nous avons
décidé de désactiver la lumière OpenGL pour
utiliser notre propre modèle. Nous représentons la
lumière par un vecteur, nous calculons ensuite l'illumination
d'une face ou d'un vertex par le produit scalaire de la normale
à la face ou au vertex. Cela nous donne un facteur
d'illumination entre -1 et 1 que l'on ramène ensuite entre 0 et
6 (en réalité de -1 à 7 puis de 0 à 6 par
projection pour renforcer l'importance du blanc implicite en 0 et des
zones pas du tout éclairées en 6). Le facteur
d'illumination nous permet alors de déterminer le ton de la
texture à appliquer. Nous avons calculé deux types de
vecteurs normaux: les vecteurs normaux aux faces et les vecteurs
normaux aux vertex. On obtient ainsi deux représentations
différentes des ombres sur l'objet. Dans la première, on
obtient une seule intensité par face. On utilise alors deux
textures de la tonal artmap par face. La texture qui a le ton
inférieur au ton voulu est affichée opaque (alpha=1)
et la texture qui a le ton supérieur au ton voulu est
affichée avec un alpha proportionnel à la
différence entre son propre ton et le ton voulu. L'autre
représentation utilise 6 textures par face à raison de 2
textures par vertex du triangle. Pour chaque vertex, on applique les
deux textures avec la même méthode que pour les faces.
Application de 2 ou 6 textures par face à l'icosaèdre
Application des textures à un objet à surfaces
arbitraires
Dans le cas d'un objet à surface arbitraires au format x3d, il
nous a fallut obtenir les coordonnées de texture des vertex et
les différentes normales nécessaires à notre
calcul d'illumination. Nous avons utilisé la librairie fournie
x3dtoolkit qui permet de charger les formats x3d et définit les
normales dont nous avons besoin. Pour calculer les coordonnées
de textures, nous avons fait appel au binôme de Maxime Houlier et
Ronan Quillévéré qui appliquait des patchs de
texture sur le modèle. A partir de là, nous avons pu
faire notre calcul d'illumination et appliquer nos textures de la
même façon que sur l'icosaèdre.
A propos de l'interface
L'interface des deux programmes permet de visualiser le modèle
et de regénérer une artmap pour la visualiser, il est
possible de définir tous les paramètres des traits pour
l'artmap.
Dans la partie visualisation, il est possible de lancer une animation:
le vecteur de lumière tourne alors autour de l'axe des z. On
peut visualiser le modèle avec les 2 méthodes
d'illumination: en prenant les normales aux sommets ou aux faces.
Dans le cas des modèles x3d, la touche l permet de charger un
nouveau modèle.
RESULTATS
Pour la génération des art map, le résultat est
satisfaisant. Il y a cependant quelques petits problèmes et
améliorations possibles:
-la génération est lente dans le cas des points.
-on arrête d'ajouter des traits quand le niveau de gris
dépasse celui attendu, il peut arriver qu'il n'y ait pas de
trait ajouté entre 2 niveaux de ton si ceux-ci sont assez
proches et qu'on a ajouté en dernier un trait qui apporte
beaucoup au niveau de gris moyen.
-les traits sont assez largement paramétrables mais on pourrait
imaginer d'autres paramêtres (par exemple la largeur commune de
tous les traits)
Nous avons eu quelques problèmes au début pour
sauvegarder nos images dans un format de fichier, avant de mieux
comprendre comment fonctionnent les Qimages.
Pour l'affichage et l'illumination, nous sommes fiers du rendu que nous
obtenons malgré la simplicité de notre modèle de
lumière: pas d'ombres, un seul type de source lumineuse...
Dans le cas des normales aux vertex, on obtient des faces un peu trop
grisées, particulièrement au centre. Cela vient des
facteurs alpha mais nous n'avons pas réussi à trouver
comment modifier la fonction qui calcule le coefficient alpha en chaque
point de la face en fonction du coefficient aux sommets. Nous pensons
qu'OpenGL utilise une fonction linéaire alors que ce qui
correspondrait plus a notre représentation serait une fonction
exponentielle qui reste proche du coefficient alpha maximal jusqu'au
centre de la face et chute ensuite vers le coefficient minimal.
En particulier, nous avons pu constater que la solution de construire
les plus petites textures par sous-échantillonnage est
pertinente car quand l'objet s'éloigne, il n'y a pas de
"brisure" dans le rendu etl'objet s'uniformise légèrement
en niveau de gris ce qui est cohérent avec la perception que
l'on a naturellement des objets éloignes.
Un autre problème qui viendrait apparemment de la
génération des coordonnées de textures est que
nous ne pouvont pas charger tous les modèles x3d fournis.
Pour aller plus loin, on pourrait completer le modéle de
lumiére en ajoutant par exemple de la lumière
"universelle" présente sur toutes les faces, les sources
lumineuses localisées et dont l'intensité varie en
fonction de la distance. On pourrait aussi gérer les ombres et
la réflexion de la lumière sur les faces.
Il serait aussi intéressant d'ajouter les contours
calculés par le binôme de Gontran Magnat et Samir Asghar.