Tester OpenGL sous Ubuntu


Le programme suivant a été réalisé avec la configuration Ubuntu 18.04, gcc version 7.5.0 et OpenGl 3.0 . Il teste la mise en oeuvre et l'utilisation des fonctionnalités de base suivantes de OpenGL : vue en perspective, objets 3D, matériaux, lumière, camera, texte, clavier.

1) Description du programme

La scène 3D comprend les éléments suivants (les 3 carrés peuvent représenter, par exemple, trois murs dans un désert):

  • Un carré parallèle à l'axe des x dont le centre se trouve placé en (0,0,40). Ce carré est constitué d'un matériau de couleur rouge (pour sa face avant) et gris (pour sa face arrière);
  • Un carré parallèle à l'axe des x dont le centre se trouve placé en (0,0,60). Ce carré est constitué d'un matériau de couleur vert (pour sa face avant) et gris (pour sa face arrière);
  • Un carré parallèle à l'axe des z dont le centre se trouve placé en (-10,0,50). Ce carré est constitué d'un matériau de couleur bleu clair (pour sa face avant) et gris (pour sa face arrière);
  • Une caméra placée, dans le plan y=0, au point de coordonnées polaire (r,a) dans le système zCx. Cette caméra est constamment dirigée vers le centre C de la scène qui se trouve au point (0,0,50) avec un angle de vue de 120°;
  • Une source de lumière ambiante de couleur blanche placée en (0, 0, 0).

01

Après avoir lancé le programme, l'appui des touches clavier suivantes provoque les actions indiquées:

  • Appui des touches e ou E: Éclairage actif ou non;
  • Appui des touches d ou D: Éclairage simple ou double face;
  • Appui des touches Up et Down: Rapprochement et éloignement de la caméra (modification de r);
  • Appui des touches Left et Right: Modification de la position de la caméra (sur le cercle de rayon r);
  • Appui des touches r ou R: Reset - réinitialisation des positions.

2) Code source

