Textures
Pour avoir un terrain réaliste, il ne suffit évidemment pas d'avoir un maillage semblable à celui que nous avons décrit dans la partie précédente. Il faut également, entre autres, s'intéresser à la partie texturage de ce terrain, c'est-à-dire appliquer une couleur à chaque point du maillage. Pour travailler sur cette partie nous avons utilisé des shaders Cg, le langage de programmation de cartes graphiques de nVidia. Cette méthode nous permet de mieux répartir les calculs de textures entre le GPU et le CPU puisqu'une partie des calculs est fait uniquement sur la carte et ne transite plus par le bus.
Nous avons choisi d'orienter nos recherches vers deux types de représentations :
- une représentation axée sur la visualisation d'informations avec la réalisation d'un atlas 3D et d'un dégradé de couleurs vives en fonction de la hauteur ;
- une représentation axée sur le photo-réalisme d'un terrain en utilisant un certain nombre de textures appliquées à différents niveaux de hauteur.
Nous allons vous présenter un peu plus en détails ces différents types de représentation et le cheminement qui nous a amené aux résultats que nous vous montrerons plus loin.
Visualisation d'informations
Pour pouvoir commencer rapidement notre travail, nous avons commencé par nous intéresser à une représentation simple mais néanmoins efficace pour faire les tests de lightmap ou de géomorphing. Ce premier type de représentation consistait à rendre le terrain par niveaux en fonction de l'altitude. Puis nous nous sommes intéressés à une représentation de type Atlas 3D. Nous vous présentons ci-dessous ces deux types de représentations.
Rendu de type Niveaux
Le principe de ce rendu est de représenter différents niveaux en fonction de l'altitude. Nous avons d'abord implémenté une version avec des valeurs prédéfinies dans le code. Cette méthode présentait l'inconvénient de ne pas pouvoir redéfinir facilement la valeur des niveaux ou encore les couleurs de ces niveaux. Nous avons donc choisi d'utiliser une texture en dégradé pour permettre à l'utilisateur de définir lui même les niveaux et les couleurs qu'il désire. L'exemple ci-dessous montre le résultat de l'utilisation d'un dégradé particulier appliqué au terrain.
Cette méthode se révèle assez riche pour définir des représentations différentes en éditant simplement la texture. En effet, on peut obtenir des effets intéressants comme la représentation ci-dessous où l'on ne dessine que des courbes de niveaux à l'aide de lignes dans la texture :
Rendu de type Atlas 3D
Nous avons voulu essayer de représenter le terrain en y apportant aussi des informations qui pourraient s'avérer plus utile pour un utilisateur. Nous avons donc utilisé un atlas pour scanner la région que nous traitions. Cette méthode imposait d'avoir une texture en haute définition. Evidemment cette méthode nécessite de créer une texture pour chaque nouveau terrain mais il est difficile de faire autrement puisque l'on fait entrer des informations spécifiques au terrain utilisé. Des déformations apparaissent lorsque les transitions de hauteurs sont trop brutales. Ce problème est en partie résolu par la taille de la texture qui est très détaillée mais il faudrait approfondir ce problème si l'on voulait obtenir des rendus plus appréciables. Vous pouvez voir ci-dessous un exemple du type de rendu que l'on obtient avec cette méthode :
Représentation réaliste
Pour représenter un terrain de manière réaliste, il faut lui appliquer des textures. Ces textures peuvent être combinées entre elles pour donner un meilleur effet visuel. Pour cela, il existe deux méthodes principales :
On peut utiliser des textures avec des masques de transparence correspondant aux différents niveaux de textures que l'on souhaite appliquer. La combinaison de ces textures donne ensuite l'impression qu'elles ne forment plus qu'une unique texture. Ce type de procédé est illustré par les figures ci-dessous où deux textures sont combinées :
Combinaison de calques de transparenceL'avantage de cette méthode est de pouvoir définir les zones intéressantes directement dans les textures mais elle a plusieurs inconvénients. Tout d'abord, chaque texture doit représenter le terrain tout entier, ce qui peut poser des problèmes de résolution. En effet, si l'on a un terrain assez grand, il faut avoir des textures de très bonne qualité pour oser espérer voir quelque chose lorsque l'on se rapproche du terrain. De plus, cette technique n'est pas automatique : à chaque nouveau terrain, il faut redéfinir un jeu de textures.
- On peut utiliser différentes textures et interpoler ces différentes textures en fonction de la hauteur dans le terrain. Ces textures n'ont donc plus de masques de transparence. Cette méthode présente plusieurs intérêts, on peut avoir des textures de plus basse résolution, et on peut changer de couche de texture plus facilement. De plus, on peut appliquer le même jeu de textures à tous les terrains, puisque la texture est choisie en fonction de la hauteur du terrain.
Nous avons choisi la deuxième méthode et cela pour plusieurs raisons. L'objectif de ce projet est de faire le rendu d'un terrain de grande taille, nous avons donc besoin d'optimiser au maximum les différentes parties de l'application, or la première méthode est trop coûteuse en place mémoire. De plus, la seconde méthode permet d'avoir une plus grande souplesse au niveau utilisateur puisque l'on peut changer une texture simplement sans avoir à redessiner quoi que ce soit.
Interpolation linéaire simple
Le premier shader que nous avons réalisé utilise un jeu de cinq textures. Ces textures sont choisies en fonction de la hauteur du terrain, c'est-à-dire que l'on définit une zone de hauteur pour chaque texture et que l'on interpole linéairement le passage d'une zone à une autre pour avoir un effet de fondu entre les deux textures et ainsi améliorer le rendu. La figure ci-dessous vous illustre ce que donne le résultat d'une telle technique :
L'inconvénient de cette méthode est d'être assez limitée sur les interpolations de textures, de telle sorte que l'on voit comme sur l'image ci-dessus, les zones de transitions. Nous avons donc tenté de chercher une méthode permettant de pallier à ce problème.
Interpolation à l'aide de gradients
Dans un deuxième temps, nous avons donc ajouté des gradients pour pouvoir définir les zones de transitions plus facilement. Le principe est simple, on procède par couches successives. Pour chaque couche, on dispose d'un gradient 1D en noir et blanc et d'une texture. Le blanc correspond à la zone où la texture doit être plaquée et le noir à la zone transparente où on laisse apparaître la couleur des couches déjà calculées. L'illustration ci-dessous vous montre le résultat d'une telle opération :
Cette méthode est beaucoup plus riche que la précédente. Tout d'abord, les transitions sont plus douces puisqu'il est possible d'ajouter plusieurs textures à un même niveau et que les gradients peuvent chevaucher les mêmes zones de transitions. Ensuite, elle permet d'avoir des textures plus détaillées sans augmenter le coût mémoire (en d'autres termes, répétées beaucoup plus de fois) sans que les répétitions ne soient trop visibles. En effet, les couches ne définissent pas forcément un nombre de répétitions identiques. Vous pouvez voir ci-dessous un exemple de rendu utilisant cette méthode, et où l'on voit nettement les transitions plus douces d'une hauteur à une autre.