Textures

       Jusqu’ici, les surfaces étaient simplement coloriées, ce qui ne permet pas d’avoir des rendus très réalistes. Les textures améliore considérablement le rendu. Le principe est de remplir une surface avec une image bitmap correspondant à une photo de la surface.

1.   Principe général

       Un texture est appliquée à une surface de la manière suivante :

·        d’abord il faut indiquer quelle image il va falloir appliquer (ce qui revient à donner un pointeur vers l’image).
·        ensuite, avant d’entrer chaque point (vertex) de la surface, il faut préciser où se situe ce point dans la texture, c’est le même principe qu’avant avec glColor. Cela revient en quelque sorte à mettre des épingles sur la texture

       OpenGL se charge ensuite d’appliquer la texture, en faisant correspondre les vertex avec les « épingles ».

2.   En OpenGL

       Dans ce cours, les routines de chargement d’images en mémoire ne seront pas expliquées. Ce dont à besoin OpenGL, c’est d’une image non compressée chargée sous la forme d’un tableau en mémoire. Il existe de nombreuses routines toutes faites pour charger les principaux formats d’images (BMP, PCX, GIF, PNG…).

2.1.               Spécifier l’image

       Pour spécifier la texture à utiliser, appeler :

void glTexImage2D( GLenum target, GLint level, GLint components, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels )
Avec :

Target

GL_TEXTUTE_2D

Level

Indique le niveau de mipmapping, expliqué plus loin dans ce cours

Components

Nombre de composantes dans la texture (1, 2, 3 ou 4). Généralement 3 (pour RGB) ou 4 (pour RGBA).

Width

Largeur de l’image. Doit être 2n + 2 (dépend de bordure).

Height

Hauteur de l’image. Doit être 2m + 2 (dépend de bordure).

Bordure

Indique la largeur de la bordure : 0 ou 1

Format

Codage des couleurs : GL_COLOR_INDEX, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB,          GL_RGBA, GL_LUMINANCE,        ou GL_LUMINANCE_ALPHA

Type

Type du tableau : GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, ou GL_FLOAT

Pixel

Pointeur vers l’image.

 

2.2.               Les « épingles »

            La première chose à faire, c’est d’activer les textures :

glEnable(GL_TEXTURE_2D) ;

            Pour poser une épingle, avant un vertex il faut appeler :

void glTexCoord2f( GLfloat s, GLfloat t )

            ou l’une de ses variantes.
            Les coordonnées (s, t) indiquent la correspondance entre le prochain vertex entré et la texture. En OpenGL, le repère d’une texture fait toujours [0..1] sur [0..1], mais s et t peuvent sortir des ces intervalles, l’effet dépend alors du paramètrage choisi.

  • Lorsque s et t sont compris entre 0 et 1, OpenGL va positionner les épingles directement sur la texture. Vous pourrez ainsi utiliser seulement une petite partie de celle-ci. Si la surface sur laquelle vous posez la texture est trés grande, il va étirer la texture pour la placer sur votre surface.
  • A l'inverse, si t et s (ou seulement un seul) sont supérieurs à 1, la texture va être répétée.

La texture appliquée sur la base du temple est répétée plusieurs fois.
La base a une longueur de 40 unités sur 4. Les valeurs de s et t sont respectivement 2 et 20
(les valeurs suivantes sont généralement intéressantes : s = 1/2 * largeur et t = 1/2 * hauteur)

2.3.               Paramétrage

2.3.1.                Application de la texture

            Les paramètres d’application d’une texture sont :

Nom

Type

Valeur possibles

Signification

GL_TEXTURE_WRAP_S

Entier

GL_CLAMP, GL_CLAMP_TO_EDGE, GL_REPEAT

Indique ce qui se passe si une coordonnée s sort de l’intervalle [0..1]. Soit la texture est répètée (mosaïque), soit seulement le bord est répété.

GL_TEXTURE_WRAP_T

Entier

Idem

Idem pout t

GL_TEXTURE_MIN_FILTER

Entier

NEAREST, LINEAR, NEAREST_MIPMAP_NEAREST, NEAREST_MIPMAP_LINEAR, LINEAR_MIPMAP_NEAREST, LINEAR_MIPMAP_LINEAR

Indique la qualité de l’agrandissement d’une texture. LINEAR est meilleur que NEAREST, mais plus lent.

