Création d'une Skybox en OpenGL

Cyril Doillon

Vous en avez marre du fond noir de votre application 3D. Il est grand temps de changer… Vous pouvez toujours passer du noir à une autre couleur, mais il serait si intéressant d'avoir des nuages et du soleil pour donner un peu de vie. Nous allons voir comment procéder dans ce tutoriel.

- Titre : Création d'une Skybox en OpenGL

- Auteur : Cyril Doillon

- Parution : 9 juin 2008

- Mise à jour : 29 novembre 2019

- Licence : Copyright ® 2008 Cyril DOILLON. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- Introduction

- I. Un peu de théorie

- I-A. La géométrie : base d'une Skybox

- I-B. La texture « CubeMap »

- I-C. Contrainte sur le DepthBuffer

- II. Création des textures : Terragen

- II-A. Par où commencer ?

- II-B. Configuration de la scène

- II-C. Position de la caméra et génération des textures

- III. Un peu de pratique

- III-A. Initialisation de la Skybox : Création de la texture CubeMap

- III-B. Géométrie de la Skybox

- III-C. Rendu principal

- Conclusion

- Sources

- Remerciements

Introduction

Tous les développements d'applications 3D commencent par la rotation d'un cube sur un fond noir. Ce fond noir vous sort par les yeux… vous pouvez toujours passer à une autre couleur, mais cela ne donnera pas beaucoup de réalisme à votre scène. Une autre solution simple serait de définir une image fixe en fond de votre application, mais le problème est que le ciel resterait fixe quel que soit le point de vue. Et si nous faisions un rendu de ciel ou de décor réaliste ?

Ce système de rendu, est souvent appelé « Skybox » (littéralement « Boite de ciel »). La Skybox est généralement un cube texturé avec un décor de ciel. Ce simple système peut poser de nombreux problèmes notamment dans la géométrie de ce cube.

Nous allons commencer par un peu de théorie pour présenter les différents concepts utilisés pour réaliser cette skybox le plus efficacement possible. Les thèmes abordés seront l'utilisation des cube-map et la contrainte sur le depth buffer. Nous continuerons par l'utilisation du logiciel « Terragen » qui permet de générer rapidement les textures de la skybox. Enfin, nous passerons à la pratique en appliquant les concepts en OpenGL.

I - Un peu de théorie

I-A - La géométrie : base d'une Skybox

Une Skybox est, comme son nom l'indique, une box ou plutôt une boite. Cette boite aura des largeur, longueur et hauteur identiques. Toutes les faces du cube seront dirigées vers l'intérieur, car toute la scène sera contenue dans celui-ci. Chacune des faces du cube correspondra aux vues du Nord, Sud, Est, Ouest de la caméra ainsi que le Haut et le Bas. La texture qui sera appliquée sur chacune d'elles correspondra à ce que l'on pourrait voir à une distance infinie, l'horizon.

Géométrie de la Skybox

Le cube sera positionné de part et d'autre de la caméra dans toutes les directions. La boite aura donc une position fixe, quelle que soit la position de la caméra. D'un point de vue de l'orientation, et contrairement à sa position, la boite sera alignée sur les trois axes X, Y et Z du monde. L'orientation sera, évidemment, indépendante de la direction de la caméra. Nous placerons, par exemple, les faces Est et Ouest sur l'axe X, Haut et Bas sur l'axe Y et Nord et Sud sur l'axe Z. Ainsi, pour un cube de taille T, les faces opposées seront sur les positions -T/2 et T/2 sur l'axe d'alignement.

Le choix de la taille T interviendra un peu plus loin dans le tutoriel dans le chapitre « Contrainte sur le DepthBuffer ».

I-B - La texture « CubeMap »

Maintenant que nous avons donné une forme à notre Skybox, il faut lui donner des couleurs. Pour cela, nous allons utiliser une texture. Celle-ci ne sera ni à une dimension, ni à deux… ni à trois… mais sera une texture cube appelée : « CubeMap » (pour plus de détails sur les textures 1D, 2D et 3D, je vous conseille de vous rendre sur des tutoriels de base sur le texturage). Une CubeMap, qu'est-ce que c'est que cette bête-là ??

