XIV. Les textures▲
Nous poursuivons le tutoriel à partir du module de code précédent.
Désactivez d'abord le brouillard en commentant la ligne glEnable GL_FOG ou en supprimant tout le code concerné
On y verra mieux sans brouillard.
XIV-A. Chargement des textures▲
OpenGL ne fournit aucune fonction pour charger des images à partir d'un fichier.
À nous de charger l'image et de fournir à OpenGL les valeurs des couleurs de chaque pixel.
Le module ModOpenGLTextureLoader contient une fonction TextureAddFromFile qui crée une texture à partir d’un fichier image, en utilisant si besoin Gdi+ pour charger le format PNG notamment.
Vous pouvez également charger, dans une texture, des images au format TGA grâce à la fonction loadTGATexture du module ModOpenGLTextureTGA.bas.
Ce module est une traduction du loader de TGA en C de David Henry
Certaines cartes graphiques n'acceptent que les images de texture dont les dimensions sont des puissances de 2 (2, 4, 8, 16, 32…).
Il est conseillé de travailler avec des textures de dimensions 2, 4, 8, 16, 32, 64, 128…
Pour charger le fichier, nous utiliserons la fonction VB LoadPicture.
Cette fonction lit les formats : bmp, ico, rle, wmf, emf, gif, jpg.
Pour lire les informations (taille, profondeur de couleur), nous utiliserons la fonction GetObject de la bibliothèque windows gdi32.
Ensuite pour créer une texture, on utilise la fonction glGenTextures.
Cette fonction prend en premier paramètre le nombre de textures qu'on veut créer.
Et elle renvoie en deuxième paramètre le nom (en fait le numéro) de la première texture créée.
Une texture s'active avec la fonction glBindTexture.
Puis on la génère avec la fonction glTexImage2D.
Et enfin on désactive la texture courante (0 en texture), on la redéfinira quand on en aura besoin.
Tout ceci est effectué par la fonction TextureAddFromFile du module ModOpenGLTextureLoader.
Importez le module standard ModOpenGLTextureLoader.
Ce module contient une fonction VB de chargement de textures.
Cette fonction TextureAddFromFile renvoie le numéro de la texture créée à partir du fichier donné en paramètre.
Le paramètre pTransparentColor est optionnel : il permet de rendre une couleur transparente.
Pour activer la transparence, il faut :
- d'abord utiliser la fonction glEnable GL_BLEND;
- puis préciser le mode de mélange de couleurs, par exemple : glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA.
Nous mettrons la transparence en pratique dans le chapitre sur l'affichage des textes.
XIV-B. Application d'une texture sur les faces du cube▲
Pour qu'OpenGL affiche les textures, il faut d'abord les activer.
On pourrait les activer et les désactiver à chaque fois qu'on en a besoin, mais comme on va tout texturer on va faire simple et activer les textures une fois à l'initialisation.
Donc, dans la procédure d'initialisation InitScene ajoutez :
' Active les textures 2D
glEnable GL_TEXTURE_2D
Puis on effectue le chargement du fichier contenant la texture (une seule fois dans la procédure InitScene), grâce à la fonction créée précédemment.
On ajoute également en en-tête de module une variable pour conserver l'identifiant de la texture.
' Identifiant de la texture plancher
Private
gTexturePlancher As
Long
' Charge la texture
gTexturePlancher =
TextureAddFromFile
(
CurrentProject.Path
&
"\plancher.jpg"
)
Voici le fichier de la texture utilisée (c'est une photo de mon plancher) :
Ensuite il faut affecter la texture pour qu'elle soit utilisée lors du dessin du cube.
Avant le dessin du cube (avant glBegin), on affecte la texture :
' Affecte la texture
glBindTexture GL_TEXTURE_2D, gTexturePlancher
' N'affecte aucune texture
glBindTexture GL_TEXTURE_2D, 0
Il est souvent conseillé d'éviter de trop fréquents appels à glBindTexture.
Pensez à utiliser des méta textures.
On ne voit pas notre texture pour autant.
Et c'est normal, car nous n'avons pas défini de coordonnées de texture.
Il faut spécifier à OpenGL comment mapper la texture.
En effet la texture et le polygone sur lequel on souhaite l'appliquer ne correspondent pas forcément.
On pourrait demander d'appliquer une texture rectangulaire sur un triangle par exemple.
Dans le cas des faces du cube, c'est simple : on demande à ce que la texture recouvre toute la face.
Pour chaque vertice de la forme dessinée, on définit les coordonnées du texel correspondant (un texel c'est comme un pixel, mais pour une texture).
- (0,0) correspond au texel en bas à gauche de la texture.
- (1,1) correspond au texel en haut à droite de la texture.
Voici comment les points de la texture vont être affectés à la face avant par exemple :
On utilise une constante cT que l'on va ensuite modifier pour répéter la texture.
' Début de la primitive pour le cube
Const
cT As
Long
=
1
glBegin GL_QUADS
' Face du haut = vert
Call
glColor3d
(
0
, 1
, 0
)
Call
glNormal3d
(
0
, 1
, 0
)
Call
glTexCoord2f
(
cT, cT)
Call
glVertex3d
(
1
, 1
, -
1
)
Call
glTexCoord2f
(
0
, cT)
Call
glVertex3d
(-
1
, 1
, -
1
)
Call
glTexCoord2f
(
0
, 0
)
Call
glVertex3d
(-
1
, 1
, 1
)
Call
glTexCoord2f
(
cT, 0
)
Call
glVertex3d
(
1
, 1
, 1
)
' Face du bas = orange
Call
glColor3d
(
1
, 0
.5
, 0
)
Call
glNormal3d
(
0
, -
1
, 0
)
Call
glTexCoord2f
(
0
, 0
)
Call
glVertex3f
(-
1
, -
1
, -
1
)
Call
glTexCoord2f
(
cT, 0
)
Call
glVertex3f
(
1
, -
1
, -
1
)
Call
glTexCoord2f
(
cT, cT)
Call
glVertex3f
(
1
, -
1
, 1
)
Call
glTexCoord2f
(
0
, cT)
Call
glVertex3f
(-
1
, -
1
, 1
)
' Face de derrière = rouge
Call
glColor3d
(
1
, 0
, 0
)
Call
glNormal3d
(
0
, 0
, -
1
)
Call
glTexCoord2f
(
0
, 0
)
Call
glVertex3f
(
1
, -
1
, -
1
)
Call
glTexCoord2f
(
cT, 0
)
Call
glVertex3f
(-
1
, -
1
, -
1
)
Call
glTexCoord2f
(
cT, cT)
Call
glVertex3f
(-
1
, 1
, -
1
)
Call
glTexCoord2f
(
0
, cT)
Call
glVertex3f
(
1
, 1
, -
1
)
' Face de devant = jaune
Call
glColor3d
(
1
, 1
, 0
)
Call
glNormal3d
(
0
, 0
, 1
)
Call
glTexCoord2f
(
0
, 0
)
Call
glVertex3f
(-
1
, -
1
, 1
)
Call
glTexCoord2f
(
cT, 0
)
Call
glVertex3f
(
1
, -
1
, 1
)
Call
glTexCoord2f
(
cT, cT)
Call
glVertex3f
(
1
, 1
, 1
)
Call
glTexCoord2f
(
0
, cT)
Call
glVertex3f
(-
1
, 1
, 1
)
' Face de gauche = violet
Call
glColor3d
(
1
, 0
, 1
)
Call
glNormal3d
(-
1
, 0
, 0
)
Call
glTexCoord2f
(
cT, cT)
Call
glVertex3f
(-
1
, 1
, 1
)
Call
glTexCoord2f
(
0
, cT)
Call
glVertex3f
(-
1
, 1
, -
1
)
Call
glTexCoord2f
(
0
, 0
)
Call
glVertex3f
(-
1
, -
1
, -
1
)
Call
glTexCoord2f
(
cT, 0
)
Call
glVertex3f
(-
1
, -
1
, 1
)
' Face de droite = bleu
Call
glColor3d
(
0
, 0
, 1
)
Call
glNormal3d
(
1
, 0
, 0
)
Call
glTexCoord2f
(
cT, cT)
Call
glVertex3f
(
1
, 1
, -
1
)
Call
glTexCoord2f
(
0
, cT)
Call
glVertex3f
(
1
, 1
, 1
)
Call
glTexCoord2f
(
0
, 0
)
Call
glVertex3f
(
1
, -
1
, 1
)
Call
glTexCoord2f
(
cT, 0
)
Call
glVertex3f
(
1
, -
1
, -
1
)
glEnd
Les pixels ne correspondent pas toujours aux texels.
Il faut donc définir ensuite comment est lissée la texture.
On utilise pour cela la fonction glTexParameterf.
Remarque : cette fonction s'applique à la texture courante, il faut donc qu'elle ait été affectée avec glBindTexture.
Ajoutez ces lignes juste après l'appel à glBindTexture :
' Filtrage de la texture
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
- GL_TEXTURE_MAG_FILTER définit le filtre lors d'un agrandissement de texture.
- GL_TEXTURE_MIN_FILTER définit le filtre lors d'une réduction de texture.
Les filtres disponibles sont :
- GL_NEAREST : utilise le texel le plus proche : plus rapide ;
- GL_LINEAR : utilise la moyenne des quatre texels les plus proches : plus beau (lissé).
Pour GL_TEXTURE_MIN_FILTER, il y a également les filtres de mipmapping GL_*_MIPMAP_*, mais nous ne le détaillons pas tout de suite.
La valeur de GL_TEXTURE_MAG_FILTER par défaut est déjà GL_LINEAR.
Mais la valeur de GL_TEXTURE_MIN_FILTER par défaut est GL_NEAREST_MIPMAP_LINEAR.
Voici donc notre cube texturé :
XIV-B-1. Modes d'application d'une texture▲
On constate que la couleur de la texture s'est multipliée avec la couleur des faces.
On peut changer le mode d'application de la texture avec la fonction glTexEnv.
La fonction glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param définit le mode d'application avec param qui prend les valeurs :
- GL_MODULATE : multiplie la couleur de texture avec celle du matériau ;
- GL_DECAL : utilise le canal alpha de la texture : à utiliser pour appliquer des textures avec transparence ;
- GL_BLEND : mélange la texture et la couleur ;
- GL_REPLACE : remplace la couleur par la texture : la couleur n'est plus visible.
Attention : contrairement à la fonction glTexParameterf, cette fonction glTexEnv s'applique à l'ensemble des textures.
Essayez les différents modes d'application de texture en ajoutant l'appel à la fonction par exemple après glBindTexture :
' Mode d'application de la texture
glTexEnvi GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE
Avec le mode GL_REPLACE, on obtient la texture initiale sans coloration supplémentaire.
Par contre on n'a plus d'éclairage.
Pour éclairer la texture sans la colorer, il suffit de colorer les faces en blanc et de laisser le mode GL_MODULATE par défaut.
XIV-B-2. Répétition de la texture▲
Telle que nous l'avons définie, la texture est redimensionnée pour occuper toute la face.
On souhaite répéter par exemple cinq fois la texture sur chaque face.
Ainsi on peut couvrir une grande surface avec une petite texture.
Il suffit de modifier les coordonnées de texture en leur donnant une valeur égale à 5.
Modifiez la valeur de la constante cT :
Const
cT As
Long
=
5
La texture est alors répétée cinq fois sur chaque face.
Si on ne souhaite pas répéter la texture, il faut changer les paramètres GL_TEXTURE_WRAP_S (horizontal) et GL_TEXTURE_WRAP_T (vertical).
Par défaut leur valeur est GL_REPEAT.
La valeur GL_CLAMP demande de borner les valeurs entre 0 et 1.
En ajoutant :
' Pas de répétition de texture complète
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP
On obtient :
Retirez les deux dernières lignes ajoutées, on va conserver le mode de répétition GL_REPEAT (par défaut).
XIV-C. Application d'une texture sur une sphère▲
Pour appliquer une texture sur la sphère, nous n'allons pas définir les coordonnées de textures pour chaque vertice.
Ce serait compliqué et glu va nous faciliter le travail.
Voici l'image de la texture que nous allons appliquer :
Cette image provient de Visible Earth.
Elle a été redimensionnée à 256*128 pixels.
Ajoutez une variable pour stocker l'identifiant de la texture.
' Identifiant de la texture de la sphère
Private
gTextureSphere As
Long
Puis charger la texture dans la fonction d'initialisation :
gTextureSphere =
TextureAddFromFile
(
CurrentProject.Path
&
"\terre.jpg"
)
Ensuite lors du dessin de la sphère avec gluSphere il faut :
- affecter la texture avec glBindTexture ;
- préciser le mode de filtrage avec glTexParameter ;
- activer les textures avec gluQuadricTexture.
Nous utilisons le même code que celui qui a servi à dessiner la première sphère.
Mais on modifie la couleur de la sphère : on remplace la couleur jaune par une couleur blanche qui n'affectera pas la texture.
Et pour mieux la voir, on augmente sa taille à 1 au lieu de 0.5
Voici le code de dessin de la sphère avec texture, c'est une deuxième sphère qu'on dessine à l'opposé de la première :
' Dessine une sphère à l'opposé de la lampe
#If VBA7 Then
Dim
lQuad2 As
LongPtr
#Else
Dim
lQuad2 As
Long
#End If
glPushMatrix
glColor3VB vbWhite
glTranslated -
3
*
Cos
(
gLightRotate), 0
, -
3
*
Sin
(
gLightRotate)
glBindTexture GL_TEXTURE_2D, gTextureSphere
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
lQuad2 =
gluNewQuadric
gluQuadricTexture lQuad2, GL_TRUE
gluSphere lQuad2, 1
, 20
, 15
gluDeleteQuadric lQuad2
glPopMatrix
Et voici notre sphère texturée :
On remarque que la texture n'a pas été placée à partir du haut de la sphère.
La France se retrouve en bas de la sphère, les deux pôles face à nous et derrière.
On va donc tourner la sphère de 90° autour de l'axe X.
glRotated -
90
, 1
, 0
, 0
Attention, les transformations s'appliquent à l'envers.
C'est-à-dire que si on souhaite tourner la sphère puis la déplacer, il faut d'abord définir le déplacement puis la rotation.
La rotation s'effectue par rapport à l'origine, il faut que la sphère soit centrée sur l'origine pour la tourner autour de son centre.
La ligne précédente est donc à insérer après le déplacement de la sphère avec glTranslated.
Maintenant la France est placée là où on l'attend, et les deux pôles en haut et en bas.
XIV-D. Le mipmapping▲
Un petit mot sur le mipmapping
Le mipmapping est une technique utilisée pour choisir la texture appropriée en fonction de la taille de l'objet.
Pour un objet lointain, on peut se contenter d'une petite texture basse définition.
Et pour un objet proche on souhaite utiliser une texture de meilleure définition.
Lorsqu'on génère une texture avec glTexImage2D, on peut utiliser le deuxième paramètre level pour préciser le niveau de la texture.
La fonction glu gluBuild2DMipmaps permet de générer des images de textures à différentes dimensions.
Pour utiliser ensuite ces textures mipmaps, il faut le préciser dans le filtre de texture.
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param avec comme valeur de param :
- GL_NEAREST_MIPMAP_NEAREST et GL_LINEAR_MIPMAP_NEAREST pour choisir la texture mipmap la plus appropriée ;
- GL_NEAREST_MIPMAP_LINEAR et GL_LINEAR_MIPMAP_LINEAR pour mélanger les deux textures mipmap les plus appropriées.
Le MipMapping peut résoudre certains problèmes de scintillement des textures.