GL_TEXTURE_MAG_FILTER

Entier

NEAREST, LINEAR

Idem en réduction


            Il existe d’autres paramètres, mais ceux-ci sont de loin les plus importants. Pour changer un paramètre, il faut appeler :

void glTexParameteri(GLenum target, GLenum pname, GLint param )

            avec target = GL_TEXTURE_2D, pname l’un des noms de paramètres, et param la nouvelle valeur.

2.3.2.                glColor

       La couleur courante (spécifiée par glColor), joue un rôle différent suivant les paramètres passés à :

void glTexEnvi( GLenum target, GLenum pname, Glint param )
 avec target = GL_TEXTURE_ENV, pname = GL_TEXTURE_ENV_MODE, et param = GL_REPLACE, GL_MODULATE, GL_DECAL, ou GL_BLEND.

       Il y a beaucoup de cas suivant le nombre de composantes de la texture. Dans le cas de 3 ou 4 composantes (RGB ou RGBA), les modes les plus courants sont :

·        GL_REPLACE, la couleur courante n’intervient pas

·        GL_MODULATE, la couleur courante multiplie la texture. Il est alors possible de changer très facilement l’intensité d’une texture, en dessinant d'abord la surface en blanc, par exemple, lequel va être atténué selon la position de la lumière, puis en plaquant la texture. L'intensité de cette dernière va varier selon l'éclairage...


Ici, c'est plutôt sombre

Mais, en changeant la position de la lumière,
cela devient beaucoup plus clair

3.   Exemple

            Voici un cube texturé. Pour simplifier (et garantir la portabilité), le format d’image est ici le « Raw », c’est-à-dire l’image seule. Paint Shop Pro gère très bien ce format. Le problème est que la taille de l’image n’est pas inclus dans ce fichier. Mon image à une taille de 128*128 et est au format RGB (24 bits = 3 octets).

void init()
{
            GLfloat Blanc[] = {1.0f, 1.0f, 1.0f, 1.0f};
            //Taille = 128 * 128. RGB 3 octets
            char buffer[128*128*3];
            FILE *f = fopen("herbe.raw", "rb");

            if (f)
            {
                                    fread(buffer, 128*128*3, 1, f);
                                    fclose(f);
                                    printf("texture chargée");
                                                //On spécifie qu'elle texture, sa taille, son type ...
                                    glTexImage2D(GL_TEXTURE_2D,0,3, 128, 128, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
                                                //cela définit la façon dont la texture est appliquée. LINEAR est le meilleur, mais le + lent.
                                    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                                    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                                                //On répète la texture si s et t sortent des bornes [0,1]
                                    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
                                    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
                                                //ouf, ca y est !!!
                                    glEnable(GL_TEXTURE_2D);
                        }else printf("Il y a un problème de fichier!!!!\n");

                        cube = glGenLists(1);
                        glNewList(cube, GL_COMPILE);
                                    glBegin(GL_QUADS);
                                                glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blanc);
                                                glNormal3d(0.0,0.0,1.0);
                                                          //on spécifie la position des épingles (on tourne : une seule coordonnée change à la fois)
                                                glTexCoord2d(0,0);
                                                glVertex3d(-1, 1, 1);
                                                glTexCoord2d(0,1);
                                                glVertex3d(-1, -1, 1);
                                                glTexCoord2d(1,1);
                                                glVertex3d( 1, -1, 1);
                                                glTexCoord2d(1,0);
                                                glVertex3d( 1, 1, 1);
                                                glNormal3d(-1.0,0.0,0.0);
                                                //idem glTexCoord2d(0,0);
                                                glVertex3d( -1, 1, 1);
                                                glTexCoord2d(0,1);
                                                glVertex3d( -1, 1, -1);
                                                glTexCoord2d(1,1);
                                               glVertex3d( -1, -1, -1);
                                                glTexCoord2d(1,0);
                                                glVertex3d( -1, -1, 1);
                                                //idem
                                                glNormal3d(1.0,0.0,0.0);
                                                glTexCoord2d(0,0);
                                                glVertex3d( 1, 1, 1);
                                                glTexCoord2d(0,1);
                                                glVertex3d( 1, -1, 1);
                                                glTexCoord2d(1,1);
                                                glVertex3d( 1, -1, -1);
                                                glTexCoord2d(1,0);
                                                glVertex3d( 1, 1, -1);
                                                glNormal3d(0.0,1.0,0.0);
                                                            //idem glTexCoord2d(0,0);
                                                glVertex3d( -1, 1, 1);
                                                glTexCoord2d(0,1);
                                                glVertex3d( 1, 1, 1);
                                                glTexCoord2d(1,1);
                                                glVertex3d( 1, 1, -1);
                                                glTexCoord2d(1,0);
                                                glVertex3d( -1, 1, -1);
                                                glNormal3d(0.0,-1.0,0.0);
                                                            //idem
                                                glTexCoord2d(0,0);
                                                glVertex3d( -1, -1, 1);
                                                glTexCoord2d(0,1);
                                                glVertex3d( -1, -1, -1);
                                                glTexCoord2d(1,1);
                                                glVertex3d( 1, -1, -1);
                                                glTexCoord2d(1,0);
                                                glVertex3d( 1, -1, 1);
                                                glNormal3d(0.0,0.0,-1.0);
                                                            //idem
                                                glTexCoord2d(0,0);
                                                glVertex3d( 1, 1, -1);
                                                glTexCoord2d(1,0);
                                                glVertex3d( 1, -1, -1);
                                                glTexCoord2d(1,1);
                                                glVertex3d( -1, -1, -1);
                                                glTexCoord2d(0,1);
                                                glVertex3d( -1, 1, -1);
                                    glEnd();
                        glEndList();
            }
}