On peut la placer à mi-chemin entre une texture 2D et une texture 3D. Elle peut se représenter, comme son nom l'indique, par un cube composé de six faces. Chacune des faces correspond à une direction par rapport au centre du cube soit les faces X positif, X négatif, Y positif, Y négatif, Z positif et enfin Z négatif. Ainsi, chacune d'elles sera une texture 2D. Donc une texture CubeMap correspond à six textures 2D, mais contient moins d'information qu'une texture 3D.

L'avantage d'un tel type de texture est d'assigner une valeur (couleur par exemple) pour une direction donnée. Cela convient tout à fait à notre skybox, car pour chaque direction donnée depuis la position de la caméra, la texture assignera une couleur. Les coordonnées ne seront donc pas une position précise sur la texture comme ce le serait pour les textures « simples », mais une direction. Ainsi, pour notre géométrie, vue auparavant, alignée sur les axes, et centrée autour de (0;0;0), il est très facile de déterminer les coordonnées de textures. Sachant qu'il n'est pas nécessaire que le vecteur soit normalisé, nous pouvons, pour chaque sommet, passer directement la coordonnée du vertex.

Texture CubeMap

I-C - Contrainte sur le DepthBuffer

Notre skybox est presque prête. Il ne reste qu'un seul problème qui va nous faire revenir sur la partie géométrique. Nous allons faire le choix de la taille de notre boite. Supposons que nous choisissions une taille T de 1000 km, ce qui nous permet de simuler une boite à distance pseudoinfinie. Cela pose deux problèmes principaux :

- les objets se trouvant à 1001km seront derrière le ciel et donc invisibles ;

- le frustum doit être au minimum de la taille de la boite et englober les 1000 km ce qui perd complètement l'avantage du frustum (limitation de la quantité d'objets affichés).

Rappel : le Frustum définit le champ de vision de la caméra. Plus d'info (ici).

Ainsi, une taille pseudoinfinie ne convient pas. Pour résoudre le problème du frustum, prenons le cas extrême inverse, soit, choisissons une taille T de 1 m. Ce choix ne convient pas non plus, car il pose un problème majeur :

- les objets se retrouvent plus facilement derrière la skybox.

Il nous faut donc trouver une méthode pour résoudre l'ensemble de ces problèmes. Nous allons donc nous intéresser au DepthBuffer qui peut nous aider dans cette tâche.

Rappel : le DepthBuffer contient, pour chaque fragment (pixel), la valeur de profondeur de l'objet dessiné le plus proche. Plus d'info (ici).

Nous savons que notre skybox doit se trouver toujours derrière l'ensemble des objets de la scène. Nous pouvons donc le rendre en premier, avant tout autre objet, pour qu'il se retrouve derrière. Malheureusement, nous conservons le problème des distances pour une boite trop petite ou trop grande. Nous allons donc utiliser une astuce de rendu pour considérer les faces de la boite comme se trouvant à l'infini même si elles ont des coordonnées proches. Cette astuce consiste à ne pas écrire dans le depth buffer lors du rendu de la skybox pour que tous les objets rendus après soient forcément considérés devant. Cela nous permet de choisir une boite qui peut être de taille 1 du moment qu'elle est rendue avant tout le reste de la scène. Le tableau suivant montre l'évolution du DepthBuffer en utilisant, ou pas, notre astuce. (Les valeurs entre parenthèses sont les valeurs de profondeur des objets, 1 infini, 0 proche.)

Valeur initiale

Skybox (0.5)

Objet (0.7)

Valeur finale utilisée

Avec écriture dans le DepthBuffer

1

0.5

0.5

Skybox

Sans écriture dans le DepthBuffer

1

1

0.7

Objet

On peut remarquer qu'un objet se trouvant derrière la skybox, sera quand même affiché devant.

II - Création des textures : Terragen

