3/5
3. Textures

Objectif de scène 3D obtenue en fin de séance
Code d’exemple
On considère dans cette partie le code des fichiers scenes/3D_graphics/02_texture/example_texture.cpp/hpp. Compilez ce code en utilisant le mot clé SCENE_EXAMPLE_TEXTURE dans le fichier _scenes/current_scene.hpp.
Une fois executé, ce code affiche un quadrangle muni d’une texture.
L’application d’une texture nécessite deux étapes
-
Le choix des coordonnées de textures, appelées également coordonnées \((u,v)\), ou encore \((s,t)\)
-
Ici les coordonnées sont stockées dans le buffer
surface_cpu.texture_uv.
-
-
Le choix d’une image qui doit être stockée sur le GPU. Similairement aux buffers OpenGL, un identifiant (ici texture_id) est accessible dans le code.
-
Le chargement de l’image en mémoire centrale est réalisée par la fonction
image_load_png -
L’envoie de l’image en mémoire du GPU est réalisé par la fonction
create_texture_gpu
-
Au moment d’afficher la surface, l’identifiant de l’image de texture à utiliser est réalisé par la commande glBindTexture(cet identifiant reste valide tant qu’une autre texture n’est pas activée).
Rem. Il est également possible d’attacher un identifiant de texture à un objet mesh_drawable (ex. surface.texture_id = texture_id) qui est alors automatiquement utilisé au moment de l’affichage.
Note. Le shader (appelé par shaders["mesh"]) utilise dans tous les cas une texture. Lorsque des objets "non texturés" sont affichés, on utilise par défaut une image blanche, qui ne modifie ainsi pas la couleur de l’objet.
-
Si vous modifiez les positions des coordonnées dans l’espace, l’image de la texture reste attachée à chaque sommet (d’après ces coordonnées de texture). L’image peut alors apparaitre comme compressée ou étirée.
-
Modifiez désormais les coordonnées de textures et tenter d’expliquer le résultat obtenu dans les configurations suivantes
surface_cpu.texture_uv = {{0,0.5}, {0.5,0.5}, {0.5,0}, {0,0}};
surface_cpu.texture_uv = {{0.25,0.5}, {0.5,0.5}, {0.5,0.25}, {0.25,0.25}};
surface_cpu.texture_uv = {{0,2}, {2,2}, {2,0}, {0,0}};
surface_cpu.texture_uv = {{0,3}, {1,3}, {1,0}, {0,0}};
surface_cpu.texture_uv = {{-1,2}, {2,2}, {2,-1}, {-1,-1}};
Exemple du cas où surface_cpu.texture_uv = {{0.25,0.5}, {0.5,0.5}, {0.5,0.25}, {0.25,0.25}};
Notez que les coins de l’images d’origine correspondent toujours aux coordonnées (0,0), (0,1), (1,1), et (1,0).
Indiquer des coordonnées (u,v) inférieur à 0, ou supérieur à 1, revient à dépasser les bords de l’image d’origine. Dans cet exemple, le dépassement apparait en noir. Cependant le comportement associé au dépassement peut être adapté à l’aide de la fonction OpenGL glTexParameteri avant l’affichage de la surface.
-
Modifiez la valeur de
GL_CLAMP_TO_BORDERenGL_MIRRORED_REPEATpour les deux lignes associées àglTexParameteri. Observez le résultat lorsque vous dépasser la valeur 1 cette fois.
Application au terrain
Reprenez l’application du terrain et modifiez celle-ci afin d’y plaquer une texture. Notez qu’il est nécessaire de réaliser les deux étapes:
-
Charger l’image que vous souhaitez plaquer sur le terrain
-
Ajouter des coordonnées de textures (uv) pour chaque sommmet du maillage du terrain.
Pour l’ajout des coordonnées de texture, il est nécessaire de modifier la fonction create_terrain en
-
Initialisant le buffer correspondant aux coordonnées de texture
-
terrain.texture_uv.resize(N*N);
-
-
Affectant les coordonnées de texture dans la boucle de remplissage des coordonnées
-
`terrain.texture_uv[kv+N*ku] = … `
-
Si vous ne voyez pas comment remplir les valeurs de texture_uv, faites un schéma d’un terrain composé de \(5\times 5\) sommets et tenter de dessiner la correspondance avec l’image que vous souhaitez plaquer.
Bruit de Perlin
Considérez le code d’exemple 3D_graphics/02_texture/exemple_perlin (mot clé SCENE_EXAMPLE_PERLIN).
Ce code applique une déformation de hauteur sur une grille régulière (initialement plane) sous la forme d’un bruit de Perlin. Celui-ci est paramétrable à l’aide des sliders de l’interface.
On rappel que le bruit de Perlin est formé à partir d’une fonction pseudo-aléatoire \(b(p)\) qui a tout point \(p\) renvoit une valeur scalaire déterministe. \(b\) est une fonction lisse à valeur entre \([0,1]\) et non périodique.
Le bruit de Perlin \(P\) est obtenu en sommant plusieurs instance de \(b\) avec des fréquences augmentant, et amplitude diminuant.
\(\displaystyle P(p) = h\;\sum_{k=0} ^ {octaves} \alpha ^ k\,b(2 ^ k\,s\,p)\)
-
\(\alpha\): persistance
-
\(s\): paramètre de scaling
-
\(h\): paramètre de hauteur
Les différents paramètres de ce bruit peuvent être manipulés interactivement à l’aide des sliders de l’interface. Retrouvez le rôle de chacun.
Rem.
-
Notez que la couleur associée à chaque sommet dépend de sa hauteur.
-
Le bruit de Perlin est évalué par une bibliothèque externe utilisant lui même l’approche du simplex noise. Notez que la bibliothèque permet de générer des bruits en dimension 1, 2, et 3 (volume).
Utilisez ce bruit de Perlin pour ajouter des détails à votre terrain déjà existant. Essayez de préserver l’apparence globale de votre fonction initiale (forme à basse résolution contrôlée explicitement par des fonctions gaussiennes) sur laquelle vous ajoutez le bruit procédural de faible amplitude pour donner l’impression visuelle de détails naturels à plus hautes fréquences.
Billboards
Les billboards (ou imposteurs), consistent à utiliser des images d’objets sur fond transparent en tant que texture pour représenter des objets d’apparence complexe sur une géométrie simple (typiquement des quadrangles).
Considérez le cas du code example_billoards. Ce code utilise une texture de brins d’herbe sur fond transparent.
Cette texture est appliquée de deux manières différentes
-
Premièrement sur un quadrangle qui fait constamment face à la caméra: permets de donner l’impression à l’utilisateur d’être toujours en face des brins d’herbes.
-
Deuxièmement sur deux quadrangles placés orthogonalement, mais d’orientation statique: évite les artefacts du au changement d’orientation du billboard, mais géométrie visible à 45 degrés.
-
Observez la manière dont la texture est utilisée dans la fonction d’affichage pour permettre la prise en compte de la transparence.
-
Utilisez les billboards pour ajouter des détails à votre scène, par exemple en ajoutant des fleurs et de la végétation sur le terrain.
Note sur la transparence en OpenGL
L’utilisation d’objets transparents (ou semi-transparents) en OpenGL nécessite des précautions supplémentaires par rapport au maillage classique.
-
Premièrement, ils doivent être affichés en dernier (après les objets standards de la scène), afin de permettre l’utilisation du "blending" par le paramètre alpha.
-
Deuxièmement, les objets transparents ne peuvent pas utiliser le buffer de profondeur, en effet, la géométrie du quadrangle n’indique pas si un objet peut être visible ou non derrière lui puisque c’est la texture qui porte cette information.
L’absence d’utilisation du buffer de profondeur lors de l’affichage de plusieurs billboards peut apporter des artefacts visuels: le billboard affiché en dernier apparait toujours devant celui affiché précédemment.
Pour éviter ces artefacts, il est possible de trier les billboards afin d’afficher ceux-ci du plus loin au plus proche de la caméra (l’ordre devant être réactualisé à chaque frame).
Skybox (extension uniquement si vous êtes en avance)
Une skybox est un cube entourant la scène sur laquelle une texture d’environnement est plaquée. La skybox permet de donner l’illusion que la scène est plongée dans un environnement plus large. La texture utilisée doit correspondre au cas d’un cube déplié, et les couleurs au niveau des arêtes doivent être cohérentes sur l’ensemble des faces.
Une fois le cube créé, celui-ci est placé de manière à englober la scène, et centré en permanence autour de la position de la caméra. Cela donne ainsi l’impression d’un paysage visible au loin.