Sources et éxécutable

Autres Formats :
Voici 2 fichiers ZIP contenant les sources de petites librairies qui permettent de charger des fichiers TGA et BMP.
Download TGA.zip
Download BMP.zip

4.   MipMapping

            Le MipMapping consiste à avoir la même texture à plusieurs échelles, de façon à limiter les transferts mémoires lors du plaquage de texture (inutile de transférer une texture 256x256 si l’objet dessiné est très loin dans le décor et ne fait plus que du 5x5).

            En théorie, le programmeur devrait avoir 3 ou 4 fois la même texture, mais avec une résolution différente. Il faut alors entrer toutes les textures à chaque fois, en changeant le paramètre level de glTextImage2D (sachant que 0 est l’image la plus grande, et les suivantes sont ses réductions). Lorsque la texture est appliqué, OpenGL soit choisi l’image de taille la plus proche de la surface à afficher (NEAREST_MIPMAP), soit fait une sorte de moyenne entre l’image de taille juste au dessus et celle juste en dessous (LINEAR_MIPMAP).

            En pratique, il y a une fonction glu :

int gluBuild2DMipmaps(GLenum target, GLint components, GLint width, GLint height, GLenum format, GLenum type, const void *data )

            Les paramètres sont les mêmes que pour glTexImage2D, sauf qu’il est cette fois possible d’utiliser des images de dimensions qui ne sont pas des puissances de 2. L’image passée est celle de meilleure qualité (level = 0).

5.   Chargement dans la carte vidéo

L’intérêt du MipMapping est très limité si les textures ne sont pas stockées dans la carte vidéo.
Le principe est similaire à celui des listes :

void glGenTextures( GLsizei n, GLuint * textures)

            permet de réserver n textures, les numéros sont alors placés dans le tableau pointé par textures. Ensuite le numéro de la texture courante est changé par :

void glBindTexture( GLenum target, GLuint texture)

            avec target = GL_TEXTURE_2D et texture le numéro de la texture à activer. Ensuite toutes les fonctions faisant intervenir une texture utilisent la texture active.

Les textures sont libérées par :
void glDeleteTextures(GLsizei n, const GLuint * textures )

Pour résumer, une texture est le plus souvent chargée par :

glGenTextures(1, &Texture_num);
glBindTexture(GL_TEXTURE_2D, Texture_num);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height(), GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

Ensuite pour activer une texture, avant un glBegin :               

                glBindTexture(GL_TEXTURE_2D, Texture_num);

6.   Priorités des textures

            Comme il se peut que toutes les textures ne rentrent pas dans la carte vidéo, il est possible de donner des priorités au chargement des textures en mémoire vidéo.

void glPrioritizeTextures( GLsizei n, GLuint * textures, GLclampf * priorities)

            avec priorities un tableau de n flottants appartenant à [0..1], 0 étant la priorité la plus faible et 1 la plus forte.

 

Page précédente    Page suivante