Brett Ridel

About Me

-
Publications
-
Teaching
-
The Revealing Flashlight

Introduction

1. Structure du projet
Téléchargez et décompressez l’archive :
$ wget http://www.labri.fr/perso/bridel/teaching/SIRE/raytracing/sire_raytracer.zip
$ unzip sire_raytracer.zip
Une base de code conséquente est fournie afin que vous n'ayez à vous concentrer que sur les parties graphiques. Tout au long des TD, de nombreuses classes seront à compléter, certaines à créer de toutes pièces, tandis que d'autres ne seront utilisées complètement qu'à la fin du projet.

1.1. Arborescence

Le projet est organisé selon cette arborescence :
  • include : contient les fichiers d'entête
  • src : continent le code source C++ principal
  • ext : contient les dépendances externes
  • shaders : contient les shaders GLSL pour l'affichage OpenGL
  • CMakeLists.txt : fichier CMake spécifiant comment compiler le projet
  • CMakeConfig.txt : fichier CMake additionnel pour compiler les dépendances externes, vous ne devriez pas avoir à le modifier.
Plusieurs dépendances externes sont utilisées, en voici une présentation succincte :
  • Eigen est une bibliothèque C++ d'algèbre linéaire. Elle sera utilisée pour la représentation et manipulation de matrices, vecteurs, transformations géométriques et résolution de systèmes d'équations ( documentation ).
  • pugixml est un analyseur syntaxique XML utilisé pour charger les fichiers de scène.
  • OpenEXR est un format de fichier standardisé utilisé pour stocker des images à grande gamme dynamique ( HDR ).
  • NanoGUI est une bibliothèque C++ qui permet de créer une fenêtre OpenGL (via GLFW ) et des contrôles utilisateurs.
  • tinyformat est l'implémentation en C++11 de printf et sprintf avec sûreté de typage.
  • filesystem est une classe pour manipuler les chemins de façon transparent sous Linux, Windows et Mac OS X.
  • lib3ds est une bibliothèque pour charger des maillages au format 3D-Studio ".3DS".
  • tinyobjloader est une bibliothèque pour charger des maillages au format Wavefront OBJ.
1.2. Architecture logicielle
Parcourez les fichiers d'entête pour comprendre la structure générale du projet. En voici les classes principales :
  • RenderingWidget : le visualiseur/débogueur OpenGL.
  • Scene : décrit une scène complète.
    • Shape : classe abstraite dont dérivent les entités géométriques de la scène.
      • Sphere : dérive de Shape, représente une sphère.
      • Plane : dérive de Shape, représente un plan infini.
      • Mesh : dérive de Shape, représente un maillage triangulaire.
    • Material : la définition complète du matériau d'un objet.
    • Light : classe abstraite dont dérivent les sources lumineuses.
    • Integrator : classe abstraite dont dérivent les méthodes d'intégration de l'équation du rendu.
    • Camera : la caméra de la scène d'où on va créer l'image.
    • Transform : contient une transformation de l'espace 3D en coordonnée homogènes et son inverse, ainsi que des opérateurs pour transformer correctement vecteurs, positions et normales.
  • Ray : représente un rayon en 3D (point d'origine et direction).
  • Hit : regroupe toutes les informations sur l'intersection d'un rayon avec un objet.
Étant donné le nombre important de fichiers sources, je vous recommande vivement d'utiliser un IDE comme, par exemple,QtCreator. Le projet n'utilise certes pas la bibliothèque logicielle Qt, mais QtCreator conserve les avantages de supporter nativement CMake et de proposer une interface graphique intuitive au dessus de GDB.
1.3. Compilation
CMake est utilisé pour gérer la compilation du projet ( tutoriel, documentation). Créez un répertoire de build à l'extérieur du dossier contenant les sources, configurez, et compilez :
$ mkdir build
$ cd build
$ cmake ../sire_raytracer
$ make -j6
La première compilation sera longue étant donné le nombre important de dépendances externes. Par défaut le projet est compilé en mode Release. Pour le compiler en mode Debug (pour pouvoir utiliser GDB), configurez le projet avec la ligne de commande :
$ cmake ../sire_raytracer -DCMAKE_BUILD_TYPE=Debug
À l'issue de la compilation, vous obtiendrez un exécutable sire_raytracer qui assurera deux fonctions :
  • la synthèse d'images par lancer de rayon (que vous allez implémenter en grande partie),
  • un afficheur de fichier OpenEXR effectuant un tone-mapping minimaliste (conversion en sRGB et contrôle de l'exposition).
2. Fichiers de scène
Pour faciliter les tests et les comparaisons, les scènes sont décrites par des fichiers au format XML (extension ".scn"). Ce type de fichiers permet de représenter une grande variété de données avec un formalisme rigoureux. Il permet également de facilement extraire et transformer cette information. Le langage de description de la scène peut être vu comme un plan de construction : au fur et à mesure que l'analyseur syntaxique parcoure le fichier XML, il instancie les objets composant la scène.

Chaque tag XML représente soit un objet, soit une propriété. Les objets correspondent directement à des instances de classes C++ qui seront allouées sur la pile. Les propriétés sont des paramètres passés au constructeur de l'objet lors de l'instanciation. Par exemple, ce bloc XML permet de créer un matériau diffus rouge :
'; highlight_xml($xml_str); ?>
Le tag <material> va entraîner la création d'un objet Material, et l'attribut diffuse indique quelle classe fille de Material doit être utilisé. Le tag <color> va créer une propriété nommée diffuseColor qui sera passée à son constructeur. Si vous ouvrez le fichier "src/material.cpp", vous verrez que le constructeur recherche cette propriété :
'; highlight_xml($str); ?>
La macro suivante permet de faire le lien automatiquement entre l'attribut diffuse du XML et le code C++ :
'; highlight_xml($str); ?>
Les propriétés suivantes sont actuellement reconnues par l'analyseur syntaxique :
'; highlight_xml($str); ?>
Les transformations de l'espace possèdent cependant une syntaxe spécifique :
'; highlight_xml($str); ?>
La transformation résultante est l'application de cette séquence d'opérations à la matrice identité.

Voici un extrait XML définissant une caméra :
'; highlight_xml($str); ?>
Attention, la Camera instanciée dans la classe Sceneest distinct de la caméra OpenGL qui affiche la scène dans le RenderingWidget. Néanmoins, au chargement de la scène, les deux caméras partagent les même attributs et la fenêtre possède la même résolution que l'image finale. À l'exécution, vous pouvez appuyez sur la touche 'c' pour copier la caméra OpenGL vers celle de la scène, ce qui vous permet d'avoir une représentation OpenGL de la scène qui va être rendue. (Attention, la résolution de la caméra correspondra alors à nouveau celle de la fenêtre.)

Lorsque la touche 'l' est pressée, le RenderingWidget ouvre une fenêtre pour choisir une fichier se terminant par l'extension ".scn" et charge le fichier de scène sélectionné (méthode loadScene). Vous pouvez également déposer directement le fichier sur la fenêtre pour obtenir le même résultat. Enfin, vous pouvez passer le fichier en ligne de commande à l'exécutable pour le charger au démarrage. Testez par exemple avec le fichier "troisSpheres.scn" :

$ ./sire_raytracer troisSpheres.scn

Vous devriez obtenir le rendu OpenGL suivant :

Trois spheres

Remerciements

Ce projet est basé sur celui de Pierre Bénard.