Test de mipmapping.

Test de mipmapping.

gluBuild2DMipmaps,glTexParameteri

Voir version :

Dépendances (dans l'archive) :
mur.bmp

Télécharger :

#include <windows.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>

#pragma comment(lib,"sdl.lib")
#pragma comment(lib,"sdlmain.lib")
#pragma comment(lib, "opengl32.lib" )
#pragma comment(lib, "glu32.lib" )

#define XRESOL 800
#define YRESOL 600

int initGL()
{
    // init
    glShadeModel(GL_FLAT);
    glClearColor(0.0f,0.0f,0.0f,0.0f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
    // cadrage
    glViewport(0,0,XRESOL,YRESOL);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f,4.0/3.0,0.1f,100.0f);
    glEnable(GL_TEXTURE_2D);
    return 1;
}

int KeyControl(float* pe)
{
    Uint8* ks = SDL_GetKeyState(NULL);
    SDL_PumpEvents();
    if (ks[SDLK_ESCAPE])
        return 1;
    if (ks[SDLK_UP])
        (*pe)+=0.01f;
    if (ks[SDLK_DOWN])
        (*pe)-=0.01f;
    return 0;
}

int Quad(float x,float y,float z,GLuint texture)
{
    glBindTexture(GL_TEXTURE_2D,texture);
    glBegin(GL_QUADS);               
        glTexCoord2f(0.0,1.0);glVertex3f(x,y,z);
        glTexCoord2f(1.0,1.0);glVertex3f(x+0.99,y,z);
        glTexCoord2f(1.0,0.0);glVertex3f(x+0.99,y+0.99,z);
        glTexCoord2f(0.0,0.0);glVertex3f(x,y+0.99,z);
    glEnd();  
    return 0;
}


GLuint ParametrerTexture(SDL_Surface* tex32,int mipmap,GLint min,GLint max)
{
    GLuint res;
    glGenTextures(1,&res);
    glBindTexture(GL_TEXTURE_2D,res);
    if (mipmap)
        gluBuild2DMipmaps(GL_TEXTURE_2D,4, tex32->w, tex32->h,GL_BGRA_EXT,GL_UNSIGNED_BYTE,tex32->pixels);
    else
        glTexImage2D(GL_TEXTURE_2D,0,GL_RGB, tex32->w, tex32->h,0,GL_BGRA_EXT, GL_UNSIGNED_BYTE, tex32->pixels);
    glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER,min); 
    glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER,max); 
    return res;
}

int InitTextures(GLuint textures[8])
{
    SDL_Surface* tex = SDL_LoadBMP("mur.bmp");
    SDL_Surface* tex32 = SDL_CreateRGBSurface(SDL_SWSURFACE,tex->w,tex->h,32,0,0,0,0);
    SDL_BlitSurface(tex,NULL,tex32,NULL);
    SDL_FreeSurface(tex);
// bord gauche
    textures[0] = ParametrerTexture(tex32,0,GL_NEAREST,GL_NEAREST);
    textures[4] = ParametrerTexture(tex32,1,GL_NEAREST,GL_NEAREST);
// bord droit
    textures[3] = ParametrerTexture(tex32,0,GL_LINEAR,GL_LINEAR);
    textures[7] = ParametrerTexture(tex32,1,GL_LINEAR,GL_LINEAR);
// milieu
    textures[1] = ParametrerTexture(tex32,1,GL_NEAREST_MIPMAP_NEAREST,GL_NEAREST);
    textures[2] = ParametrerTexture(tex32,1,GL_NEAREST_MIPMAP_LINEAR,GL_NEAREST);
    textures[5] = ParametrerTexture(tex32,1,GL_LINEAR_MIPMAP_NEAREST,GL_LINEAR);
    textures[6] = ParametrerTexture(tex32,1,GL_LINEAR_MIPMAP_LINEAR,GL_LINEAR);
    SDL_FreeSurface(tex32);
    return 0;
}

int main(int argc, char **argv)
{
    GLuint textures[8];
    SDL_Surface *surface;
    float e = 0.0f;
    SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE);
    surface = SDL_SetVideoMode(XRESOL,YRESOL,32,SDL_HWSURFACE|SDL_OPENGL);
    initGL();
    InitTextures(textures);
    while(!KeyControl(&e))
    {
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();
        gluLookAt(0,0,5,0,0,4,0,1,0);

        Quad(-2,0,e,textures[0]);
        Quad(-1,0,e,textures[1]);
        Quad(0,0,e,textures[2]);
        Quad(1,0,e,textures[3]);
        Quad(-2,-1,e,textures[4]);
        Quad(-1,-1,e,textures[5]);
        Quad(0,-1,e,textures[6]);
        Quad(1,-1,e,textures[7]);

        SDL_GL_SwapBuffers( );
    }
    SDL_Quit();
    return 0;
}



Commentaires

	Ici, je vais faire des tests de filtrage de texture.

	Je ne vais pas trop parler d'initialisation de texture :
	glEnable(GL_TEXTURE_2D);
	glGenTextures,glBindTexture et glTexCoord2f

	Mais surtout des différents filtrages que j'applique.

	Je crée un tableau de 8 textures :
	GLuint textures[8];

	Je les initialise dans InitTextures, et je les affiche dans un Quad.
	Les flèches permettent de zoomer sur les textures.

	Dans la fonction InitTextures, je charge une image avec SDL, je la convertis en 32 bits, 
	puis je crée 8 texture avec ma fonction ParametrerTexture, à laquelle je vais donner différents paramètres.

	Et c'est la que tout va se jouer.

