Sujets et Corrections
de TD et TP

Fichier zip
des exercices OpenGL

(avec Solution
Visual Studio
Pro 2015)

RETOUR

TD n°1 et 2 : Premières scènes OpenGL

Exercice n°1

(1) Programmer en OpenGL la scène suivante sous la forme d'une fonction C sans utiliser les fonctions glPushMatrix et glPopMatrix ailleurs qu'en début et fin de fonction:
Quatre cubes de coté 2.0 aux positions (2.0,0.0,2.0), (2.0,0.0,-2.0), (-2.0,0.0,2.0) et (-2.0,0.0,-2.0).

(2) Reprogrammer en OpenGL la scène de la question (1) de telle manière que les cubes aient une de leurs faces orientée vers l'origine du repère.

(3) Reprogrammer en OpenGL la scène de la question (2) en utilisant les fonctions glPushMatrix et glPopMatrix pour rendre les objets indépendants les uns des autres et simplifier l'écriture de la fonction scène.

(4) Programmer une scène OpenGL en plaçant 3 cubes de coté 2.0 aux 3 sommets d'un triangle équilatéral défini avec les caractéristiques suivantes:
  - rayon 1.5,
  - centré sur l'origine,
  - plongé dans le plan xOz.
Les 3 cubes présentent une de leurs faces orientée vers l'origine.

Exercice n°2

(1) Programmer la scène OpenGL modélisant un bras robot simplifié composé d'un bras et d'un avant-bras.
Le bras est articulé pour que sa base puisse tourner autour de l'axe Oy d'un angle r1. Il s'agit d'un parallélépipède rectangle de dimension (3.0,1.0,1.0).
L'avant-bras est articulé autour de l'axe y au bout du bras pour un angle r2. Il s'agit d'un parallélépipède rectangle de dimension (3.0,0.8,0.8).

(2) Modifier la fonction OpenGL de l'exercice n°1 en remplaçant les parallélépipèdes par des cylindres de tailles équivalentes à celles des objets qu'ils remplacent.

Exercice 3

(1) Implanter en OpenGL une fonction de dessin d'une molécule de Benzène (C6H6).

Les atomes de carbone (atomes centraux) ont un rayon égal à 0.5.
Les liaisons entre 2 atomes de carbone ont pour longueur (centre à centre) 2.0 et pour rayon 0.15.
Les atomes d'hydrogène ont un rayon égal à 0.25.
Les liaisons entre atome de carbone et d'hydrogène ont pour longueur (centre à centre) 1.2 et pour rayon 0.05.
La molécule est centrée sur l'origine et placée dans le plan xOy.

(2) Modifier la modélisation de la molécule de benzène de la question précédente pour que les liaisons carbone-carbone soient alternativement des liaisons simples et des liaisons doubles (voir figure ci-dessous).
Les cylindres modélisant ces liaisons auront pour rayon 0.05 (comme les liaisons carbone-hydrogène). Dans le cas des liaisons doubles, les deux cylindres de modélisation seront écartés de 0.1.

Solutions

Quatre cubes (Question 3)
Trois cubes
Bras robot avec parallélépipèdes
Bras robot avec cylindres
Molécule de benzène

TP n°1 : Premières implantations OpenGL

Exercice n°1

Télécharger le fichier archive IG-2018-2019.zip. Ce fichier archive contient une "solution" Visual Studio 2015.
Après extraction, un répertoire IG-2018-2019 est créé. Ce répertoire contient lui-même 6 répertoires:
  - Bin pour les exécutables,
  - Include pour les fichiers d'entête OpenGL (fichiers non présents dans Visual Studio),
  - Lib pour les fichiers librairie OpenGL (fichiers non présents dans Visual Studio),
  - Projet pour le fichier de description de la solution (Projet.sln) et les répertoires contenant les projets faisant partie de la solution (Un seul répertoire actuellement: Exemple),
  - Src pour les fichiers source des projets inclus dans la solution,
  - Temp pour les fichiers temporaires (solution, compilation, ...).

La solution comprend un seul projet nommé Exemple. Ce projet référence un seul fichier source Exemple.cpp et est configuré pour une compilation utilisant OpenGL:
  - fichiers d'entête (répertoire implicite ../../Include),
  - fichiers librairie: OpenGL32.ms.lib et glu32.ms.lib dans les options de configuration GUI et glut32.ms.lib par référence directe,
  - copie de l'exécutable dans le répertoire Bin.
La compilation (génération) de ce projet doit conduire à la création d'un exécutable nommé Exemple.exe dans le répertoire Bin. Son exécution requière les dll OpenGL32.dll et Glu32.dll (toujours présentes par défaut dans le système d'exploitation Windows) ainsi que la dll Glut32.dll (jamais présente par défaut dans le système d'exploitation Windows mais dont il existe une copie dans le répertoire Bin où est copié l'exécutable).

(1) Extraire l'archive IG-2018-2019.zip. Lancer Visual Studio 2015 et charger la solution. Vérifier la compilation et l'exécution du projet Exemple.

(2) Implanter la question (3) de l'exercice n°1 du TD n°1. On pourra directement modifier le fichier Exemple.cpp de la question précédente pour y intégrer le code de génération de la scène.

(3) Implanter la question (4) de l'exercice n°1 du TD n°1.

Solutions

 

GLUT

Quatre cubes

Trois cubes

Bras robot avec des "cubes"

TP n°1 : GLUt

Le fichier code source GLUtMinimum.cpp illustre le fonctionnement événementiel de la librairie GLUt. On rappelle que nous allons utiliser cette librairie annexe pour construire l'interface utilisateur de nos programmes OpenGL, celui-ci ne contenant aucune fonction dédiée à cette fin.

Le fichier source GLUtMinimum.cpp contient le minimum d'appels à OpenGL de façon à mettre en évidence les fonctionnalités GLUt et non les fonctionnalités OpenGL. La scène construite est constituée d'un unique tore. Le calcul d'illumination est activé et une seule lumière est allumée. L'élimination des parties cachées est activée. La projection est réalisée en projection orthographique. Le contenu du volume cubique dont la diagonale est définie par les positions (-1.0,-1.0,-1.0) et (1.0,1.0,1.0) du repère de modélisation est affiché dans le viewport de visualisation en projection selon l'axe -z du repère de modélisation. Le viewport de visualisation est configuré pour occuper automatiquement (dynamiquement) l'intégralité de la fenêtre.
La fonction main organise les points suivants:
  - exécution d'une fonction (static void clean(void)) lorsque l'application est interrompue par exécution de la fonction exit,
  - configuration et création de la fenêtre de visualisation,
  - configuration des paramètres OpenGL qui doivent l'être et qui n'auront pas à être reconfigurés au cours de la vie du programme,
  - programmation de la gestion des événements,
  - affichage de la fenêtre de visualisation et lancement de la boucle infini de gestion des événements.

