Introduction

L'objectif de ce TP est la création d'une petite architecture pour la modélisation et la visualisation en temps réel de scènes naturelles complexes. Le travail effectué se porte principalement sur le rendu de terrain réaliste puis l'optimisation du niveau de détail.

Modélisation de formes géométriques élémentaires

Pour chaque primitive, on définit les coordonnées des sommets, ainsi que les normales en chaque sommet afin de réaliser l'illumination de l'objet.

Cube

Il s'agit d'un simple cube à 6 faces, les normales en chaque face orientées vers l'extérieur du cube.

Cylindre

Le cylindre est défini comme deux couvercles et une enveloppe, à partir de coordonnées circulaires.

Sphère

Les sommets sont définis à partir de coordonnées sphériques. Les normales sont dirigées sur l'axe centre-sommet, vers l'extérieur.

Boîte englobante

Chaque objet définit sa boîte englobante, qui est le plus petit cube contenant l'objet. La boîte englobante de la réunion de deux objets est la plus petite boîte contenant ces deux objets.

On peut visualiser la boîte englobante de chaque objet ou union afin de tester celle-ci. La boîte est affichée en pointillés.

Boîte englobante
Primitives cube, cylindre, sphères, et boîte englobante de la réunion de ces primitives

Texture des objets

On crée une classe TextureManager qui permet de gérer les matériaux. Un matériel est identifié par son nom ou son rang, ce qui évite de charger plusieurs fois la même texture.

Puis chaque objet est texturé : on rajoute le chargement des images et la définition des coordonnées de textures aux objets vus précédemment.

Primitives texturées
Primitives cylindre et sphères texturées

Objets complexes

Construction

On utilise les trois primitives vues précédemment pour modéliser un humanoïde. Les primitives sont positionnées grace à la pile de transformations GL_MODELVIEW d'OpenGL. Chaque objet est placé relativement à un autre, ce qui définit un arbre de transformation :

  • Tronc
    • Tete
    • Bras gauche (ry1, rz1)
      • Avant-bras gauche (ry2, rz2)
    • Bras droit (ry3, rz3)
      • Avant-bras gauche (ry4, rz4)
    • Cuisse gauche (ry5, rz5)
      • Mollet gauche (ry6, rz6)
    • Cuisse droite (ry7, rz7)
      • Mollet droit (ry8, rz8)

Humanoïde
Humanoïde généré à partir de primitives géométriques simples

Génération de terrain

Géométrie du terrain

La géométrie du terrain est générée à partir d'une carte de hauteur. On utilise un vecteur de taille unitaire qui définit les dimensions de chaque pixel de la carte de hauteur.

Les normales sont générées pour chaque sommet de la façon suivante. On dispose d'un tableau normale[] qui contient autant d'éléments, initialement nuls, qu'il y a de sommets. Pour chaque face, on calcule sa normale puis on ajoute celle-ci dans le tableau normale[], aux rangs des 3 sommets qui composent la face. Chaque normale de sommet reçoit donc la contribution des 6 faces adjacentes, on pondère donc chaque normale de face par 1/6.

Texture du terrain

On utilise deux textures, l'une de roc et l'autre de neige. La texture est assignée selon l'altitude de la face : à partir d'un seuil, on bascule d'une texture à l'autre.

Skybox

Afin d'ajouter du réalisme, on ajoute une boîte qui englobe tout le terrain. Sur les faces intérieures, on texture une image de coucher de soleil sur des montagnes.

On ajoute un brouillard de la même couleur que le fond de la skybox (teinte bleutée) afin d'assurer un dégradé entre la scène (géométrie réelle) et la texture de la skybox.

On prend garde à placer la vraie source de lumière dans la même position que le soleil texturé sur la skybox, sinon l'illumination des faces du terrain ne sera pas réaliste.

Terrain
Rendu de relief avec une skybox

Génération de forêts

Imposteurs

La primitive de base de la forêt est un arbre modelisé selon la méthode des imposteurs. Il s'agit de deux plans perpendiculaires sur lesquels est plaqué une texture d'arbre. On dispose de trois textures d'arbres qui sont choisies aléatoirement afin d'aporter de la variété.

Placement des arbres

On génère un certain nombre d'arbres, qui sont placés autour d'un point fixe, dans un cercle de rayon donné. On contraint l'altitude de l'arbre à un intervalle donné (par exemple entre 100m et 1000m).

Forêt
Forêt générée avec la technique des imposteurs

Niveau de détail

Génération du terrain

Afin d'améliorer la vitesse de rendu du terrain, on précalcule plusieurs terrains avec un nombre décroissant de polygones. Le premier terrain est généré à partir de la carte de hauteur avec un pas de 1 pixel. Le second terrain est généré avec un pas de 2, puis 4, 8, etc. Chaque objet généré correspond à un niveau de détail.

Affichage

Lors de l'affichage, on utilise une subdivision hiérarchique de l'objet Terrain afin de choisir le niveau de détail voulu. Pour cela, on part d'un niveau de détail grossier et on calcule la distance de la caméra au centre de l'objet. Si cette distance est supérieure à un seuil, on affiche l'objet avec le niveau de détail grossier. Si la distance est inférieure à un seuil, cela signifie que la caméra est proche de l'objet et que l'on a besoin d'afficher plus de détails. On subdivise donc l'objet en 4 parties puis on applique l'algorithme récursivement sur chacun d'eux avec un niveau de détail plus fin.

Un avantage immédiat de cette technique, est que l'on peut tester la visibilité d'une partie du terrain gràce à sa boîte englobante. Si une portion de terrain se trouve derrière la caméra, on ne l'affiche pas, ce qui evite des transferts de polygones en direction de la carte graphique.

Plusieurs problèmes se posent. Le premier est de calculer la distance de la caméra à l'objet. Le parti pris est de prendre le centre de l'objet, mais idéalement on veut calculer la distance avec le polygone le plus proche de la caméra. Le second problème est le raccord entre deux régions de niveau de détail différent. En effet, les sommets qui se trouvent à la frontière ne sont pas forcément alignés, ce qui cause des trous à l'affichage. Enfin, lorsque l'on déplace la caméra, on peut constater des sauts d'un niveau de détail à un autre.

Niveau de détail
Niveau de détail sur le terrain

Objets et animation

Format OBJ

On s'interresse ici aux modèles créés par un artiste dans un outil dédié (Alias Wavefront / Maya). Ces modèles sont sauvegardés au format OBJ puis chargés à l'aide de la bibliothèque glm.

Animation

Pour animer le personnage, on charge différents modèles représentant des moments clés de l'animation, puis on les affiches successivement.

Personnage
Personnage animé modélisé sous Maya

Conclusion et améliorations

Pour conclure, voici un certain nombre d'améliorations proposées pour la poursuite du travail.

Texture du terrain

La texture du terrain est soit de la roche, soit de la neige au dessus d'un certain seuil. Il serait bien d'utiliser un plus grand nombre de textures afin d'avoir plus de variété, ou le multitexturing pour avoir des transitions plus douces.

Niveau de détail de la forêt

Afin d'afficher un plus grand nombre d'arbre, on pourrait utiliser une structure gérant le niveau de détail comme il a été fait pour le terrain. En particulier, les arbres se trouvant derrière la caméra se trouveraient éliminés.

Animation

Enfin, le personnage pourrait être animé suivant une interpolation des modèles clés afin d'améliorer la fluidité de l'animation.