// Mipmapping

	Il y a deux façons de créer des textures, sans mipmapping (avec glTexImage2D), et avec mipmapping (gluBuild2DMipmaps)

	Le mipmapping, c'est précalculer des images 4 fois plus petites récursivement, qui serviront à faire un meilleur lissage en
	cas de dézoom. Le mipmapping prendra environ 1/3 de mémoire (VRAM) en plus.

	http://en.wikipedia.org/wiki/Mipmap

	L'utilité sera d'afficher une image ou une autre (l'image principale ou une des images plus petites) en fonction de la distance
	de la texture à la caméra.

	Lançons le programme, et regardons tout ça : 
	Il y a 8 carreaux texturés, que nous désigneront selon l'ordre de lecture naturelle.

	Nous allons tout d'abord commencer par voir ce qu'il se passe quand on zoom. Zommez avec les flèches.
	Vous pouvez constater en zoomant à fond que les carreaux d'en haut sont pixelisé tandis que ceux d'en bas sont lissés.

	Dans ma fonction ParametrerTexture, c'est le dernier paramètre qui détermine le type de zoom.
	Deux valeurs possibles :
	
	GL_NEAREST : pixelisation
	GL_LINEAR  : lissage (interpolation bilinéaire)

	Maintenant, voyons ce qu'il se passe si on dézoom : et la, c'est l'avant dernier paramètre qui jouera.
	Dézoomez à fond, et constatez : 
	
	- d'abord, ça scintille immédiatement sur les surfaces 1 et 5 (celles de gauche)

	Leur point commun est GL_NEAREST pour le min : le scintillement est immédiat.
	Leur différence, l'une est avec et l'autre sans mipmapping. Cependant, dans la mesure ou on n'utilise pas d'options de mipmapping,
	ce sera la même chose.

	Si vous continuez à dézoomer, vous verrez qu'au bout d'un moment, le rendu des surfaces 4 et 8 (de droite) va devenir crado.
	Si vous continuez à dézoomer à fond, les traits blancs de la brique vont "clignotter"

	Les paramètres des surfaces de droite sont GL_LINEAR : dans les deux cas, on fait un lissage bilinéaire, mais en s'appuyant sur la texture
	principale : la grande texture de base, l'image de 512*512. Et donc ce sont des erreurs d'arrondis qui font cet effet, du fait que la 
	texture affichée est beaucoup beaucoup plus petite que l'image d'origine.

	Tout ça, c'est sans se servir du mipapping. Même si les surfaces du bas (5 et 8) ont été créées avec le mipmapping, les options 
	de zoom GL_NEAREST et GL_LINEAR font qu'on ne s'en sert pas.

	Voyons maintenant le carré central ou on s'en sert :

	Zoomez, et dézoomez progressivement, vous allez voir un moment une cassure sur les carrés 2 et 6. (gauche milieu).
	ça va "devenir flou" d'un seul coup.

	Les paramètres utilisés sont :

	GL_NEAREST_MIPMAP_NEAREST et GL_LINEAR_MIPMAP_NEAREST

	C'est le NEAREST de la fin qu'ils ont en commun, il veut dire "utilise la mipmap la plus proche en fonction de l'éloignement), donc 
	il y a une cassure, un seuil au dela duquel on utilise une mipmap ou une autre. (une image, ou une plus petite)

	Leur différence est le NEAREST ou LINEAR (après le GL)

	Cela veut dire qu'une fois qu'on a choisi le MIPMAP, soit on prend le pixel le plus proche (cas en haut), soit on fait 
	une interpollation bilinéaire (cas en bas). 
	Outre la cassure, le résultat en bas est plus lisse.

	Voyons maintenant les deux derniers cas, les surfaces 3 et 7 (au milieu à droite).

	Leurs options sont les suivantes :

	GL_NEAREST_MIPMAP_LINEAR et GL_LINEAR_MIPMAP_LINEAR

	Cette fois ci, c'est le LINEAR de la fin qu'ils ont en commun, il veut dire "fait un lissage entre 2 mipmaps" : 
	au lieu d'en choisir brutalement une ou l'autre en fonction de la distance, on choisit les deux les plus proches,
	et on fera une interpollation. 

	De ce fait, il n'y a plus de cassure en zoomant et dézoomant.

	Il y a juste celui d'en haut qui scintille un peu, parce qu'il prendra les pixels les plus proches dans chaque texture.

	Celui d'en bas, lui, interpolle bilinéaire chacune des deux mipmap, puis interpolle en fonction des 2 mipmap les plus proches.

	C'est une interpollation trilinéaire.

	Le gagnant, enfin le plus doux, est bien sur la surface numéro 7 !

Laissez un commentaire / post a comment




Vos commentaires
ANONYME le 21.08.14 - 18:47:40
C'est super bien expliqué et clair :) !

d le 10.10.16 - 13:12:36
dz