II-A - Par où commencer ?

Nous avons vu de quoi était composée l'intégralité de notre skybox. Maintenant, nous passons aux choses sérieuses, la pratique. J'en entends déjà dans le fond qui se demandent comment ils vont faire la texture de la skybox, car ils ne se sentent pas du tout l'âme d'un artiste… Il y a toujours la possibilité d'en trouver gratuitement sur le web. Et si un outil le faisait pour nous ? Et s'il nous créait notre skybox unique pour notre application ?

Ce formidable outil s'appelle Terragen. Il existe en deux versions. La première, gratuite et limitée et la seconde en version payante réservée à un usage commercial uniquement. En tant que programmeurs amateurs, nous pouvons nous contenter de la première version qui donne des résultats tout à fait acceptables. Cette version est disponible en téléchargement sur le site officiel du logiciel et pour plusieurs plateformes.

Site officiel de Terragen

Après le téléchargement et l'installation du logiciel, nous pouvons attaquer la génération de notre texture.

Interface générale de Terragen

II-B - Configuration de la scène

Lorsque l'on crée un nouveau monde sous Terragen, il faut commencer par configurer tous les paramètres d'environnement. À gauche de la fenêtre principale se trouvent une série de boutons, qui permettent de configurer différentes caractéristiques de la scène comme les nuages, les couleurs, le soleil, le terrain…

Boutons de configuration

Au niveau du terrain, par défaut, à la création d'un nouvel environnement, le terrain est plat. Cela nous convient très bien, car nous allons nous contenter d'un fond sans relief. Il vous est tout à fait possible de générer des montagnes avec Terragen. De la même manière, nous n'avons pas besoin de mer ou de quelconque océan. Si vous voulez plus d'informations sur la génération avec du terrain ou avec de l'eau, je vous conseille de vous reporter aux différents tutoriels que l'on peut trouver au travers de la toile.

Une chose un peu plus intéressante à configurer est le paramétrage des nuages. Il est possible de configurer l'altitude des nuages, leur luminosité, leur taille, leur quantité, leur couleur… Je vous laisse faire quelques tests pour voir ce qui vous convient le mieux.

Configuration des nuages

Il est également possible de configurer l'atmosphère de notre environnement à savoir les dégradés de couleurs du ciel. La configuration suivante consiste à paramétrer la lumière du soleil. Différents paramètres peuvent être réglés comme les angles et positions du soleil, la couleur de luminosité, les rayons d'éblouissement… Je vous laisse également faire vos propres essais…

Configuration du soleil

Il peut être intéressant de faire correspondre la position du soleil de votre skybox et la position de la lumière principale dans votre scène 3D. Pour cela, notez sur un bout de papier les angles de positionnement.

II-C - Position de la caméra et génération des textures

Maintenant, nous pouvons passer aux rendus de nos six textures. Grâce au tout premier bouton, nous pouvons afficher la fenêtre du contrôle du rendu. Cette fenêtre nous permet de positionner la caméra sur notre terrain, le niveau de détail du rendu et de prévisualiser celui-ci.

Configuration du rendu

Il faut commencer par paramétrer notre caméra. Nous allons commencer par la placer au centre de notre scène soit en 128 * 128. Si vous avez modifié la taille du terrain, il faut ajuster ces coordonnées à votre terrain. Nous plaçons également la target de la caméra vers le Nord de notre scène, à savoir en 128 * 256. Les angles sont calculés automatiquement en fonction des deux paramètres précédents. Nous plaçons la caméra et sa target à une hauteur de 1 pour se trouver juste au-dessus de notre terrain plat. La dernière chose à paramétrer est le zoom de la caméra pour que chaque rendu corresponde à une vision de 90°. Dans la boite de dialogue qui apparait lorsque l'on clique sur le bouton « Camera Setting », nous pouvons configurer précisément le zoom à 1. Nous allons donc positionner la caméra de six manières différentes, une par texture à générer :

Texture générée

Position de la caméra

Target de la caméra