Les événements suivants sont gérés "normalement":
  - rafraichissement de la fenêtre de dessin (display),
  - modification de la taille de la fenêtre de dessin (reshape).
Les événements suivants sont gérés a minima par affichages écran texte:
  - frappe d'une touche alphanumérique du clavier (keyboard),
  - frappe d'une touche non-alphanumérique du clavier (special),
  - clic souris dans la fenêtre de dessin (mouse),
  - déplacement de la souris bouton appuyé dans la fenêtre de dessin (mouseMotion).
Le code de gestion des événements suivants est programmé pour une gestion a minima par affichages écran texte, mais ces événements ne sont activés (lignes laissées en commentaire) dans la fonction main:
  - aucun événement n'est en attente (idle),
  - déplacement de la souris bouton non appuyé devant la fenêtre de dessin (passiveMouseMotion).

Le fichier GLUt-3-spec.pdf contient la documentation de référence de GLUt. Il pourra vous aider à implanter les réponses aux questions suivantes.

a) Implanter un contrôle clavier permettant de switcher entre les modes d'affichage plein et fil de fer en utilisant la touche de clavier Espace.

b) Implanter une animation telle que le tore tourne sur lui-même autour de l'axe x à raison de 1° de rotation entre chaque image.

c) Implanter un contrôle clavier permettant d'activer/désactiver l'animation au moyen de la touche Entrée.

d) Implanter un contrôle clavier permettant de faire tourner le tore sur lui-même autour de l'axe y dans un sens ou dans l'autre en utilisant les touches Flèche gauche et Flèche droite.

e) Implanter un contrôle clavier permettant de passer l'affichage en mode plein écran en utilisant les touches de clavier 'f' ou 'F'.

f) Implanter un contrôle souris permettant d'inverser le sens de rotation de l'animation par clic du bouton droit de la souris dans la fenêtre de dessin.

g) Corriger le problème de déformation de la scène lorsque la dimension de la fenêtre est changée par l'utilisateur vers des valeurs différentes de résolutions en x et en y.

Solutions

 

GLUT

Fonctionnalités principales de GLUt:
 - création de fenêtres
 - gestion des événements :
   - fenêtre,
   - clavier,
   - souris

TD n°3 : Modélisation par facettes

Exercice n°1

(1) Modéliser par facettes un cube de coté c centré sur l'origine du repère de modélisation. On ne générera pas les normales.
La fonction créée aura pour prototype:
  void mySolidCube(double c);

TD02-01a.png TD02-01b.png 

(2) Modifier la modélisation de la question précédente pour ajouter la gestion des normales.
Le but est de rendre possible les calculs d'éclairage.

TD02-02a.png TD02-02b.png 

Exercice n°2

Modéliser par facettes un cylindre selon les caractéristiques suivantes:
  - choix du rayon,
  - choix de la hauteur,
  - choix du nombre de facettes en découpage longitudinal pour une valeur entière ns,
  - centré sur l'origine du repère de modélisation,
  - axé selon y.
On ne modélisera pas les bases du cylindre, mais uniquement le tube.
La fonction créée aura pour prototype:
  void mySolidCylindre(double hauteur, double rayon, int ns);

Question supplémentaire: Ajouter un découpage latéral (selon l'axe y) pour une valeur nl.
Le prototype de la fonction devient:
  void mySolidCylindre(double hauteur, double rayon, int ns, int nl);

TD02-03a.png TD02-03b.png 

TD02-04.png

Solutions

 

GLUT

Cubes et cylindres par facettes

TP n°3 : Modélisation géométrique

(1) Implanter l'exercice n°2 du TD n°1 en version "parallélépipèdes" et en version "cylindres". On utilisera la fonction de modélisation de cylindre développée au cours du TD n°3.

(2) Ajouter les contrôles clavier permettant de faire varier les angles de rotation de l'avant-bras et du bras. Exemple: Up/Down pour changer l'angle r1 par incrément de 1.0° et Page up/Page down pour changer l'angle r2 par incrément de 1.0°.

(3) Ajouter au bras robot une "pince robot" formée de deux mandibules modélisées par des cones. En dehors du fait d'utiliser des cones pour les mandibules, vous êtes libre de définir votre pince comme vous le souhaitez (objets canoniques de modélisation, taille(s) de ces objets, ...)

(4) Ajouter les contrôles clavier permettant d'ouvrir/fermer la pince et de la faire tourner sur elle-même au bout du bras robot autour de l'axe du bras. Exemple: Right/Left pour changer l'angle de rotation de la pince par incrément de 1.0° et +/- pour ouvrir/fermer la pince.

Solutions

 

GLUT

Un bras robot avec une pince

TD n°4 : Paramètrage numérique de caméras

a) On considère une caméra de visualisation en projection parallèle orthographique placée en position (0.0, 0.0, 0.0) orientée selon l'axe (0.0, 0.0, -1.0). On considère une scène centrée sur le point de coordonnées (0.0, 0.0, -100.0) et occupant un volume circulaire de rayon 10.0.
Quelle ouverture doit-on donner à cette caméra pour visualiser cette scène en gros plan dans une fenêtre d'affichage carrée (viewport carré)?
Définir le paramétrage numérique de la fonction OpenGL utilisée pour réaliser cette visualisation: glOrtho.

b) On considère une caméra de visualisation en projection en perspective placée en position (0.0, 0.0, 0.0) orientée selon l'axe (0.0, 0.0, -1.0). On considère une scène centrée sur le point de coordonnées (0.0, 0.0, -100.0) et occupant un volume circulaire de rayon 10.0.
Quelle ouverture doit-on donner à cette caméra pour visualiser cette scène en gros plan dans une fenêtre d'affichage carrée (viewport carré)?
Définir le paramétrage numérique de la fonction OpenGL utilisée pour réaliser cette visualisation: gluPerspective.

