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 :
    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 :


Exemple :

penombre 10 rayons / pixel penombre 30 rayons / pixel

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 :

suivi de chemins   suivi de chemins

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.