Orientation de la caméra

X négatif

128x128x1

128x256x1

0x0x0

X positif

128x128x1

128x0x1

180x0x0

Z négatif

128x128x1

0x128x1

-90x0x0

Z positif

128x128x1

256x128x1

90x0x0

Y négatif

128x128x1

128x128x-128

0x-90x0

Y positif

128x128x1

128x128x128

0x90x0

- Pour XN, ZN, XP, ZP : il faut appliquer une rotation de 180° et retourner l'image horizontalement.

- Pour YN et YP : il faut appliquer une rotation de -90° et ensuite retourner l'image horizontalement.

Nous allons passer maintenant au rendu, proprement dit, des textures. Tout se situe dans la partie gauche de notre fenêtre. Nous avons, tout d'abord la possibilité de prévisualiser nos rendus. Il nous faut également configurer le niveau de détail de notre rendu. Je vous conseille de le mettre au maximum, même s'il prend un peu de temps, cela donne des résultats tout à fait acceptables. Nous devons également configurer la taille de notre image finale. Nous la passons à 512x512 pixels, ce qui est déjà une grosse texture. Nous sommes maintenant prêts pour rendre nos six textures.

Il ne faut pas modifier la scène (terrain, nuage…) entre deux rendus de texture, car la scène complète sera modifiée et il vous faudra recommencer toutes les textures précédemment rendues. Cela permet de conserver des jointures entre textures relativement propres et invisibles.

III - Un peu de pratique

III-A - Initialisation de la Skybox : Création de la texture CubeMap

Nous avons maintenant tous les éléments nécessaires pour attaquer la vraie partie pratique de programmation. La première chose à faire est d'initialiser notre texture CubeMap. Ce type de texture n'est pas supporté par défaut par OpenGL. Son utilisation se fait par l'extension ARB « GL_ARB_texture_cube_map ». Celle-ci est disponible sur toutes les cartes graphiques depuis 1999 environ donc il est très peu probable de trouver une carte ne la supportant pas. Mais pour faire cela propre, nous allons quand même vérifier son support dans notre carte graphique au moyen de la méthode glGetString(GL_EXTENSIONS). Si le nom de l'extension se trouve dans la chaîne de caractères, les textures CubeMap sont supportées. Dans notre cas, seulement sept constantes vont nous être utiles. Celles-ci permettent de définir le type de texture ainsi que chacune de ses faces. Leur nom doit vous rappeler quelque chose…

Spécification de l'extension GL_ARB_texture_cube_map

Extension OpenGL pour les CubeMap

#define GL_TEXTURE_CUBE_MAP_ARB             0x8513
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB  0x8515
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB  0x8516
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB  0x8517
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB  0x8518
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB  0x8519
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB  0x851A

// Test de l'extension GL_ARB_texture_cube_map
char* extensions = (char*) glGetString(GL_EXTENSIONS);
if(strstr(extensions, "GL_ARB_texture_cube_map") != NULL)
{
// Initialisation de la CubeMap
}
else
{
// Autre système (six textures 2D par exemple) ou sortie de l'application ou toute autre gestion d'erreur
}

Nous pouvons maintenant procéder à la création de notre texture. Nous allons donc utiliser nos six textures BMP générées par Terragen. Nous commençons par définir l'ordre de déclaration des textures. Nous chargeons ensuite les textures en mémoire grâce à la méthode LoadBMP vue dans les tutoriels de Nehe.

Tutoriel Nehe sur les textures

Nous demandons ensuite à OpenGL de nous générer une texture de type CubeMap dont un identifiant nous est retourné. Nous ajoutons ensuite nos textures une à une. Nous pouvons terminer par la configuration de la texture avec des éventuels mipmap…

Initialisation de la Skybox

// Liste des faces successives pour la création des textures de CubeMap
GLenum cube_map_target[6] = {
GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
};