c) Dans le cadre d'une implantation OpenGL, décrire une solution permettant de s'assurer que l'intégralité de la scène sera visualisée quel que soit le ratio résolution horizontale sur résolution verticale adopté par le viewport d'affichage.

Solutions

 

GLUT

Ouverture d'une caméra orthographique

Ouverture d'une caméra en perspective

TP n°4 : Caméras virtuelles

Le fichier code source ParametrageCamera.cpp contient un programme C+OpenGL complet réalisant la modélisation géométrique d'une scène et organisant son affichage écran. Cette scène est constituée de 64 cubes de coté 0.5 placés en 4 plans de 4x4 cubes de façon à occuper un volume cubique de coté 7.0 centré sur l'origine du repère de modélisation. Les cubes sont colorés en fonction de leur position dans la scène. L'affichage est réalisé en projection parallèle orthographique de façon à ce que l'intégralité de la zone d'affichage de la fenêtre soit utilisée pour le viewport OpenGL. On rappelle que la direction de visualisation est la direction -z.
Télécharger et compiler ce fichier. Vérifier la bonne exécution de l'exécutable ainsi obtenu.

a) Lorsque la fenêtre de visualisation est modifiée par l'utilisateur pour adopter une résolution en x différente de la résolution en y, les objets affichés sont déformés.

 

Résoudre ce problème de façon que cette déformation disparaisse et que la scène reste intégralement visible quel que soit le ratio résolution en x / résolution en y.

  

b) Modifier le code source pour que l'affichage ne soit plus réalisé en projection parallèle orthographique mais en projection en perspective. On placera la caméra virtuelle en position (0.0,0.0,100.0). On l'orientera de façon qu'elle regarde l'origine du repère de modélisation (sur laquelle la scène est centrée). On choisira la direction y comme direction de la verticale.
Il convient ici d'utiliser la fonction gluPerspective à la place de la fonction glOrtho (dans la fonction reshape) et d'ajouter un appel à la fonction gluLookAt dans la fonction display en plaçant cet appel juste avant l'appel à la fonction scene de façon que les coordonnées spécifiées en paramètres de gluLookAt soient considérées dans le même repère que celui associé à la scène, à savoir le repère de modélisation. On choisira les paramètres d'appel du gluPerspective et du gluLookAt de façon réfléchie (autant que possible pas d'essai "pour voir"). Rappel : Les paramètres d'appel de ces deux fonctions sont généralement liés.

c) Modifier une nouvelle fois le code source pour que la caméra virtuelle soit maintenant placée en position (0.0,0.0,10.0).

  

d) Modifier une dernière fois le code source pour qu'il soit possible de contrôler la position de la caméra en utilisant le clavier:
 - Up et Down pour la déplacer en y,
 - Right et Left pour la déplacer en x,
 - Page up et Page down pour la déplacer en z.
Elle reste orientée vers l'origine du repère de modélisation.

   

Question supplémentaire: On a placé l'appel à gluLookAt entre les appels aux fonctions glLightfv et scene. Déplacer l'appel à gluLookAt juste avant l'appel à glLightfv et tester le programme ainsi obtenu. La scène affichée est géométriquement identique mais les couleurs issus des calculs d'éclairage sont différents. Pourquoi?

   

Solutions

 

GLUT

Parametrage d'une caméra OpenGL (a)

Parametrage d'une caméra OpenGL (b)

Parametrage d'une caméra OpenGL (c)

Parametrage d'une caméra OpenGL (d)

TP n°5 : Plaçage de texture

L'archive zip ChargementImagePNG.zip contient les fichiers "code source" d'une librairie de gestion de fichiers "image" au format png accompagnés d'un exemple d'utilisation sous la forme d'une fonction main tentant deux chargements d'image successifs : Test.png et Emojis.png.

Plus précisément, une fonction d'importation et une fonction d'exportation sont décrites dans le fichier ChargePngFile.h.
La fonction d'importation prend en paramètre le nom du fichier à importer et deux pointeurs sur entier destinés à récupérer la résolution en x et la résolution en y de l'image importée. Elle retourne un pointeur sur unsigned char correspondant au tableau d'octets issu de l'importation (NULL si échec). Le tableau retourné est alloué dynamiquement par malloc et se doit d'être libéré par free après utilisation. Il contient les composantes RVB des pixels codées sur 8 bits (1 octet) et entrelacées dans l'ordre rouge, vert, bleu si le fichier image importé était un fichier au format png 24 bits entrelacé.

a) Télécharger et désarchiver ce fichier zip.
  - Windows : Ouvrir la solution Visual Studio accompagnant les fichiers source. Compiler, exécuter et vérifier la bonne exécution de l'exécutable obtenu.
  - Linux : Ne conserver que le fichiers source c, cpp et h dans leurs répertoires respectifs ainsi que le fichier Emojis.png présent dans le répertoire bin. Au moyen du gestionnaire de projet de développement que vous avez l'habitude d'utiliser, créer un projet incluant l'ensemble des fichiers c et cpp fournis et générant l'exécutable dans le répertoire bin. Compiler, exécuter et vérifier la bonne exécution de l'exécutable obtenu.

b) Développer un programme OpenGL permettant d'afficher une scéne composée d'un rectangle de coté 7.5 x 5.0. On pourra utiliser comme base le code développé au cours du TP n°4.

c) Modifier le code source de la question (b) pour que le rectangle soit muni d'une texture le recouvrant entièrement utilisant l'image contenue dans le fichier Emojis.png.

 

d) Reprendre la fonction de modélisation de cylindre de l'exercice n°2 du TD n°3 pour y ajouter les instructions permettant de le recouvrir d'une texture. Dans le programme de la question (c), remplacer le rectangle par un cylindre de hauteur 5.0 et de rayon 2.5.

 

Solutions

 

GLUT

Plaçage de texture

Utiliser plusieurs textures

Les programmes ci-dessous montrent l'utilisation de plusieurs textures pour dessiner un cube où chacune des 6 faces est texturée au moyen d'une image différente de celles des 5 autres faces.
Le premier programme est une simple adaptation du programme de la question (c). Le second programme montre comment installer les textures en mémoire graphique au cours d'une première phase pour ensuite les utiliser à la demande de façon rapide.

  

 

GLUT

Plaçage de textures multiples (chargement à la demande)

Plaçage de textures multiples (chargement préalable)