/*****************************************************************
* gl-test.cpp - Test de OpenGL 3.0
* Objets 3D, camera, eclairage, lumiere, materiaux, clavier, texte
* auteur : C.Turrier - 26 décembre 2020
* compilation : g++ gl-test.cpp -o test -lglut -lGLU -lGL
* Execution : ./test
******************************************************************/
#include <GL/freeglut.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#define PI 3.14159
//variables globales
char texte0[40+1]; char texte[40+1];
//indicateur eclairage actif
int e=1;
//indicateur eclairage double face
int df=1;
//angle en degrés de la camera/axe z
float a=0.0;
//coordonnées de la camera, dans le plan y=0
float zc=0, xc=0;
//rayon du cercle, dans le plan y=0, sur lequel se deplace la camera
static float r=30;
//materiaux
float mat1[] = { 1.0, 0.0, 0.0, 1.0 };//rouge- gris
float mat2[] = { 0.3, 0.3, 0.3, 1.0 };
float mat3[] = { 0.0, 1.0, 0.0, 1.0 };//vert-gris
float mat4[] = { 0.3, 0.3, 0.3, 1.0 };
float mat5[] = { 0.0, 1.0, 1.0, 1.0 };//bleuclair-gris
float mat6[] = { 0.3, 0.3, 0.3, 1.0 };
//demi largeur des carres
float L=4;
//fonction pour ecrire du texte
void ecrire(char *chaine)
{
int longueur, i;
longueur = (int) strlen(chaine);
for (i = 0; i < longueur; i++)
{glutBitmapCharacter(GLUT_BITMAP_9_BY_15, chaine[i]);}
}
//fonction pour initialiser la lumiere
void initialise(void)
{
//couleur de fond noir
glClearColor(0.0, 0.0, 0.0, 0.0);
//source de lumiere
glEnable(GL_LIGHT0);
float position[] = {0.0, 0, 50.0, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, position);
float couleur[] = {1.0, 1.0, 1.0, 1.0};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, couleur);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
}
//fonction d'actualisation affichage suite a evenement clavier
void affiche()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glDisable(GL_LIGHTING);
//eclairage double face
if (df==1){
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
strcpy(texte, "Eclairage double face");
glRasterPos3f(-3.2, 2.7, -2.0);glColor3f(1.0, 1.0, 1.0);
ecrire(texte);
}
//eclairage simple faces
if (df==0) {
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
strcpy(texte, "Eclairage simple face");
glRasterPos3f(-3.2, 2.7, -2.0); glColor3f(1.0, 1.0, 1.0);
ecrire(texte);
}
//informations à l'ecran
gcvt(r, 6, texte0);
strcpy(texte, "Distance de la camera = ");
strcat(texte,texte0);
glRasterPos3f(-3.2, 2.4, -2.0); glColor3f(1.0, 1.0, 1.0);
ecrire(texte);
gcvt(a, 6, texte0);
strcpy(texte, "Angle de la camera par rapport axe z = ");
strcat(texte,texte0);
glRasterPos3f(-3.2, 2.1, -2.0); glColor3f(1.0, 1.0, 1.0);
ecrire(texte);
if (e==1) {
strcpy(texte, "Eclairage actif");
glRasterPos3f(-3.2, 3.0, -2.0); glColor3f(1.0, 1.0, 1.0);
ecrire(texte);
glEnable(GL_LIGHTING);
}
if (e==0) {
strcpy(texte, "Eclairage non actif");
glRasterPos3f(-3.2, 3.0, -2.0); glColor3f(1.0, 1.0, 1.0);
ecrire(texte);
}
//--------------------POSITION DE LA CAMERA--------------
zc=50+r*cosf(a*PI/180);
xc=r*sinf(a*PI/180);
gluLookAt(xc, 0, zc, 0.0, 0.0, 50.0, 0.0, 1.0, 0.0);
//--------------------------------------------------------
//carre-rouge gris
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat1);//bleuclair- gris
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, mat2);
glBegin(GL_TRIANGLES);
glVertex3f(+L, -L, 40.0);
glVertex3f(-L, -L, 40.0);
glVertex3f(-L, +L, 40.0);
glVertex3f(+L, -L, 40.0);
glVertex3f(-L, +L, 40.0);
glVertex3f(+L, +L, 40.0);
glEnd();
//carre-vert gris
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat3);//vert-gris
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, mat4);
glBegin(GL_TRIANGLES);
glVertex3f(-L, -L, 60.0);
glVertex3f(+L, -L, 60.0);
glVertex3f(+L, +L, 60.0);
glVertex3f(-L, -L, 60.0);
glVertex3f(+L, +L, 60.0);
glVertex3f(-L, +L, 60.0);
glEnd();
//carré-bleuclair-gris
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat5);//bleuclair-gris
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, mat6);
glBegin(GL_TRIANGLES);
glVertex3f(-10, -L, 50-L);
glVertex3f(-10, -L, 50+L);
glVertex3f(-10, +L, 50+L);
glVertex3f(-10, -L, 50-L);
glVertex3f(-10, +L, 50+L);
glVertex3f(-10, +L, 50-L);
glEnd();
//bascule a l'ecran
glutSwapBuffers();
}
//fonction de dimensionnement de la fenetre du programme
void dimensionne(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//-------------CARACTERISTIQUES DE LA CAMERA------------------
gluPerspective(120.0, w/h, 1.0, 300.0);
//-----------------------------------------------------------
glMatrixMode(GL_MODELVIEW);
}
//fonction appelee sur evenement clavier
void clavier(unsigned char t, int x, int y)
{
switch (t){
case 27: exit(0); break;
case 'd': if (df==0) {df= 1;} else {df=0;} glutPostRedisplay(); break;
case 'D': if (df==0) {df= 1;} else {df=0;} glutPostRedisplay(); break;
case 'e': if (e==0) {e= 1;} else {e=0;} glutPostRedisplay(); break;
case 'E': if (e==0) {e= 1;} else {e=0;} glutPostRedisplay(); break;
case 'r': r=30.0; a=0; glutPostRedisplay(); break;
case 'R': r=30.0; a=0; glutPostRedisplay(); break;
default: break;
}}
//fonction appelee sur appui touches speciales void fleches(int t, int x, int y) { if (t==GLUT_KEY_UP){r=r-1.0; if (r<15.0) {r=15.0;}}
if (t==GLUT_KEY_DOWN){r=r+1.0; if (r>80.0) {r=80.0;}}
if (t==GLUT_KEY_LEFT){a=a+1.0; if (a>360.0) {a=a-360.0;}}
if (t==GLUT_KEY_RIGHT){a=a-1.0; if (a<0.0) {a=a+360.0;}}
glutPostRedisplay();
}
//fonction affichant des infos dans le terminal
void infos(void)
{
printf("Appuyer les touches suivantes:\n");
printf("> e ou E : eclairage actif ou non\n");
printf("> d ou D : eclairage simple ou double face\n");
printf("> Up et Down : modification distance camera\n");
printf("> Left et Right : modification position camera\n");
printf("> r ou R : reset positions\n");
}
//programme principal
int main(int argc, char* argv[])
{
infos();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
glutInitWindowSize(400, 400);
glutInitWindowPosition(100, 100);
glutCreateWindow("Test OpenGL");
glutDisplayFunc(affiche);
glutReshapeFunc(dimensionne);
glutKeyboardFunc(clavier);
glutSpecialFunc(fleches);
initialise();
glutMainLoop();
}

Code source

3) Écrans

03

4) Commentaires

Les commentaires placés dans le programme expliquent son fonctionnement.

4.1 Caméra

La fonction gluLookAt() définit position et l'orientation de la caméra qui filme la scène.

void gluLookAt(
GLdouble eyex,
GLdouble eyey,
GLdouble eyez,
GLdouble centerx,
GLdouble centery,
GLdouble centerz,
GLdouble upx,
GLdouble upy,
GLdouble upz );