// Chargement des six textures
AUX_RGBImageRec * texture_image[6];
texture_image[0] = LoadBMP( "Skybox/XN.bmp" );
texture_image[1] = LoadBMP( "Skybox/XP.bmp" );
texture_image[2] = LoadBMP( "Skybox/YN.bmp" );
texture_image[3] = LoadBMP( "Skybox/YP.bmp" );
texture_image[4] = LoadBMP( "Skybox/ZN.bmp" );
texture_image[5] = LoadBMP( "Skybox/ZP.bmp" );

// Génération d'une texture CubeMap
GLuint cube_map_texture_ID;
glGenTextures(1, &cube_map_texture_ID);

// Configuration de la texture
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, cube_map_texture_ID);

for (int i = 0; i < 6; i++)
{
glTexImage2D(cube_map_target[i], 0, 3, texture_image[i]->sizeX, texture_image[i]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_image[i]->data);

if (texture_image[i])
{
if (texture_image[i]->data)
{
free(texture_image[i]->data);
}
free(texture_image[i]);
}
}

glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);

Il est possible que vous deviez tourner vos textures de 180° si vous utilisez un format BMP, car c'est un format inversé.

III-B - Géométrie de la Skybox

Nous allons maintenant définir une fonction ou méthode DrawSkyBox() qui sera appelée à chaque frame lors du rendu de notre scène. Celle-ci s'occupera de dessiner l'ensemble de notre géométrie. Pour simplifier les choses, nous allons utiliser un TRIANGLE_STRIP (« bande ») par face, mais cela peut très facilement être optimisé. Nous commençons par définir la taille de notre cube, ou plus précisément, sa demi-taille. Comme nous l'avons vu précédemment, sa valeur n'est pas très importante pour le rendu, il suffit qu'elle se situe dans le frustum d'affichage. Nous continuons en indiquant que nous utilisons la texture créée plus haut. L'étape suivante consiste au positionnement général de la SkyBox. Pour cela, nous réinitialisons la matrice ModelView et nous déplaçons le point de vue uniquement en orientation. Ainsi, la Skybox se trouve centrée autour de la caméra. Enfin, nous définissons chacune de nos faces. Nous pouvons remarquer que les coordonnées de textures correspondent exactement au vertex du cube. Cela vient du fait que nous centrons notre cube autour de la caméra (soit (0;0;0)) et que chaque coordonnée de vertex correspond à sa direction depuis son centre. On termine en rétablissant la matrice ModelView précédemment sauvegardée.

Rendu du cube

// Taille du cube
float t = 1.0f;

// Utilisation de la texture CubeMap
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, cube_map_texture_ID);

// Réglage de l'orientation
glPushMatrix();
glLoadIdentity();
glRotatef( camera_pitch, 1.0f, 0.0f, 0.0f );
glRotatef( camera_yaw, 0.0f, 1.0f, 0.0f );

// Rendu de la géométrie
glBegin(GL_TRIANGLE_STRIP);            // X Négatif
glTexCoord3f(-t,-t,-t); glVertex3f(-t,-t,-t);
glTexCoord3f(-t,t,-t); glVertex3f(-t,t,-t);
glTexCoord3f(-t,-t,t); glVertex3f(-t,-t,t);
glTexCoord3f(-t,t,t); glVertex3f(-t,t,t);
glEnd();

glBegin(GL_TRIANGLE_STRIP);            // X Positif
glTexCoord3f(t, -t,-t); glVertex3f(t,-t,-t);
glTexCoord3f(t,-t,t); glVertex3f(t,-t,t);
glTexCoord3f(t,t,-t); glVertex3f(t,t,-t);
glTexCoord3f(t,t,t); glVertex3f(t,t,t);
glEnd();

glBegin(GL_TRIANGLE_STRIP);            // Y Négatif
glTexCoord3f(-t,-t,-t); glVertex3f(-t,-t,-t);
glTexCoord3f(-t,-t,t); glVertex3f(-t,-t,t);
glTexCoord3f(t, -t,-t); glVertex3f(t,-t,-t);
glTexCoord3f(t,-t,t); glVertex3f(t,-t,t);
glEnd();