Epreuve n°1 : Modélisation géométrique

Sujet

Question 1

a) 6 types de surfaces existent : GL_POLYGON, GL_TRIANGLES, GL_QUADS, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN et GL_QUAD_STRIP.

b) Les normales étant utilisées pour les calculs d'éclairage, celles-ci doivent impérativement être spécifiées pour que ceux-ci s'opérent correctement.

Question 2

La façon la plus simple de modéliser la facette carrée trouée demandée consiste à utiliser un GL_QUAD_STRIP formé de 4 quadrilatères (10 vertices). Les bords du GL_QUAD_STRIP sont constitués des bords intérieurs et extérieurs. Les arêtes de recollement sont constituées des "diagonales" de la facette trouée. Les deux premiers et deux derniers vertices sont identiques de façon à fermer le GL_QUAD_STRIP.

 

 

Question 3

Le cube schématisé est constitué de 12 "boites" parallélépipédiques rectangulaires. Une recherche des éléments pouvant être reproduits permet de déterminer qu'une structure en U formée de 3 boites peut être générée 4 fois avec une rotation de 90° entre chaque instanciation. Une fonction est donc développée pour modéliser cette structure. Pour faciliter la modélisation des boites, on aura intérêt à créer une fonction ad hoc avec passage en paramètres des largeur, hauteur et profondeur.

 

 

Solutions

 

GLUT

Epreuve de TD n°1

TP n°6 : Lumières et matériaux

Le fichier source LumieresEtMaterielBase.cpp implante un programme d'affichage OpenGL dans lequel, à l'exception d'une, toutes les instructions spécifiques à la gestion des matériaux et des lumières ont été omises. L'instruction conservée se trouve dans la fonction init. Elle a pour but de supprimer (configurer à noir) la lumière ambiante existant par défaut au sein d'OpenGL (configurée à (0.2,0.2,0.2,1.0)) en plus des lumières classiques (GL_LIGHT0 à GL_LIGHT7).
Ce programme implante la modélisation géométrique de deux scènes. La première est composée de 3 tores. La seconde ne comporte qu'un cube. On notera toutefois que, dans le but d'améliorer les calculs d'illumination, le cube est modélisé de façon à intégrer une décomposition de chacune des 6 faces en un maillage de 100x100 facettes élémentaires carrées. La touche 's' permet de switcher entre les deux scènes. La touche Espace permet de switcher entre les modes d'affichage plein et fil de fer.
Ce programme implante une fonctionnalité d'animation de la scène par rotation autour d'elle-même. Cette animation peut être activée/désactivé au moyen de la touche 'a'. La touche F2 permet de ramener la scène à sa configuration de rotation initiale.
Ce programme intègre des appels à des fonctions actuellement vides destinées à isoler les portions de code OpenGL dédiées à la configuration des lumières et des matériaux utilisés :
  - static void configurationLumieres(void) : configuration des lumières,
  - static void configurationMaterielTore1(void) : configuration du matériel du premier tore,
  - static void configurationMaterielTore2(void) : configuration du matériel du deuxième tore,
  - static void configurationMaterielTore3(void) : configuration du matériel du troisième tore,
  - static void configurationMaterielCube(void) : configuration du matériel du cube.

A noter : Dans la fonction display, les fonctions OpenGL glPushAttrib et glPopAttrib sont utilisées pour sauvegarder dans une pile ad hoc et restaurer de façon rapide l'intégralité de la configuration des lumières et du matériel. Le paramètre de glPushAttrib dédié à cette sauvegarde est GL_LIGHTING_BIT.

 

 

Le but du TP consiste à placer les instructions de configuration des calculs d'illumination dans le respect des questions posées.

a) Activer l'utilisation des calculs d'éclairage.

 

 

b) Activer et configurer la lumière 0 selon les caractéristiques suivantes:
  - Lumière ponctuelle placée en position (2.0,2.0,2.0)
  - Emission diffuse rouge
  - Pas d'émission spéculaire
  - Pas d'émission ambiante

 

 

c) Désactiver la lumière 0. Activer et configurer la lumière 1 selon les caractéristiques suivantes:
  - Lumière directionnelle de direction d'incidence (-2.0,0.0,4.0)
  - Emission diffuse verte
  - Emission spéculaire blanche
  - Pas d'émission ambiante

 

 

d) Désactiver la lumière 1. Activer et configurer la lumière 2 selon les caractéristiques suivantes:
  - Spot placé en position (-2.0,-2.0, 10.0) et de direction d'éclairage (3.0, 3.0,-10.0)
  - Spot d'ouverture globale égale à 40°
  - Emission diffuse bleue
  - Emission spéculaire jaune
  - Pas d'émission ambiante

 

 

e) Activer simultanément les lumières 0, 1 et 2.

 

 

f) On aura remarqué que les émissions spéculaires des questions (c) et (d) semblent ne pas produire de résultat à l'écran. Ceci s'explique par le fait que le matériel par défaut d'OpenGL ne génère pas de réponse à ce type d'éclairage.
Configurer le matériel des tores et du cube pour qu'il génère une réponse spéculaire blanche avec une réflectivité de 64.0 (valeur intermédiaire entre les valeurs générant les réponses maximales et minimales : 0.0 et 128.0).

 

 

g) Modifier le matériel des tores selon les caractéristiques suivantes:
  - Tore n°1: pas de réflexion diffuse, réflexion spéculaire jaune, réflectivité de 15.0, pas de réflexion ambiante, pas d'émission
  - Tore n°2: réflexion diffuse jaune, réflexion spéculaire rouge, réflectivité de 100.0, pas de réflexion ambiante, pas d'émission
  - Tore n°3: réflexion diffuse rouge, réflexion spéculaire bleue, réflectivité de 64.0, pas de réflexion ambiante, émission grise (gris moyen)

 

Questions supplémentaires

1) Tester la possibilité offerte par OpenGL de créer des lumières ponctuelle ou spot intégrant une atténuation de l'éclairage fonction de la distance entre la lumière et le point qu'elle éclaire : atténuation linéaire, atténuation quadratique.
Rappel : par défaut, il n'y a pas d'atténuation pour ces deux types de lumières.

2) Réaliser une animation où les lumières tournent autour de l'origine et la scène reste immobile.

3) Tester l'influence du nombre de facettes de modélisation sur les éclairages et la vitesse d'animation.

