MIM Images
année 2003-2004
http://www710.univ-lyon1.fr/~jciehl/
TD7 - Visualisation d'Arbres de Construction
(Partie 2)
Lancer de rayons récursif,
Eclairement Global
L'objectif de ce TD est d'améliorer la visualisation
des arbres de construction du TD 6. Dans un premier temps, le lancer de rayons
sera étendu afin de calculer les réflexions et éventuellement
les réfractions (lancer de rayons récursif). Il est donc nécessaire
de modifier la description des objets en leur ajoutant un attribut matière.
Le calcul de l'éclairement direct doit aussi être adapté
à la matière de l'objet (un miroir ne réfléchit
pas la lumière comme un objet diffus ...). Il sera ensuite possible
d'utiliser le lancer de rayon récursif pour calculer une première
approximation de l'éclairement global.
Installez ce squelette dans
un répertoire. Il contient une correction du TD6 ainsi que la définition
des matières et des sources étendues.
Partie 1. Matières et interactions
Les matières sont décrites formellement
par une fonction à 6 dimensions qui est difficilement manipulable.
Une approximation courante consiste à utiliser une somme pondérée
de trois comportements idéaux : parfaitement diffus, parfaitement
spéculaire et réfléchissant (surface rugueuse, effet
"glossy", Phong). Ces comportements sont des fonctions d'un couple de directions
(direction de l'observateur et direction réfléchie). C'est
également le choix d'openGL. Le terme réfléchissant
("glossy") est aussi appelé modèle de Phong en openGL (cf.
manuel de programmation, chapitre
6).
La structure MATIERE (définie dans struct.h)
permet de représenter les objets opaques ainsi que les objets transparents
:
- typedef struct
- {
- float k_du; // poids du comportement
diffus
- float k_dd; // poids du comportement
diffus directionnel (glossy, phong ...)
- float dd_n; // exposant du diffus
directionnel
- float k_sp; // poids du comportement
spéculaire
- float n; // indice de
réfraction pour les objets réfractants
- float a; // atténuation
pour une longueur unitaire dans un objet transparent
- } MATIERE;
Le squelette contient plusieurs foncions utilitaires
permettant d'associer une matière à une primitive, elles sont
définies dans matiere.c.
remarque : il est également possible d'associer
une matière aux opérations booléennes (cf. projets).
Les interactions se calculent très simplement,
reportez vous à la fin du chapitre
6 du manuel de programmation openGL.
Partie 2. Lancer de rayons récursif
Modifiez votre lancer de rayons afin de calculer l'aspect
des matières réfléchissantes et éventuellement
réfractantes. Il est en général plus simple de casser
la fonction de calcul en plusieurs morceaux :
- visu, la boucle principale,
- lancer_rayon qui renvoie la couleur incidente le long du
rayon fourni en paramètre,
- eclairement_direct qui renvoie la couleur réfléchie
par un point après avoir déterminée la visibilité
des différentes sources de lumières.
La fonction lancer_rayon est récursive
et sera éventuellement appelée plusieurs fois lorsque un rayon
intersecte une matière réfléchissante ou réfractante.
Il est en général utile de contrôler la profondeur d'appel
et de stopper la récursion à un niveau raisonnable (< 10).
remarque : lors du calcul de la réfraction,
il est a priori nécessaire de relancer des rayons à l'intérieur
des objets. Les fonctions d'intersections des primitives fournies ne fonctionnent
pas dans ce cas là, il faudra les modifier légèrement.
Partie 3. Sources étendues
Le squelette définit également une structure
générique permettant de décrire une source de lumière
de forme quelconque (en utilisant le même principe que pour les primitives).
Modifiez votre programme afin de calculer l'éclairement du à
une source sphérique, par exemple. Il suffit de déterminer quelle
fraction de la surface de la source de lumière est visible en chaque
point de la scène (ou combien de rayons d'ombre ne sont pas interceptés
par un objet).
Il y a deux manières différentes de faire
ce calcul :
- soit en modifiant la fonction eclairement_direct (plusieurs appels
à source_rayon pour chaque point),
- soit en modifiant visu (plusieurs appels à lancer_rayon pour
chaque pixel).
Exemple :
1 miroir et 2 sources sphériques,
à gauche : 10 rayons d'ombre par source et par pixel, à droite,
30 rayons d'ombre par source et par pixel.
Partie 4. Eclairement global
Une fois que votre lancer de rayons récursif fonctionne,
il est relativement simple d'y ajouter un premier calcul de l'éclairement
global par suivi de chemin. Dans la partie précédente, vous
ne lancez de rayons supplémentaires que pour les matières réfléchissantes
ou transparentes. L'éclairement global simule les échanges d'énergie
entre les objets : c'est à dire que tous les objets réfléchissent
autour d'eux l'énergie qu'ils reçoivent. Il suffit donc de
relancer des rayons pour toutes les matières. Reste à déterminer
dans quelle direction relancer les rayons et comment combiner toutes les
énergies (et combien de rayons ?).
Les sources de lumières émettent le plus
d'énergie, mais les parties éclairées des objets redistribuent
une partie de cette énergie autour d'eux. Résultat : lorsque
2 points à la surface d'objets sont visibles, ils échangent
de l'énergie. N'importe quel point de la scène peut être
considéré comme une source de lumière, reste à
déterminer la quantité d'énergie ré-émise
par chaque point.
Les différentes méthodes sont très
succintement résumées dans le "Global Illumination Compendium"
équations 107 et 108.
Exemple :
1 miroir, 2 sources sphériques, tous les objets sont parfaitement
diffus (à part le miroir)
à gauche : suivi de chemins, 4 rebonds par chemin, 30 chemins par
pixel (1 rayon par source et par rebond le long du chemin)
à droite : même méthode, mêmes paramètres
mais 1000 chemins par pixel (20 minutes de calcul pour une image 400x400)
remarque : le fait de lancer plusieurs chemins par pixel permet d'anti-aliasser
l'image automatiquement, il suffit de répartir les rayons uniformément
dans le pixel.
La méthode utilisée pour calculer l'exemple
lance un seul rayon par source pour estimer l'éclairement direct et
un rayon pour estimer l'éclairement indirect avec une densité
de probabilité proportionnelle au cosinus (cf. GIC). Les rebonds suivants
permettent d'estimer l'énergie réfléchie vers le point
primaire (son énergie indirecte).
remarque : cette méthode est biaisée puisque la profondeur
du chemin est arbitrairement fixée. cf. utilisation de la roulette
russe (GIC eq. 109) pour construire une version non biaisée.