Lancer de rayons : Introduction
1. Structure du projet
Téléchargez et décompressez l’archive :
$ wget http://www.labri.fr/perso/pbenard/teaching/pghp/ressources/pghp_raytracer.zip
$ unzip pghp_raytracer.zip
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
- 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
etsprintf
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 :
Viewer
: l'interface utilisateur.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 deShape
, représente une sphère.Plane
: dérive deShape
, représente un plan infini.Mesh
: dérive deShape
, 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 compilation à l'extérieur du dossier contenant les sources, configurez et compilez :
$ mkdir build
$ cd build
$ cmake ../pghp_raytracer
$ make -j6
Release
. Pour le compiler en mode Debug
(pour pouvoir utiliser GDB), configurez le projet avec la ligne de commande :
$ cmake ../pghp_raytracer -DCMAKE_BUILD_TYPE=Debug
À l'issue de la compilation, vous obtiendrez un exécutable pghp_raytracer.
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.
2.1. Syntaxe
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 :
<material type="diffuse">
<color name="diffuseColor" value="0.8, 0.0, 0.0" />
</material>
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é :
Diffuse::Diffuse(const PropertyList &propList)
{
m_diffuseColor = propList.getColor("diffuseColor",Color3f(0.2));
}
REGISTER_CLASS(Diffuse, "diffuse")
Les propriétés suivantes sont actuellement reconnues par l'analyseur syntaxique :
1
2
3
4
5
6
7
<string name="property name" value="arbitrary string"/>
<boolean name="property name" value="true/false"/>
<float name="property name" value="float value"/>
<integer name="property name" value="integer value"/>
<vector name="property name" value="x, y, z"/>
<point name="property name" value="x, y, z"/>
<color name="property name" value="r, g, b"/>
1
2
3
4
5
6
7
<transform name="property name">
<translate value="x, y, z"/>
<scale value="x, y, z"/>
<rotate axis="x, y, z" angle="deg."/>
<rotate value="q1, q2, q3, q4"/>
<lookat origin="x,y,z" target="x,y,z" up="x,y,z"/>
</transform>
Voici un extrait XML définissant une caméra :
1
2
3
4
5
6
7
8
9
<camera type="perspective">
<float name="fieldOfView" value="45.0" />
<integer name="width" value="400"/>
<integer name="height" value="400"/>
<integer name="samples" value="1"/>
<transform name="toWorld">
<lookat target="-11, 5, 0" origin="15, 1, 0" up="0, 1, 0"/>
</transform>
</camera>
2.2. Utilisation
Lorsque la touche 'l' est pressée, le Viewer
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" :
$ ./pghp_raytracer troisSpheres.scn