4) Tester l'utilisation de valeurs supérieures à 1.0 pour les coefficients des "couleurs" pour les lumières et les matériels.
Rappel : Utiliser des coefficients numériques supérieurs à 1.0 est tout à fait admis pour les lumières (notion d'énergie). Ce n'est pas le cas pour les matériels.

Solutions

 

GLUT

Lumières et matériel

TP n°7 : Lancement du projet

Description du travail à réaliser

De façon à faciliter le développement du projet, réaliser le test des deux fichiers sources suivants:
  - DeuxFenetres.cpp
  - TestMemoire.cpp

Le fichier DeuxFenetres.cpp illustre la possibilité offerte par GLUt de gérer plusieurs fenêtres d'affichage OpenGL. La fonction int glutCreateWindow(void) permet de créer les fenêtres. Elle retourne un handle entier à mémoriser permettant de garder une référence sur chaque fenêtre ouverte. Les fenêtres sont individuellement munies de leurs fonctions display, reshape, keyboard, special, mouse, ... qui permettent de gérer leur fonctionnement événementiel. Attention, les fenêtres partagent une et une seule fonction idle. Chaque fenêtre peut recevoir en propre un ordre de rafraichissement en utilisant la fonction void glutPostWindowRedisplay(int f) où f est le handle de la fenêtre à rafraîchir. Dans chaque fenêtre est géré un environnement OpenGL complet pouvant être intégralement paramétré : lumières, matériaux, textures, caméra, options d'affichage, ...

Le fichier TestMemoire.cpp montre une technique spécifique à VisualStudio permettant de contrôler les opérations de gestion dynamique de la mémoire : new, delete, calloc, malloc, free,... Le but de cette technique est de faciliter la détection des problèmes souvent constatés : double free ou delete, pas de free pour un *alloc, pas de delete pour un new, ... Il s'agit d'un équivalent à valgrind. Attention, les bibliothèques de compatibilté mfc doivent être installées (option non activée par défaut au moment de l'installation de VisualStudio) pour que TestMemoire.cpp puisse être compilé et donc exécuté.
Pour que le contrôle soit réalisé, il est nécessaire que la compilation soit réalisée en mode "Debug" et que l'exécution soit lancée sous debugger. Les directives de compilation incluses dans le code source font que la compilation et l'exécution sont possibles sans problème en mode release ou bien si un autre compilateur que VisualStudio est utilisé. Le code est instrumenté au début avec un certain nombre de #include et dans la fonction main avec les lignes suivantes :
#if defined(WIN32) || defined(WIN64)
  #if defined(_DEBUG)
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    _crtBreakAlloc = 120;
  #endif
#endif

qui configurent l'outil d'analyse
(1) pour qu'à la fin d'exécution du programme sous debugger un rapport de l'utilisation dynamique de la mémoire soit établi et affiché dans la fenêtre "Sortie" de Visual Studio,
(2) pour qu'un point d'arrêt pour le debugger soit placé lors de la 120ème opération d'allocation dynamique de mémoire (new, malloc, calloc, ...).
Si on ne souhaite pas qu'un point d'arrêt soit réalisé, on pourra placer la ligne en commentaire.
La fenêtre de VisualStudio nommée "Pile des appels" permet de savoir où le point d'arrêt a été déclenché par le debugger.

a) Corriger le problème mémoire existant dans TestMemoire.cpp.

b) Ajouter une troisième fenêtre permettant de visualiser la scène depuis un 3ème point de vue (au choix).

Epreuve n°2 : Caméras virtuelles

Sujet

1a) Une projection parallèle orthographique est une projection planaire (plan de projection plan) caractérisée par le fait que la projection de chaque objet sur le plan de projection est réalisée selon un vecteur (une direction) unique et que ce vecteur projection unique est orthogonal au plan de projection.

1b) Non exhaustivement :
  - Les parallélismes existant dans la scène réelle sont retrouvés dans la scène affichée.
  - La taille des objets affichés ne dépend pas de leur position dans la scène.
    -> Tous les objets de même taille ont la même taille à l'écran.
    -> On peut utiliser la taille d'un objet à l'écran pour se faire une idée de sa taille réelle.
    -> On ne peut pas utiliser la taille d'un objet à l'écran pour se faire une idée de sa distance et donc de sa profondeur et de sa place dans la scène.
Ces propriétés sont appropriées aux situations d'affichage où la taille des objets doit être facilement interprétée à partir de leurs tailles à l'écran, où l'interprétation de la distance aux objets n'est pas nécessaire et où les parallélismes doivent être conservés. Exemple : dans un logiciel de modélisation géométrique.

1c) La fonction OpenGL dédiée à la configuration d'une projection parallèle orthographique est la fonction
void glOrtho(double xGauche,double xDroit,double yInferieur,double ySuperieur,double cMin,double cMax);
Elle configure une telle projection selon la direction -z en plaçant un plan de clipping vertical gauche en x=xGauche, un plan de clipping vertical droit en x=xDroit, un plan de clipping horizontal inférieur en y=yInferieur et un plan de clipping horizontal supérieur en y=ySuperieur. Ces quatre plans de clipping sont mappés sur les bords gauche, droit, inférieur et supérieur du viewport de visualisation. Les valeurs cMin et cMax définissent les "distances" en z par rapport à l'origine où sont placés les plans de clipping en profondeur. CMin et cMax peuvent être positifs ou négatifs.
Le volume de visualisation ainsi créé est un parallélépipède rectangle de diagonale (xGauche,yInferieur,-cMin)-(xDroit,ySuperieur,-cMax) dans lequel la projection se fait selon l'axe -z.

