Une introduction à l'OpenGL "Moderne" - Chapitre 2: Hello World: Le Slideshow
Par Narann le samedi, 23 octobre 2010, 15:34 - Script et code - Lien permanent
Voici la traduction du deuxième chapitre du tutorial de Joe Groff. :hehe:
Ici, vous allez écrire l'architecture global de votre programme, qui concerne surtout le système de fenêtrage.
Prenez le temps de configurer votre environnement de développement, il ne faut pas que la compilation soit une procédure rébarbative, vous allez le faire un grand nombre de fois...
Ce n'est pas la partie la plus intéressante mais rassurez vous, ce tutorial est assez court et vous aurez bien assez le temps de vous casser les dents sur les suivants! :baffed:
Une introduction à l'OpenGL "Moderne" - Chapitre 2: Hello World: Le Slideshow
Sommaire
- Les fichiers d'entete OpenGL
- Mise en place de notre fenêtre avec GLUT
- Compiler et lancer notre programme
- Chapitre suivant
Mise à jour: J'ai résolu les soucis que certaines personnes ont pu rencontrer, tout particulièrement ceux concernant la compilation sur Unix et Visual C++. Ce chapitre à également sa page Reddit.
Dans le chapitre précédent, je vous présentais un schéma du pipeline graphique. C'est l'heure de le mettre en pratique. Avant que nous essayions rendre une scène 3d, je vais faire comme dans tout bon tutorial, à savoir, une simple application "hello world" en deux dimension, afin de présenter les bases de l'API OpenGL.
Nous allons prendre cette image:
Nous allons ensuite la dessiner dans une fenêtre.
Mais les images qui ne bougent pas, c'est un peu ennuyeux. C'est pourquoi nous allons rendre l'exercice un peu plus intéressant en faisant des fondus enchainés avec cette image:
Ce n'est certes pas très passionnant comme programme, mais au delà de sa simplicité, celui ci nous exercera à quasiment toutes les parties d'OpenGL qu'un programme plus complexe nécessiterai.
Le code source complet est en ligne sur Github, ici. Composé de 380 lignes de C et de deux shaders d'une douzaine de ligne chacun, ce code (qui ne fait que dessiner une image sur l'écran) peut sembler exagéré. Cela dis, une grande partie de ce code pose les bases des démos à venir.
Le fichier hello-gl.c contient tout ce qui concerne le rendu OpenGL, tandis que util.c contient les fonctions qui vont nous permettre de lire des images TGA.
J'ai inclus les deux images, hello1.tga et hello2.tga, dans ce format, car il est facile à "décoder" sans avoir à utiliser une librairie externe.
Les codes des shaders sont dans deux fichiers:
- hello-gl.v.glsl pour le vertex shader.
- hello-gl.f.glsl pour le fragment shader.
Dans ce chapitre, j'expliquerai comment les différentes parties du programme hello-gl utilise l'API OpenGL pour envoyer des données dans le pipeline graphique et comment il le fait fonctionner.
Je donnerai également un bref aperçu du langage GLSL quand nous verront shaders.
C'est beaucoup de choses à faire dans un seul billet de blog, c'est pourquoi je diviserai ce chapitre en quatre parties.
Dans cette première partie, nous allons ouvrir une fenêtre avec GLUT. Dans la seconde partie, nous allons implémenter le buffer et les textures qui contiendront respectivement les vertices bruts et les images de notre programme.
Après ça, nous écriront le code des shaders qui traiteront ces données pour en faire l'image final, et nous les implémenterons dans notre application OpenGL.
Dans le dernier article, nous parlerons des appels aux fonctions OpenGL qui servent à rendre la scène sur l'écran.
Maintenant que vous avez le plan en tête, commençons à coder!
Nous allons commencer par configurer GLUT pour avoir une fenêtre vide sur l'écran.
Les fichiers d'entete OpenGL
#include <stdlib.h> #include <GL/glew.h> #ifdef __APPLE__ # include <GLUT/glut.h> #else # include <GL/glut.h> #endif
Chaque plateforme a ses headers OpenGL à différents endroits, mais avec GLEW, vous n'avez pas à vous soucier de ça.
Le fait d'inclure GL/glew.h vous permet de récupérer tout les headers OpenGL, sans que vous ayez à aller les récupérer vous même.
Malheureusement, ce n'est pas le cas de GLUT, et pour l'inclure, vous devez passer par quelques tricks multi-plateforme (les ifdef).
Son header est généralement dans GL/glut.h, mais le framework GLUT livré avec MacOS X utilise les conventions de header Apple. Ducoup, le header de GLUT est dans GLUT/glut.h.
Il y a également un bug dans la façon dont les versions récentes des headers C standards de Visual Studio interagissent avec glut.h, ce qui requière que stdlib.h soit déclaré avant glut.h.
Mise en place de notre fenêtre avec GLUT
int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowSize(400, 300); glutCreateWindow("Hello World"); glutDisplayFunc(&render); glutIdleFunc(&update_fade_factor);
GLUT fournit une interface au système de fenêtrage (window system) limité mais simple et portable.
Après avoir initialisé GLUT en appelant la fonction glutInit, nous utilisons glutInitDisplayMode pour spécifier les buffers dont notre framebuffer par défaut disposera.
Dans notre cas, un buffer de couleur (GLUT_RGB) avec double buffering (GLUT_DOUBLE) est suffisant.
La technique du double buffering permet de stocker deux color buffers dans le framebuffer et d'alterner à chaque frame entre le buffer affiché sur l'écran et celui qui est en court de rendu, ce qui permet d'avoir une animation fluide.
Si nous avons besoin d'un buffer de profondeur (depth buffer) ou d'un buffer de masque (stencil buffer), nous pouvons l'appeler ici.
Ensuite, nous nous servons de glutInitWindowSize pour initialiser la taille de notre fenêtre à 400x300 (la taille de nos images) et nous créons notre fenêtre avec glutCreateWindow.
Pour finir, nous faisons appel à deux fonctions qui "reçoivent" les events (callbacks) de la fenêtre:
- glutDisplayFunc qui calcul notre image quand la fenêtre lui demande de s'afficher.
- glutIdleFunc qui met continuellement à jour le "fade factor" entre les deux images.
glewInit(); if (!GLEW_VERSION_2_0) { fprintf(stderr, "OpenGL 2.0 not available\n"); return 1; }
Une fois que GLUT a créé notre fenêtre, nous préparons OpenGL afin de pouvoir y faire des appels.
La première chose que nous faisons est d'initialiser GLEW. Lorsque glewInit est appelé, il définit des appels au fonctions OpenGL en se basant sur la version ainsi que les extensions supportées par votre matériel.
Nous vérifions que GLEW_VERSION_2_0 est définit pour être certain que le matériel qui exécuté le programme a au moins OpenGL 2.0.
Une fois que la version est vérifié, l'utilisation de GLEW devient quasiment invisible, et nous n'aurons plus besoin d'interagir avec lui.
if (!make_resources()) { fprintf(stderr, "Failed to load resources\n"); return 1; } glutMainLoop(); return 0; }
GLEW initialisé, nous appelons notre fonction make_resources qui set nos ressources OpenGL.
Nous verront cette fonction durant les prochaines parties de ce chapitre.
Si nos ressources sont correctement chargé, glutMainLoop prend le relais.
Il affiche la fenêtre, commence par recevoir les events de l'UI, et appel les fonctions que l'on a setté en réponse à ses events (les callbacks).
Il fermera aussi le programme pour nous quand l'utilisateur le quittera.
Le return 0 supprime simplement les avertissements du compilateur et il n'est, de toute façon, jamais réellement atteint.
Compiler et lancer notre programme
Arrivé ici, nous pouvons écrire le code des callbacks de GLUT, de la fonction make_resources, et faire fonctionner notre (au combien inutile) programme.
static int make_resources(void) { return 1; }
static void update_fade_factor(void) { }
static void render(void) { glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glutSwapBuffers(); }
glClearColor set une couleur de fond RGBA (dans notre cas, blanche) que glClear utilise pour remplir le buffer de color du framebuffer.
glutSwapBuffers amène ensuite notre color buffer à l'écran.
Avec tout ça en place, nous pouvons maintenant compiler et lancer notre programme.
Cette version est dans le reposit de Github et s'appelle hello-gl-dummy.c.
La commande qui compile le programme et le link aux libs OpenGL, GLUT et GLEW peut varier suivant les plateformes.
Sur la plupart des systèmes Unix, elle devrait ressembler à ça:
gcc -o hello-gl-dummy hello-gl-dummy.c \ -I/usr/X11R6/include -L/usr/X11R6/lib \ -lGL -lGLEW -lglut
Sur MacOS X:
# Assuming GLEW was installed to /opt/local gcc -o hello-gl-dummy hello-gl-dummy.c \ -I/opt/local/include -L/opt/local/lib \ -framework OpenGL -framework GLUT -lGLEW
Sur Windows avec Visual C++:
cl /Fohello-gl-dummy.obj /c hello-gl-dummy.c link /out:hello-gl-dummy.exe hello-gl-dummy.obj \ opengl32.lib glut32.lib glew32.lib
Sur Windows avec mingw:
gcc -o hello-gl-dummy.exe hello-gl-dummy.c \ -lopengl32 -lglut32 -lglew32
Le reposit contient également les makefiles de chacune de ses plateformes.
Vous pouvez compiler cette version du programme en utilisant hello-gl-dummy (ou hello-gl-dummy.exe sur Windows):
make -f Makefile.MacOSX hello-gl-dummy # or Makefile.Unix or Makefile.Mingw
nmake /f Nmakefile.Windows hello-gl-dummy.exe
Une fois que vous avez compilé le programme, vous devriez être capable de le lancer et d'avoir une fenetre blanche, comme promis:
Fermez la fenêtre, ou, sur MacOS X, quittez l'application.
Chapitre suivant
Avec la satisfaction d'avoir une fenêtre ouverte devant nous, nous somme prêt à remplir OpenGL de vertex et d'images.
Dans le prochain article, j'introduirais les buffers et textures OpenGL.
Vous pouvez retrouver l'article original sur la page de Joe Groff, un fois de plus: Merci à lui!