eyex, eyey, eyez : position de la caméra
centerx, centery, centerz : point pointé par la caméra
upx, upy, upz : axe considéré comme étant la verticale

La fonction gluPerspective() définit les caractéristiques de la caméra.

gluPerspective(fovy, aspect, zNear, zFar);

fovy : angle de champs de la caméra (en degrés)
aspect : aspect ratio largeur/hauteur des images
zNear : distance minimum (positive) de vision de la caméra (plan proche minimum). Tous les objets situés à une distance de la caméra inférieure à zNear ne peuvent pas être vus par la caméra
zFar : distance maximum (positive) de vision de la caméra (plan éloigné maximum). Tous les objets situés à une distance de la caméra supérieure à zFar ne peuvent pas être vus par la caméra

4.2) Effet de profondeur

L'instruction glEnable(GL_DEPTH_TEST) met en place un buffer de profondeur. Ce buffer va permettre d'indiquer à OpenGl dans quel ordre les objets 3D présents dans la scène 3D doivent se supperposer sur l'écran.

L'instruction glDepthFunc(GL_LESS) demande à OpenGL de superposer sur l'écran les objets 3D dans leur ordre de profondeur par rapport à la caméra (les plus proches de la caméra masquent en tout ou partie les objets placés derrière eux); En l'absence de cette instructiob, OpenGL affiche les objets à l'écran dans l'ordre dans lequel ils sont dessinés dans le programme, ce qui peut conduire à des effets de superposition irréalistes.

4.3) Lumière

Les fonctions glEnable(GL_LIGHTING) et glDisable(GL_LIGHTING) permettent d'activer et de désactiver l’éclairage de OpenGL.
Lorsque l'éclairage OpenGL est activé, les objets de la scène apparaissent à l'écran avec des couleurs qui dépendent de la couleur de la lumière et de la couleurs des matériaux qui constituent les objets.
Lorsque l'éclairage OpenGL est désactivé, les objets de la scène apparaissent tous à l'écran avec une couleur blanche.

La fonction glLightfv() permet de définir une lumière et d’initialiser les valeurs de certains paramètres associés à cette lumière.

void glLightfv(
GLenum light,
GLenum pname,
const GLfloat *params );

light: identifiant d'une lumière. Le nombre de lumières possibles dépend de l'implémentation, mais au moins huit lumières sont prises en charge. Ils sont identifiés par des noms symboliques de la forme GL_LIGHTi où i est une valeur: 0 à GL_MAX_LIGHTS - 1.
pname: paramètre de la lumière (GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_POSITION, GL_SPOT_DIRECTION...)
params: spécifie la valeur avec laquelle le paramètre pname sera initialisé.

La fonction glLightModelfv() définit les valeurs d’initialisation pour le paramètre passé en argument.

void glLightModelfv(
GLenum pname,
const GLfloat *params );

pname: paramètre passé en argument (GL_LIGHT_MODEL_AMBIENT, GL_LIGHT_MODEL_LOCAL_VIEWER, GL_LIGHT_MODEL_TWO_SIDE)
params: spécifie la valeur avec laquelle le paramètre pname sera initialisé.

La fonction glLightModeli() définit les valeurs d’initialisation pour le paramètre passé en argument.

void glLightModeli(
GLenum pname,
GLint param );

pname: paramètre passé en argument (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_LIGHT_MODEL_TWO_SIDE)
param: spécifie la valeur avec laquelle le paramètre pname sera initialisé.

4.4) Matériaux

La fonction glMaterialfv() permet de spécifier les paramètres des matériaux pour le modèle d'éclairage considéré.

void glMaterialfv(
GLenum face,
GLenum pname,
const GLfloat *params );

face: définit les faces qui seront colorées par la lumière (GL_FRONT, GL_BACK ou GL_FRONT_AND_BACK). Généralement on choisit GL_FRONT
pname: définit le paramètre de matériau considéré (GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION, GL_SHININESS, GL_AMBIENT_AND_DIFFUSE, GL_COLOR_INDEXES) pour les faces prises en compte.
params: spécifie la valeur avec laquelle le paramètre pname sera initialisé.

En mode d'éclairage double face actif, l'éclairage des faces avant et arrière des objets est effectué en prenant en compte les matériaux définis pour les faces avant et arrière de ces objets.
En mode d'éclairage double face inactif, l'éclairage des faces avant et arrière des objets est effectué en prenant en compte les matériaux définis pour les faces avant des objets.

4.5) Faces avant et arrière des objets 3D

Les faces avant (front faces) et arrière (back faces) des objets 3D sont définies de la façon suivante.

Les objets 3D sont constitué de triangles.
La face avant d'un triangle est celle pour laquelle les sommets sont définis dans le sens inverse des aiguilles d'une montre, entre les instructions glBegin(GL_TRIANGLES) et glEnd().
La face arrière d'un triangle est celle pour laquelle les sommets sont définis dans le sens des aiguilles d'un montre, entre les instructions glBegin(GL_TRIANGLES) et glEnd().

02