2a) Le rôle de la fonction gluPerspective est de configurer une caméra virtuelle de visualisation en perspective selon l'axe -z pour un observateur placé à l'origine. Elle permet de configurer l'angle d'ouverture vertical (fov ci-dessous, valeur en degrés), le ratio par lequel il faut multiplier l'angle d'ouverture vertical pour obtenir l'angle d'ouverture horizontal (ratio ci-dessous), la distance en z (valeur positive) en dessous de laquelle les objets à visualiser sont clippés (cMin ci-dessous) et la distance en z (valeur positive) au delà de laquelle les objets à visualiser sont clippés (cMax ci-dessous).
Son prototype est:
void gluPerspective(double fov,double ratio,double cMin,double cMax);
Application numérique : La distance entre le centre de la scène et la caméra est égale à sqrt((-2.0--4.0)2+(-4.0-6.0)2+(6.0--5.0)2) = sqrt(4.0+100.0+121.0) = sqrt(225.0) = 15.0. Le rayon de la scéne est de 5.0. L'angle d'ouverture vertical est égal à 2.0*asin(5.0/15.0) radians converti en degrés en multipliant par 180.0 et divisant par PI. Cette formule peut être directement intégrée dans le code. La valeur numérique est d'environ 39°.
Pour cMin on prend la distance entre le centre de la scène et la caméra et on retranche le rayon de la scène. Cela donne 15.0-5.0=10.0. Pour cMax on prend la distance entre le centre de la scène et la caméra et on ajoute le rayon de la scène. Cela donne 15.0+5.0=20.0. On a tout intérêt à ajuster ces valeurs d'un epsilon négatif pour cMin et positif pour cMax de façon à être certain que la scène n'est pas clippée en z.

2b) La fonction gluLookAt est utilisée pour résoudre le problème du placement et de l'orientation d'une caméra virtuelle de visualisation lorsque celle-ci n'est pas placée à l'origine ou n'est pas orientée selon l'axe -z. Son appel est réalisé entre la configuration de la caméra et la modélisation de la scène.
Cette fonction prend 9 valeurs double en paramètre. Les 3 premiers paramètres représentent la position (cx,cy,cz) de la caméra. Les valeurs à configurer seront donc (-4.0,6.0,-5.0). Les trois suivants représentent la position (vx,vy,vz) d'un point qui sera projeté au centre du viewport de visualisation. Il s'agit généralement d'un point situé au centre de la scène. On utilisera donc les valeurs (-2.0,-4.0,6.0). Enfin, les trois derniers définissent la direction (dx,dy,dz) qui sera projetée verticalement dans le viewport d'affichage. La verticale étant généralement l'axe y, on configurera (0.0,1.0,0.0).

2c) L'appel à gluLookAt peut être placé dans la fonction display juste avant la modélisation de la scène ou bien dans la fonction reshape après le glLoadIdentity en mode GL_MODELVIEW.

#ifndef M_PI
  #define M_PI 3.14159
#endif
#define EPSILON 1.0

static void reshape(int tx,int ty) {
  glViewport(0,0,tx,ty);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  double ratio =(double) tx/ty;
  gluPerspective(2.0*asin(5.0/15.0)*180/M_PI,ratio,10.0-EPSILON,20.0+EPSILON);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(-4.0,6.0,-5.0,-2.0,-4.0,6.0,0.0,1.0,0.0);
}

Solutions

 

GLUT

Epreuve de TD n°2

TP n°8 : Coordonnées homogènes

Le fichier CH3D.h est le fichier de déclaration d'une classe destinée à coder des coordonnées homogènes. Pour faciliter les opérations matricielles (TD n°5), le choix a été fait de ne pas utiliser en attribut 4 champs réels mais un tableau de 4 réels. Ce tableau est déclaré en public.

a) Développer le fichier CH3D.cpp implantant cette classe.
Le constructeur sans paramètre crée une position initialisée à l'origine. Le constructeur à 4 paramètres réels crée des coordonnées homogènes initialisées à ces valeurs. Le constructeur à paramètre unique de type pointeur sur CH3D crée une copie (un clone) de cet objet. La méthode void print(void) se contentera d'afficher sous forme textuelle sur une même ligne sans saut de ligne les valeurs des quatre réels contenus dans le tableau des coordonnées.

b) Développer les fichiers .h et .cpp d'une classe dérivée de CH3D permettant de coder des positions dans un espace à trois dimensions (4ème coordonnée égale à 1.0 en coordonnées homogènes). Cette classe sera nommée Pos3D. Elle contiendra les trois constructeurs :
  - Pos3D(void),
  - Pos3D(double px,double py,double pz),
  - Pos3D(Pos3D *p)
et un destructeur.
Le premier constructeur construit une position située à l'origine. Le deuxième construit la position de coordonnées (px,py,pz). Enfin, le dernier constructeur construit une copie (un clone) de la position p. Cette classe ne contient aucune méthode à part la méthode print directement héritée de CH3D.

c) Développer les fichiers .h et .cpp d'une classe dérivée de CH3D permettant de coder des directions dans un espace à trois dimensions(4ème coordonnée égale à 0.0 en coordonnées homogènes). Cette classe sera nommée Dir3D. Elle contiendra les quatre constructeurs suivants :
  - Dir3D(void),
  - Dir3D(double dx,double dy,double dz),
  - Dir3D(Dir3D *d),
  - Dir3D(Pos3D *pi,Pos3D *pf)
et un destructeur.
Le premier constructeur construit une direction orientée en -z. Le deuxième constructeur construit la direction de coordonnées (dx,dy,dz). Le troisième constructeur construit une copie (un clone) de la direction d. Le quatrième constructeur construit la direction pi vers pf. Cette classe ne contient aucune méthode à part la méthode print directement héritée de CH3D.

On donne le fichier Mathematiques1.cpp. Ce fichier contient un programme constitué d'une unique fonction void main(void) destinée à valider les développements que vous allez réaliser aux questions (d), (e) et (f). Vous devriez obtenir un affichage voisin de celui donné ci-dessous (valeurs identiques éventuellement formatées de façon différente).

d) Développer une méthode d'instance (méthode "classique") et une méthode de classe (méthode statique) permettant de calculer la distance existant entre une position et une autre position. Les méthodes développées doivent être compatibles avec les appels réalisés dans la fonction main du programme Mathematiques1.cpp.

e) Développer une méthode permettant de calculer la norme d'une direction. Développer une méthode permettant de normer une direction.

f) Développer une méthode d'instance et une méthode de classe permettant de calculer le produit scalaire d'une direction par une autre direction.

g) Développer une méthode d'instance et une méthode de classe permettant de calculer le produit vectoriel d'une direction par une autre direction.

Solutions

CH3D.h CH3D.cpp
Pos3D.h Pos3D.cpp
Dir3D.h Dir3D.cpp
Mathematiques1.cpp

Si on souhaite disposer d'une classe "Coodonnées Homogènes" permettant d'utiliser des attributs x, y, z et w de type réel tout aussi bien qu'un attribut c de type tableau de 4 réels avec concordance mémoire entre x et c[0], y et c[1], z et c[2] et w et c[3] (utilisation d'une union), on pourra substituer au fichier CH3D.h cette version de fichier CH3D.h.

