Application de texture en OpenGL
Introduction Jusqu’à maintenant, les objets ont été affichés en utilisant une couleur ou un dégradé entre les couleurs des sommets. En appliquant une texture, vous collez une image sur un polygone que vous avez pu obtenir en scannant une photographie. L’application de texture est un sujet très vaste et complexe : les textures peuvent être exprimées en une, deux ou trois dimensions; on peut appliquer des textures à des surfaces composées de plusieurs polygones ou à des surfaces courbes; on peut prendre en compte le contour des objets; on peut prendre en compte l’environnement dans lequel se trouve un objet pour donner l’impression que les objets brillants réfléchissent cet environnement sur leurs surfaces; on peut appliquer une texture à une surface de plusieurs manières : « peindre » directement la surface, utiliser la texture pour moduler la couleur de la surface, fusionner une couleur de texture et une couleur de surface.
Les textures sont simplement des tableaux rectangulaires de couleurs (R, V, B, A). Ces valeurs d’un tableau de texture sont souvent appelées « texels ». Exemple d’application de texture : contour de l’objet Déformation de l’objet après affichage ce qui entraîne une distorsion de la texture. texture Selon la taille de la texture, celle de l’image à l’écran et la déformation de l’objet, plusieurs texels peuvent correspondre à un emplacement sur l’objet ce qui nous amène à en établir la moyenne, ou encore, les texels peuvent chevaucher plusieurs emplacements sur l’objet, ce qui revient à en calculer une moyenne pondérée.
Étapes nécessaires à l’application d’une texture Construire une texture dans un tableau en mémoire. 0. const int Largeur = 64; const int Hauteur = 64; const int RVBA = 4; static GLubyte echiquier[Largeur][Hauteur][RVBA]; void Construction_de_la_texture() { int i, j, k; for (i = 0; i < Hauteur; i++) for (j = 0; j < Largeur; j++) k = (((i&0x8) == 0) ^ ((j&0x8) == 0)) * 255; echiquier[i][j][0] = (GLubyte) k; echiquier[i][j][1] = (GLubyte) k; echiquier[i][j][2] = (GLubyte) k; echiquier[i][j][3] = (GLubyte) 255; } Appel à « Construction_de_la_texture() » dans la fonction « Initialisation ». 1.
Nommer un objet de texture. 2. Tout entier non signé peut être utilisé comme nom de texture. Pour éviter les réutilisations accidentelles, demandez à glGenTextures() de fournir des noms de texture non encore utilisées. void glGenTextures(GLsizei n, GLuint * Noms_de_texture); Retourne n noms non utilisés pour les objets de texture dans le tableau Noms_de_texture. Les noms retournés dans ce tableau ne sont pas nécessairement des entiers contigus. Exemple : Déclaration au début de l’application : static GLuint Nom_de_texture; // Retourne un numéro de texture non utilisé à l’adresse désignée // par le 2ième paramètre. glGenTextures(1, &Nom_de_texture); Dans la fonction « Initialisation »,
Note : Ces noms de texture sont marqués comme utilisés mais ils n’acquièrent un état de texture et une dimension (1D, 2D ou 3D) uniquement à l’occasion du 1er chargement. Zéro est un nom de texture réservé et n’est jamais retourné par glGenTextures() comme nom de texture. On peut déterminer si un nom de texture est déjà utilisé : GLboolean glIsTexture(GLuint Nom_de_texture); Retourne GL_TRUE si Nom_de_texture est le nom d’une texture qui a été chargée et qui n’a pas été ultérieurement supprimée. Retourne GL_FALSE si Nom_de_texture est 0 ou si Nom_de_texture est différent d’un nom de texture existant. La primitive retourne GL_FALSE si Nom_de_texture a été retourné par glGenTextures() mais n’est pas encore chargé (par au moins un appel de glBindTexture() avec ce nom).
Créer et utiliser les objets de texture. 3. Pour créer et utiliser les objets de texture, on emploie la routine : glBindTexture(GLenum cible, GLuint Nom_de_texture); Lorsque vous utilisez un entier non signé (Nom_de_texture) pour la 1ière fois, un nouvel objet de texture est créé selon la dimension spécifiée par cible (GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D) et se voit assigner ce nom. Cet objet est généré à partir des valeurs par défaut de l’image et des propriétés de la texture. Les prochains appels à glTexImage2D(), glTexSubImage2D(), glCopyTexImage2D(), glCopyTexSubImage2D() et glTexParameter*() stockent les données dans l’objet de texture. En réutilisant un entier, vous chargez un objet de texture existant, il devient actif et ses données représentent l’état de la texture active. Autrement dit, l’état de la texture précédemment chargée est remplacé par le nouveau. Exemple : // Permet de créer un nouvel objet de texture 2D et de lui assigner // un numéro de texture déjà alloué ou bien de charger un objet de // texture existant. glBindTexture(GL_TEXTURE_2D, Nom_de_texture);
Choix de filtres en l’absence de correspondance exacte entre les texels et les pixels. 4. Indique comment la texture doit être répétée et comment les couleurs doivent être filtrées dans le cas où il n'existe pas de correspondance exacte entre les texels de la texture et les pixels à l'écran. void glTexParameter{if}( GLenum cible, GLenum nom_du_parametre, TYPE valeur_du_parametre); void glTexParameter{if}v(GLenum cible, TYPE * valeur_du_parametre); Le 1er paramètre est GL_TEXTURE_1D, GL_TEXTURE_2D ou GL_TEXTURE_3D pour indiquer une texture 1D, 2D ou 3D. Les valeurs des 2 autres paramètres apparaissent dans le tableau de la diapositive suivante.
Exemple : glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
Spécifier la texture associée à un objet. 5. Permet de spécifier les propriétés de l'image de texture comme, par exemple, la taille, le type et l'emplacement. void glTexImage2D ( GLenum cible, // 2 valeurs constantes possibles : // GL_TEXTURE_2D ou // GL_PROXY_TEXTURE_2D // détermine si les ressources sont suffisantes pour // supporter une texture donnée. GLint niveau, // 0 en présence d’une seule résolution. On peut aussi considérer // plusieurs niveaux de résolution de la texture pour éviter les effets // visuels désagréables lorsque les objets texturés sont visionnés à // des distances différentes du point de vue. GLint f_interne, // Format interne à sélectionner pour chaque texel. Ce format // combiné à une fonction de texture détermine le mode // d’application des textures. 38 constantes symboliques et les // entiers entre 1 et 4 décrivent la variété de possibilités. GLsizei Largeur, // Fournit les dimensions de l’image de texture sous la forme GLsizei Hauteur, // (2m+2b)x(2m+2b) où m est un entier non négatif et b la bordure. // Dimension minimale : 64 x 64 ou 66 x 66 avec les bordures.
// Largeur de la bordure : // 0 sans bordure, // 1 avec bordure GLint Bordure, // Largeur de la bordure : // 0 sans bordure, // 1 avec bordure // (voir plus loin). GLenum format, // Décrit le format et // le type des données // de l’image de texture. GLenum type, const GLvoid * texels); // Décrit la texture et // sa bordure i.e. // héberge les données // de l’image de texture. ou à un type de données compacté.
Exemple : glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, Largeur, Hauteur, 0, GL_RGBA, GL_UNSIGNED_BYTE, echiquier); Activez le mode d’application de la texture. 6. Il vous faut activer la texture avant d’afficher la scène, en utilisant la primitive glEnable() à laquelle vous associez la constante symbolique GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D ou GL_TEXTURE_CUBE_MAP. Exemple : // Permet d'activer le mode d'application de texture 2D dans la fonction // « Affichage ». glEnable(GL_TEXTURE_2D);
Indiquez le mode d’application de la texture à chaque pixel. 7. Jusqu’à maintenant, les valeurs de texture ont été utilisées directement en tant que couleurs à appliquer à la surface à restituer. Il est également possible de faire appel aux valeurs associées aux textures pour moduler la couleur dans laquelle la surface serait restituée en l’absence de texture. Il existe un choix très vaste de fonctions de texture définies à l’aide de glTexEnv : void glTexEnv{if}(GLenum cible, GLenum nom, TYPE parametre); void glTexEnv{if}v(GLenum cible, GLenum nom, TYPE * parametre); Intégration d’un modèle de texture à un modèle de rendu Exemple I : Pour déterminer de quelle façon les couleurs de la texture sont intégrées dans le modèle de rendu, l'approche la plus simple est considérée qui consiste à initialiser l’intensité lumineuse à la valeur de la texture. Aucun autre calcul n'est nécessaire. glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Exemple II : Sachant que la couleur d’un objet correspond à la couleur de la composante de lumière diffuse lorsque la surface est éclairée par de la lumière blanche, l’objet apparaît peint à partir de la texture choisie. I = element_de_texture(s, t) [ka La + kd cos Ld] + ks Ls cos, pour des valeurs appropriées de s et t. Puisque la couleur de la composante spéculaire correspond à la couleur de la source lumineuse, la texture est indépendante de la composante spéculaire. Opengl permet aussi d’opter pour ce type de modèle de texture : glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
Affichez la scène en spécifiant les coordonnées géométriques des objets et les coordonnées de texture correspondantes. 8. Les coordonnées de texture déterminent le texel de la texture qui sera assigné à un sommet. Comme pour l’interpolation de couleurs entre 2 sommets de polygones, les coordonnées de texture sont interpolées entre les sommets. Les coordonnées de texture peuvent disposer de 1, 2, 3 ou 4 coordonnées (s, t, r, q) comme suit : textures 1D : s textures 2D : s, t textures 3D : s, t, r. La coordonnée q permet de créer des coordonnées homogènes. Les valeurs des coordonnées de texture s’étendent généralement de 0 à 1. La commande de déclaration des coordonnées de texture, glTexCoord*(), est comparable à glVertex*(), glColor*() et glNormal*(). Elle est utilisée à l’intérieur d’une paire glBegin() et glEnd().
void glTexCoord{1 2 3 4}{sifd}(TYPE coordonnees); void glTexCoord{1 2 3 4}{sifd}v(TYPE * coordonnees); Positionne les coordonnées de texture actives (s, t, r, q). Lors des prochaines invocations de glVertex*(), ces sommets récupéreront ces coordonnées actives. Avec glTexCoord1*(), la coordonnée s est positionnée à la valeur spécifiée, t et r sont positionnées à 0 et q à 1. Quant à glTexCoord2*(), elle permet de spécifier s et t; r et q sont positionnées resp. à 0 et 1. Avec glTexCoord3*(), q est positionnée à 1 et les autres coordonnées sont définies comme spécifié. La commande glTexCoord4*(), permet de spécifier toutes les coordonnées. Employez le suffixe approprié (s, i, f ou d) et la valeur correspondante pour TYPE (GLshort, GLint, GLfloat ou GLdouble) pour déclarer le type de données des coordonnées. Les coordonnées de texture sont multipliées par la matrice de texturage 4 x 4 avant toute application.
Exemple : Application d’une texture à des surfaces planes. glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0); glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0); glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421); glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421); glEnd(); Note I : Si la surface et la texture ont des formes différentes, des distorsions peuvent survenir. Note II : Si les surfaces ne sont pas planes, on peut définir la normale associée à chaque sommet avant sa définition.
Exemple I de programme élémentaire au complet Construction d’une texture sous forme d’échiquier et application de la texture à 2 carrés. // Tiré de Mason Woo, Jackie Neider, Tom Davis et Dave Shreiner, // OpenGL 2.0 Le guide officiel pour l'apprentissage et // la maîtrise d'OpenGL 2.0.CAMPUSPRESS, 2006. #include <windows.h> #include <GL/glut.h> #include <GL/glaux.h> const int Largeur = 64; const int Hauteur = 64; const int RVBA = 4; static GLubyte echiquier[Largeur][Hauteur][RVBA]; static GLuint Nom_de_texture;
void Construction_de_la_texture() { // Construction d'un échiquier. int i,j, k; for (i = 0; i < Hauteur; i++) for (j = 0; j < Largeur; j++) k = (((i&0x8) == 0) ^ ((j&0x8) == 0)) * 255; echiquier[i][j][0] = (GLubyte) k; echiquier[i][j][1] = (GLubyte) k; echiquier[i][j][2] = (GLubyte) k; echiquier[i][j][3] = (GLubyte) 255; }
void Initialisation(void) { // Permet d'initialiser la couleur de fond RVB. glClearColor(0.0, 0.0, 0.0, 0.0); // Permet d'obtenir un modèle de rendu constant. glShadeModel(GL_FLAT); // Donne accès à un tableau de distances // lors de l'élimination des parties cachées. glEnable(GL_DEPTH_TEST); Construction_de_la_texture(); // Retourne un numéro de texture non utilisé // à l'adresse désignée par le 2ième paramètre. glGenTextures(1, &Nom_de_texture); // Permet de créer un nouvel objet de texture 2D et // de lui assigner ce numéro. glBindTexture(GL_TEXTURE_2D, Nom_de_texture);
// Indique comment la texture doit être répétée et comment // les couleurs doivent être filtrées dans le cas où il // n'existe pas de correspondance exacte entre les texels // de la texture et les pixels à l'écran. // glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, // Permet de spécifier les propriétés de l'image de texture // comme, par exemple, la taille, le type et l'emplacement. glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, Largeur, Hauteur, 0, GL_RGBA, GL_UNSIGNED_BYTE, echiquier); }
void affichage( void ) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Permet d'activer le mode d'application de texture 2D. glEnable(GL_TEXTURE_2D); // Pour déterminer de quelle façon les couleurs de la texture // sont intégrées dans le modèle de rendu, l'approche la plus // simple est considérée; elle consiste à initialiser l’intensité // lumineuse à la valeur de la texture. // Aucun autre calcul n'est nécessaire. glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // Permet de rendre actif un objet de texture. glBindTexture(GL_TEXTURE_2D, Nom_de_texture);
// 2 polygones sont dessinés. Les coordonnées de texture sont // positionnées aux coordonnées des sommets. glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0); glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0); glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421); glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421); glEnd(); glFlush(); glDisable(GL_TEXTURE_2D); }
Utilisation de la mémoire tampon comme source des données de texture. À la place de glTexImage2D, glCopyTexImage2D() lit un rectangle de pixels dans la mémoire tampon et utilise ce rectangle comme un ensemble de texels pour composer une nouvelle texture. void glCopyTexImage2D ( GLenum cible, // Le 1er paramètre doit être positionné à GL_TEXTURE_2D. GLint niveau, // Idem à glTexImage2D. GLint f_interne, // Idem à glTexImage2D. GLint x, // Coordonnées du sommet inférieur gauche du rectangle de pixels GLint y, // aligné sur l’écran. GLsizei Largeur, // Indique la taille de ce rectangle de pixels dont la forme coïncide GLsizei Hauteur, // avec celle de glTexImage2D. GLint Bordure // Largeur de la bordure. );
Proxy de texture La taille des textures est à prendre en compte. OpenGL offre des outils permettant d’évaluer si votre implémentation OpenGL est capable de supporter un format de texture donné à une taille de texture donnée. GLint * glGetIntegerv(GL_MAX_TEXTURE_SIZE, parametre); Retourne la taille de la plus grande texture carrée supportée. Cela ne tient pas compte du format interne de chaque texel. Pour les textures 3D, on utilise plutôt GL_MAX_3D_TEXTURE_SIZE. glTexImage2D( GL_PROXY_TEXTURE_2D, niveau, f_interne, Largeur, Hauteur, Bordure, format, type, NULL); Permet de savoir si les ressources sont suffisantes pour une texture 2D standard.
void glGetTexLevelParameter{if}v( GLenum cible, GLint niveau, GLenum nom_variable_d_etat, TYPE * parametre); Permet de savoir si les ressources suffisent pour héberger votre texture. Si elles sont insuffisantes p/r à une variable d’état (largeur, hauteur de la texture, largeur de bordure, …), la valeur 0 est retournée. Exemple : GLint Largeur; glTexImage2D( GL_PROXY_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &Largeur);
Remplacer en tout ou en partie une texture Il est souvent préférable de remplacer en tout ou en partie une image de texture par de nouvelles données, plutôt que d’en créer une nouvelle. void glTexSubImage2D( GLenum cible, // GL_TEXTURE_2D est utilisé. GLint niveau, // voir glTexImage2D(). GLint decalage_x,// Position relative des texels p/r à (0, 0) GLint decalage_y,// représentant le coin inférieur gauche // de la texture. GLsizei Largeur, // Dimensions de la région destinée à GLsizei Hauteur, // remplacer en tout ou en partie la // texture active. GLenum format, // voir glTexImage2D(). GLenum type, // voir glTexImage2D(). const GLvoid * texels); // Accueille les données de la // sous-image de texture. Définit une texture 2D qui remplace en tout ou en partie une région à l’intérieur de la texture active 2D. Note : La mémoire tampon peut faire office de source de données; glTexSubImage2D peut être remplacée par glCopyTexSubImage2D() qui lit un rectangle de pixels dans la mémoire tampon et modifie une portion de la texture existante.
Exemple : Modification de la texture précédente. // Tiré de Mason Woo, Jackie Neider, Tom Davis et Dave Shreiner, // OpenGL 2.0 Le guide officiel pour l'apprentissage et // la maîtrise d'OpenGL 2.0.CAMPUSPRESS, 2006. #include <windows.h> #include <GL/glut.h> #include <GL/glaux.h> const int Largeur_Image = 64; const int Hauteur_Image = 64; const int Largeur_Sous_Image = 16; const int Hauteur_Sous_Image = 16; const int RVBA = 4; static GLubyte echiquier[Largeur_Image][Hauteur_Image][RVBA]; static GLubyte Sous_image[Largeur_Sous_Image][Hauteur_Sous_Image][RVBA]; static GLuint Nom_de_texture;
void Construction_des_textures() { // Construction d'un échiquier. int i, j, k; for (i = 0; i < Hauteur_Image; i++) for (j = 0; j < Largeur_Image; j++) { k = (((i&0x8)==0) ^ ((j&0x8)==0)) * 255; echiquier[i][j][0] = (GLubyte) k; echiquier[i][j][1] = (GLubyte) k; echiquier[i][j][2] = (GLubyte) k; echiquier[i][j][3] = (GLubyte) 255; } // Construction d'un échiquier réduit. for (i = 0; i < Hauteur_Sous_Image; i++) for (j = 0; j < Largeur_Sous_Image; j++) { k = (((i&0x4)==0) ^ ((j&0x4)==0)) * 255; Sous_image[i][j][0] = (GLubyte) k; Sous_image[i][j][1] = (GLubyte) 0; Sous_image[i][j][2] = (GLubyte) 0; Sous_image[i][j][3] = (GLubyte) 255;
void clavier(unsigned char cle, int x, int y) { switch(cle) case 's': case 'S': glBindTexture(GL_TEXTURE_2D, Nom_de_texture); glTexSubImage2D(GL_TEXTURE_2D, 0, 20, 32, Largeur_Sous_Image, Hauteur_Sous_Image, GL_RGBA, GL_UNSIGNED_BYTE, Sous_image); glutPostRedisplay(); break; case 'r': case 'R': glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Largeur_Image, Hauteur_Image, 0, GL_RGBA, GL_UNSIGNED_BYTE, echiquier); default: break; } Note : Les autres fonctions demeurent inchangées ou presque.
Exemple : Chargement de plusieurs textures. // Tiré de Mason Woo, Jackie Neider, Tom Davis et Dave Shreiner, // OpenGL 2.0 Le guide officiel pour l'apprentissage et // la maîtrise d'OpenGL 2.0.CAMPUSPRESS, 2006. #include <windows.h> #include <GL/glut.h> #include <GL/glaux.h> const int Largeur = 64; const int Hauteur = 64; const int RVBA = 4; static GLubyte Premiere_image[Largeur][Hauteur][RVBA]; static GLubyte Deuxieme_image[Largeur][Hauteur][RVBA]; static GLuint Nom_de_texture[2];
void Construction_de_textures() { int i, j, k; for (i = 0; i < Hauteur; i++) for (j = 0; j < Largeur; j++) k = (((i&0x8)==0) ^ ((j&0x8)==0)) * 255; Premiere_image[i][j][0] = (GLubyte) k; Premiere_image[i][j][1] = (GLubyte) k; Premiere_image[i][j][2] = (GLubyte) k; Premiere_image[i][j][3] = (GLubyte) 255; k = (((i&0x10)==0) ^ ((j&0x10)==0)) * 255; Deuxieme_image[i][j][0] = (GLubyte) k; Deuxieme_image[i][j][1] = (GLubyte) 0; Deuxieme_image[i][j][2] = (GLubyte) 0; Deuxieme_image[i][j][3] = (GLubyte) 255; }
void Initialisation(void) { // Permet d'initialiser la couleur de fond RVB. glClearColor(0.0, 0.0, 0.0, 0.0); // Permet d'obtenir un modèle de rendu constant. glShadeModel(GL_FLAT); // Donne accès à un tableau de distances // lors de l'élimination des parties cachées. glEnable(GL_DEPTH_TEST); Construction_de_textures(); // Retourne un numéro de texture non utilisé // à l'adresse désignée par le 2ième paramètre. glGenTextures(2, Nom_de_texture); // Permet de créer un nouvel objet de texture 2D et // de lui assigner ce numéro. glBindTexture(GL_TEXTURE_2D, Nom_de_texture[0]);
// dans le cas où il n'existe pas de correspondance exacte entre les // Indique comment la texture doit être répétée et les couleurs filtrées // dans le cas où il n'existe pas de correspondance exacte entre les // texels de la texture et les pixels à l'écran. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Permet de spécifier les propriétés de l'image de texture comme, // par exemple, la taille, le type et l'emplacement. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Largeur, Hauteur, 0, GL_RGBA, GL_UNSIGNED_BYTE, Premiere_image); glBindTexture(GL_TEXTURE_2D, Nom_de_texture[1]); 0, GL_RGBA, GL_UNSIGNED_BYTE, Deuxieme_image); }
void affichage( void ) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Permet d'activer le mode d'application de texture 2D. glEnable(GL_TEXTURE_2D); // Pour déterminer de quelle façon les couleurs de la texture sont // intégrées dans le modèle de rendu, l'approche la plus simple est // considérée; elle consiste à initialiser l’intensité lumineuse à la // valeur de la texture. Aucun autre calcul est nécessaire. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // Permet de rendre actif un objet de texture. glBindTexture(GL_TEXTURE_2D, Nom_de_texture[0]);
// 2 polygones sont dessinés. Les coordonnées de texture sont // positionnées aux coordonnées des sommets. glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0); glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0); glEnd(); glBindTexture(GL_TEXTURE_2D, Nom_de_texture[1]); glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421); glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421); glFlush(); glDisable(GL_TEXTURE_2D); }
Textures à une dimension Dans certaines situations, les textures 1D sont suffisantes. Ex. : Dessin de bandes texturées dont toutes les variations s’effectuent dans une seule direction. Les textures 1D se comportent comme une texture 2D avec une hauteur égale à 1 et une absence de bordures en haut et en bas. void glTexImage1D ( GLenum cible, GLint niveau, GLint f_interne, GLsizei Largeur, // 2m ou (2m+2 en présence d’une bordure) où m est un // entier non négatif. GLint Bordure, GLenum format, GLenum type, const GLvoid * texels // texels est un tableau 1D. ); Tous les autres paramètres ont la même signification que glTexImage2D.
Note : Toutes les routines de définition de texture 2D et de sous-texture 2D possèdent leurs « homologues » 1D : glCopyTexSubImage1D() Exemple de texture 1D : #include <windows.h> #include <GL/glut.h> #include <GL/glaux.h> const int Largeur = 64; const int Hauteur = 64; const int RVBA = 4; static GLubyte Premiere_image[Largeur][Hauteur][RVBA]; static GLubyte Deuxieme_image[Largeur][RVBA]; static GLuint Nom_de_texture[2];
void Construction_de_textures() { int i, j, k; for (i = 0; i < Hauteur; i++) for (j = 0; j < Largeur; j++) k = (((i&0x8)==0) ^ ((j&0x8)==0)) * 255; Premiere_image[i][j][0] = (GLubyte) k; Premiere_image[i][j][1] = (GLubyte) k; Premiere_image[i][j][2] = (GLubyte) k; Premiere_image[i][j][3] = (GLubyte) 255; } k = ((i&0x8)==0) * 255; Deuxieme_image[i][0] = (GLubyte) k; Deuxieme_image[i][1] = (GLubyte) 0; Deuxieme_image[i][2] = (GLubyte) 0; Deuxieme_image[i][3] = (GLubyte) 255;
void Initialisation(void) { // Permet d'initialiser la couleur de fond RVB. glClearColor(0.0, 0.0, 0.0, 0.0); // Permet d'obtenir un modèle de rendu constant. glShadeModel(GL_FLAT); // Donne accès à un tableau de distances // lors de l'élimination des parties cachées. glEnable(GL_DEPTH_TEST); Construction_de_textures(); // Retourne un numéro de texture non utilisé // à l'adresse désignée par le 2 ième paramètre. glGenTextures(2, Nom_de_texture);
// Permet de créer un nouvel objet de texture 2D et // de lui assigner ce numéro. glBindTexture(GL_TEXTURE_2D, Nom_de_texture[0]); // Indique comment la texture doit être répétée et les couleurs doivent // être filtrées dans le cas où il n’existe pas de correspondance // exacte entre les texels de la texture et les pixels à l'écran. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Permet de spécifier les propriétés de l'image de texture // comme, par exemple, la taille, le type et l'emplacement. glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, Largeur, Hauteur, 0, GL_RGBA, GL_UNSIGNED_BYTE, Premiere_image);
// Permet de créer un nouvel objet de texture 1D et de lui assigner ce // numéro. glBindTexture(GL_TEXTURE_1D, Nom_de_texture[1]); // Indique comment la texture doit être répétée et les couleurs doivent // être filtrées dans le cas où il n’existe pas de correspondance exacte // entre les texels de la texture et les pixels à l'écran. // glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Permet de spécifier les propriétés de l'image de texture comme, // par exemple, la taille, le type et l'emplacement. glTexImage1D( GL_TEXTURE_1D, 0, GL_RGBA, Largeur, 0, GL_RGBA, GL_UNSIGNED_BYTE, Deuxieme_image); }
void affichage( void ) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Permet d'activer le mode d'application de texture 2D. glEnable(GL_TEXTURE_2D); // Pour déterminer de quelle façon les couleurs de la texture sont // intégrées dans le modèle de rendu, l'approche la plus simple est // considérée; elle consiste à initialiser l'intensité lumineuse à la // valeur de la texture. Aucun autre calcul est nécessaire. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // Permet de rendre actif un objet de texture. glBindTexture(GL_TEXTURE_2D, Nom_de_texture[0]); // 2 polygones sont dessinés. Les coordonnées de texture sont // positionnées aux coordonnées des sommets.
glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0); glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0); glEnd(); glDisable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_1D); glBindTexture(GL_TEXTURE_1D, Nom_de_texture[1]); glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421); glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421); glFlush(); glDisable(GL_TEXTURE_1D); }
Textures tridimensionnelles Images de textures compressées Bordures de textures Niveaux de détail multiples Filtrage Textures résidentes et suppression de textures Etc.