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.