Remarque : Dans un but d'efficacité à l'exécution, les solutions proposées ci-dessus ne sont pas programmées en respectant les recommandations usuelles de la programmation orientée objet (protection des attributs, protection des types, méthodes private/protected, ...). On trouvera ci-dessous une implantation respectant ces recommandations.

TD n°5 : Transformations géométriques

On souhaite implanter les outils informatiques qui nous permettront de réaliser des transformations géométriques.

a) Implanter un classe mère TG3D permettant de coder des transformations géométriques génériques en coordonnées homogènes.
On munira TG3D des deux constructeurs :
  - TG3D(void),
  - TG3D(TG3D *tg)
et d'un destructeur.
Le constructeur sans paramètre construit l'identité. Le constructeur à paramètre unique de type pointeur sur TG3D crée une copie (un clone) de cet objet.
On créera aussi une méthode void print(void) d'affichage texte des composantes.

b) Dériver de la classe TG3D une classe fille Tr3D permettant de coder des transformations géométriques de type translation.
On munira Tr3D des quatre constructeurs :
  - Tr3D(void),
  - Tr3D(double tx,double ty,double tz),
  - Tr3D(Dir3D *d),
  - Tr3D(Tr3D *tr)
et d'un destructeur.
Le constructeur sans paramètre construit l'identité. Le constructeur à 3 paramètres de type double construit la translation de vecteur (tx,ty,tz). Le constructeur à paramètre unique d de type pointeur sur Dir3D construit la translation de vecteur défini par les composantes de d. Le constructeur à paramètre unique tr de type pointeur sur Tr3D crée une copie (un clone) de cet objet. Cette classe ne contient aucune méthode à part la méthode print directement héritée de TG3D.

c) Dériver de la classe TG3D une classe fille Rt3D permettant de coder des transformations géométriques de type rotation.
On munira Rt3D des quatre constructeurs :
  - Rt3D(void),
  - Rt3D(double alpha,double ax,double ay,double az),
  - Rt3D(double alpha,Dir3D *d),
  - Rt3D(Rt3D *rt)
et d'un destructeur.
Le constructeur sans paramètre construit l'identité. Le constructeur à 4 paramètres de type double construit la rotation d'angle alpha degrés autour de l'axe (ax,ay,az) passant par l'origine. Le constructeur à paramètres alpha et d de types respectifs double et pointeur sur Dir3D construit la rotation d'angle alpha degrés autour de l'axe de direction définie par d et passant par l'origine. Le constructeur à paramètre unique rt de type pointeur sur Rt3D crée une copie (un clone) de cet objet. Cette classe ne contient aucune méthode à part la méthode print directement héritée de TG3D.

d) Dériver de la classe TG3D une classe fille Sc3D permettant de coder des transformations géométriques de type zoom (scale).
On munira Sc3D des trois constructeurs :
  - Sc3D(void),
  - Sc3D(double rx,double ry,double rz),
  - Sc3D(Sc3D *sc)
et d'un destructeur.
Le constructeur sans paramètre construit l'identité. Le constructeur à 3 paramètres de type double construit le zoom de rapports (rx,ry,rz). Le constructeur à paramètre unique sc de type pointeur sur Sc3D crée une copie (un clone) de cet objet. Cette classe ne contient aucune méthode à part la méthode print directement héritée de TG3D.

e) On souhaite réaliser la transformation d'une position ou d'une direction codée en coordonnées homogènes par une transformation géométrique. Implanter une méthode d'instance permettant de réaliser cette opération.

f) On souhaite réaliser la composition de deux transformations géométriques. Implanter une méthode d'instance permettant de réaliser cette opération.

Solutions

TG3D.h TG3D.cpp
Tr3D.h Tr3D.cpp
Rt3D.h Rt3D.cpp
Sc3D.h Sc3D.cpp
Mathematiques2.cpp

Les solutions ci-dessous ont été réalisées avec respect des recommandations usuelles du développement orienté objet :
  - protection des types pour éviter la possibilité de faire endosser le comportement lié à une classe par un objet qui n'implante pas cette classe,
  - protection des attributs (attributs private et protected, getters et setters),
  - méthodes private et protected,
  - non utilisation de fonctionnalités purement liées au langage C :
    - union anonymes,
    - ...
  - ...

CH3D.h CH3D.cpp
Pos3D.h Pos3D.cpp
Dir3D.h Dir3D.cpp
TG3D.h TG3D.cpp
Tr3D.h Tr3D.cpp
Rt3D.h Rt3D.cpp
Sc3D.h Sc3D.cpp
Mathematiques3.cpp

TD n°6 : Courbes B-Splines

a) On dispose d'un tableau de quatre Pos3D (voir TP n°8). On souhaite déterminer la position, pour une valeur t donnée, d'un point situé sur la courbe B-Spline définie par la ligne polygonale constituée de ces quatre positions.


Ligne polygonale

 
Positions à t = 0.0 et t = 1.0


Toutes les positions

Développer une fonction ad hoc prenant en paramètres le tableau g des quatre Pos3D, la valeur de t (0.0 <= t <= 1.0), la matrice de base mb utilisée et le pointeur p sur la Pos3D résultat du calcul :
void determinationPositionSurBSpline(Pos3D **g,double t,double mb[4][4],Pos3D *p);

b) On dispose d'un tableau de Pos3D. Le nombre de ces positions est au moins égal à quatre. On souhaite tracer la courbe B-Spline par morceaux définie par la ligne polygonale constituée de ces positions. Pour ce faire, on souhaite calculer n positions de lissage (n >= 2) uniformément réparties.
Développer une fonction ad hoc.


B-Spline par morceaux

Solutions

 

GLUT

Courbe B-Spline par morceaux

Epreuve n°3 : Matériels et lumières

Sujet

TP n°9 : Courbes lissées