glBegin(GL_TRIANGLE_STRIP);            // Y Positif
glTexCoord3f(-t,t,-t); glVertex3f(-t,t,-t);
glTexCoord3f(t,t,-t); glVertex3f(t,t,-t);
glTexCoord3f(-t,t,t); glVertex3f(-t,t,t);
glTexCoord3f(t,t,t); glVertex3f(t,t,t);
glEnd();

glBegin(GL_TRIANGLE_STRIP);            // Z Négatif
glTexCoord3f(-t,-t,-t); glVertex3f(-t,-t,-t);
glTexCoord3f(t, -t,-t); glVertex3f(t,-t,-t);
glTexCoord3f(-t,t,-t); glVertex3f(-t,t,-t);
glTexCoord3f(t,t,-t); glVertex3f(t,t,-t);
glEnd();

glBegin(GL_TRIANGLE_STRIP);            // Z Positif
glTexCoord3f(-t,-t,t); glVertex3f(-t,-t,t);
glTexCoord3f(-t,t,t); glVertex3f(-t,t,t);
glTexCoord3f(t,-t,t); glVertex3f(t,-t,t);
glTexCoord3f(t,t,t); glVertex3f(t,t,t);
glEnd();

// Réinitialisation de la matrice ModelView
glPopMatrix();

III-C - Rendu principal

Nous pouvons passer enfin au rendu principal de notre application. On commence, comme tout rendu, par vider les différents buffers utilisés, réinitialiser la couleur principale et initialiser la caméra. On peut ainsi commencer le rendu de notre skybox. On définit ainsi que l'on souhaite utiliser le tampon de profondeur, que l'on active l'extension des textures CubeMap et que l'on désactive la lumière. Ce dernier cas nous sert à éviter les problèmes liés à l'ombre des faces sur notre cube et on garde ainsi un rendu continu entre les faces. La fonction glDepthMask() nous sert à définir un masque d'écriture dans le DepthBuffer. Lorsque l'on passe GL_TRUE, on active l'écriture alors que lorsque l'on passe GL_FALSE, on la désactive. On peut enfin dessiner notre skybox et réinitialiser les états du rendu.

Rendu de la SkyBox

// Initialisation de la scène
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glColor3f( 1.0f, 1.0f, 1.0f );

// Placement de la caméra
glTranslatef( 0.0f, 0.0f, -8.0f );
glRotatef( CAMERA_Pitch, 1.0f, 0.0f, 0.0f );
glRotatef( CAMERA_Yaw, 0.0f, 1.0f, 0.0f );

// Configuration des états OpenGL
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_CUBE_MAP_ARB);
glDisable(GL_LIGHTING);

// Désactivation de l'écriture dans le DepthBuffer
glDepthMask(GL_FALSE);

// Rendu de la SkyBox
DrawSkyBox( camera_yaw, camera_pitch );

// Réactivation de l'écriture dans le DepthBuffer
glDepthMask(GL_TRUE);

// Réinitialisation des états OpenGL
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
glEnable(GL_LIGHTING);

// .... on continue par le rendu de la scène

Conclusion

Lors de ce tutoriel, nous avons vu comment créer un fond réaliste statique pour votre application 3D. Cela nous a permis d'aborder quelques notions très intéressantes comme les textures CubeMap ou l'utilisation avancée du DepthBuffer. Nous obtenons un résultat tout à fait satisfaisant du moment que la texture utilisée est générée correctement. Dans un prochain tutoriel, nous aborderons les différentes améliorations que l'on peut opérer sur cette Skybox pour la rendre encore plus efficace.

Pour toutes questions, n'hésitez pas à demander directement sur le forum OpenGL

Sources

Un exemple simple d'utilisation de notre skybox est disponible :

- FTP

- HTTP

Remerciements

Je tiens particulièrement à remercier Loka et RideKick pour leur relecture et leur soutien. Je remercie également Yno. Et je remercie milena pour ses remarques sur l'orientation des images pour résoudre les problèmes de jointures.