On considère la liste de positions trois dimensions suivante :
( 6.5, 4.9,-3.00), ( 7.0, 5.0,-3.00), ( 7.5, 4.9,-2.00),
( 8.0, 4.6, 0.00), ( 7.5, 4.4, 2.00), ( 7.0, 4.2, 3.50),
( 6.0, 3.8, 4.00), ( 5.0, 2.8, 4.00), ( 4.0, 1.8, 4.00),
( 3.0, 0.8, 4.00), ( 0.0, 0.0, 4.00), (-1.4, 0.7, 3.75),
(-2.0, 2.0, 3.50), (-1.4, 3.3, 3.25), ( 0.0, 4.0, 3.00),
( 1.4, 3.3, 2.75), ( 2.0, 2.0, 2.50), ( 1.0, 0.7, 2.25),
(-1.0, 0.0, 2.00), (-2.4, 0.7, 1.75), (-3.0, 2.0, 1.50),
(-2.4, 3.3, 1.25), (-1.0, 4.0, 1.00), ( 0.4, 3.3, 0.75),
( 1.0, 2.0, 0.50), ( 0.0, 0.7, 0.25), (-2.0, 0.2, 0.00),
(-7.0, 0.0, 1.50), (-8.0, 0.0,-1.30), (-7.0, 0.3,-1.90),
(-6.0, 1.8,-2.40), (-4.5, 4.9,-2.40), (-3.0, 3.2,-2.40),
( 0.5, 2.4,-2.80), ( 3.5, 4.4,-2.80), ( 4.5, 4.7,-2.90),
( 5.5, 4.8,-3.00).

On souhaite dessiner une courbe lissant la ligne polygonale formée par ces 37 positions.

a) Implanter une fonction de lissage par B-Spline par morceaux applicable à un ensemble de points de contrôle, pour une matrice de base particulière et générant n points répartis uniformément sur la courbe.


Courbe B-Spline par morceaux, matrice de base NRUBS
Mise en évidence des morceaux


Courbe B-Spline par morceaux, matrice de base Catmull-Rom
Mise en évidence des morceaux

b) Implanter un programme OpenGL complet permettant de dessiner simultanément avec des couleurs différentes:
  - la ligne polygonale définie selon les 37 positions ci-dessus,
  - la courbe B-Spline par morceaux obtenue en utilisant la matrice de base NRUBS et ces 37 points en tant que points de contrôle,
  - la courbe B-Spline par morceaux obtenue en utilisant la matrice de base Catmull-Rom et ces 37 points en tant que points de contrôle.

c) Implanter une fonction de lissage par courbe de Bézier applicable à un ensemble de points de contrôle et générant n points répartis uniformément sur la courbe.

d) Modifier le programme de la question (b) pour dessiner en plus la courbe de Bézier contrôlée par les 37 points.



Blanc : Ligne polygonale
Magenta : B-Spline NRUBS
Cyan : B-Spline Catmull-Rom
Jaune : Courbe de Bezier

Solutions

 

GLUT

Courbes B-Spline par morceaux et courbe de Bézier

TD n°7 : Remplissage d'une facette triangulaire

Implanter une fonction de remplissage 2D d'un triangle.

Méthode: Remplir un triangle en 2D peut être réalisé en traçant toutes les lignes horizontales de pixels délimitées par ses bords gauche et droit. Il convient donc de déterminer les abscisses extrèmes de ces lignes horizontales pour chacun des y compris entre ymin et ymax où ymin (resp. ymax) est la valeur minimale (resp. maximale) des ordonnées des 3 sommets de définition du rectangle.

Ainsi, deux tableaux xd et xg sont calculés dont les indices correspondent aux ordonnées y des lignes de pixels.
Le calcul de ces deux tableaux est réalisé par implantation et adaptation de l'algorithme de Bresenham pour le tracé de segments de droite. Cet algorithme adapté est appliqué aux trois bords du triangle rempli.

Solutions

 

GLUt

Remplissage d'un triangle 2D

TP n°10 : TP Projet

TP n°11 : Calcul de la direction des rayons réfléchis et transmis dans le cadre d'un algorithme de lancer de rayons

L'implantation d'un algorithme de lancer de rayons nécessite l'implantation d'un certain nombre de fonctions de calcul. Par exemple, pour chaque type d'objet graphique géré, il sera nécessaire de tester s'il existe une intersection entre un objet graphique de ce type et un rayon. Un autre exemple de fonctions devant être implantées sont les fonctions nécessaires aux calculs d'illumination : diffusion, réflexions spéculaires, ...
Ce TP s'attache au calcul des directions des rayons issus de la décomposition d'un rayon lumineux incident à l'interface entre le milieu incident et un autre milieu. Ces rayons sont au nombre de deux : les rayons de réflexion et de transmission.

Vous trouverez dans le fichier RayTracing.zip l'ensemble des fichiers sources constitutifs d'un programme permettant d'afficher des scènes constituées de sphères en utilisant un algorithme de lancer de rayons. Ces sphères peuvent être diffusantes, transparentes et réfléchissantes. Plus exactement ce programme ouvre deux fenêtres. La première réalise l'affichage de façon habituelle en utilisant OpenGL. La seconde fenêtre permet l'affichage de la même scène, mais en utilisant le lancer de rayons. La touche Enter permet de lancer l'affichage en lancer de rayons. La touche Espace permet de changer de scène. La souris peut être utilisée dans la fenêtre OpenGL pour faire tourner la scène sur elle-même. Il est alors possible de relancer le calcul en lancer de rayons.

a) Télécharger le fichier RayTracing.zip. Réaliser l'extraction de l'ensemble des fichiers qu'il contient. Intégrer ces fichiers à un projet de développement permettant la compilation en utilisant OpenGL et GLUt. Compiler le projet. La compilation n'aboutit pas car deux méthodes ont été supprimées : une première pour calculer la direction du rayon réfléchi, une deuxième pour calculer la direction du rayon transmis.

b) Déterminer la classe dans laquelle ces méthodes manquent et leurs entêtes.

c) Développer ces deux méthodes pour obtenir un programme fonctionnel. Vous vous reporterez au cours sur le lancer de rayons pour trouver les formules de calcul.

Hiérarchie de classes

Vecteur4     CoordonneesHomogenes3D     Position3D
       
             
            Dimension3D
           
             
Matrice4x4     TransformationGeometrique3D     Translation3D
       
             
      MatriceDeBase     Rotation3D
         
             
            Scale3D
           
             
            LookAt
           
             
Rvb     Couleur      
         
             
      Energie      
           
             
             
Lumiere     LumierePonctuelle     LumiereSpot
       
             
      LumiereDirectionnelle      
           
             
Materiel            
           
             
Objet     Sphere