L3 synthèse d'images
2025

TP2 - lancer de rayons et lumières


le tp1 permet de calculer une première image, avec quelques objets éclairés par un soleil(+ les ombres).


Partie 1 : plusieurs soleils !

avant de se lancer dans le calcul complet qui permet d'éclairer les objets avec un soleil et un ciel, on va regarder un cas plus simple : avec 2 soleils !
qu'est ce qui change ? on va faire 2 fois le même calcul : une fois par soleil et ajouter les 2 résultats. la lumière réfléchie par un objet éclairé par 2 sources de lumière est la somme de la lumière réfléchie par chaque source.

et les ombres ? l'objet peut être à l'ombre des 2 sources, ou d'une seule, ou d'aucune. encore une fois, on additionne les 2 resultats : pour chaque source de lumière l'objet est éclairé ou pas, et c'est ce résultat que l'on additionne.

vérifiez que vous obtenez un résultat cohérent, par exemple :


2 soleils / directions et un ciel noir...


vous pouvez reproduire ce résultat avec les directions : Vector l1= normalize(Vector(-4, 6, 1)); et Vector l2= normalize(Vector(4, 6, -1));

on observe bien le sol complètement noir sous la sphère, ie aucun soleil n'éclaire cette partie. on a bien des ombres plus claires à gauche et à droite de la sphère, ie 1 seul soleil éclaire dans ce cas et l'autre est à l'ombre.


Partie 2 : et le ciel ?

relisez le cours pour générer des directions (aléatoires ou sur une grille). pour calculez l'image, on va utiliser le même principe qu'au dessus, mais avec N directions.

exercice 1 :
générez des directions aléatoires différentes pour chaque pixel de l'image.

rappel : il faudra sans doute modifier la boucle de parcours des pixels de l'image, comme expliqué dans la dernière section du tp1, cf "intermède : plus vite", en initialisant un générateur de nombres aléatoires pour chaque ligne de l'image.



exercice 2 : écrivez le calcul avec les N directions générées. utilisez N= 4 pour commencer.


N= 4 directions aléatoires différentes par pixel. oui c'est moche. les pixels du ciel ont la bonne couleur, cf l'exercice 3.

attention : les directions calculées par le code du cours sont toujours orientées au dessus de l'horizon, c'est bien pour éclairer les objets par le ciel mais il faut faire attention à un
détail... une direction générée peut être sous la surface de l'objet ! comment détecter ce cas ? pourquoi est-ce un problème ?

indication : comment vérifier que 2 vecteurs sont orientés dans la même direction ? ou dans des direction opposées ?
indication : il suffit de vérifier que la direction est orientée dans la même direction que la normale au point p !

rappel : la couleur du ciel correspond au terme Li( lk ) dans le cours, ie la lumière émise par la source qui arrive (ie qui est incidente) au point p depuis la direction l, et Li( l ) > 0 si l est au dessus de l'horizon et au dessus de la surface en p et 0 / noir sinon.


exercice 3 :
pour l'instant, l'image est noire pour tous les pixels qui ne "voient" pas un objet. et par définition, les rayons du pixel qui ne voient pas un objet, voient... le ciel ! modifiez la couleur du pixel dans ce cas.


N= 256, c'est plus long à calculer mais c'est moins moche... et le ciel à la bonne couleur.


exercice 4 :
et avec le soleil en plus ?

que faut-il ajouter ?

rappel : quand 2 sources de lumière éclairent le même objet, l'objet reçoit plus de lumière, ie on additionne les 2 valeurs...


N= 256 directions pour le ciel + le soleil...


exercice 5 :
et avec un ciel coloré ? comment modifier la couleur du ciel en fonction de la direction l ? par exemple, au lever du soleil, les directions juste au dessus de l'horizon n'ont pas la même couleur que les autres directions. idem au coucher du soleil.
vérifiez que cette couleur du ciel qui dépend de la direction est bien prise en compte pour calculer la lumière réfléchie vers le pixel dans tous les cas : lorsque le pixel observe un objet, ou lorsqu'il observe le ciel.

indications : comment définir Li( l ) ?

utilisez des objets gris, de couleur neutre, cf Color(0.5) par exemple, pour vérifier que l'éclairage est cohérent...
et n'oubliez pas que les couleurs sont des float entre 0 et 1 (et pas des entiers entre 0 et 255)

vérifiez également que Red() * Blue() == Black()... cette dernière remarque devrait vous aider à choisir des couleurs un peu plus nuancées, ie le produit de 2 couleurs primaires est noir, par définition.

indications : utilisez les constructeurs de palettes de couleurs ! il suffit de convertir les couleurs html entre 0 et 255 en divisant par 255 : Color color= Color(180, 42, 60, 255) / 255;


le sol et la sphère sont gris, mais la couleur du ciel varie entre et bleu et violet.



le sol et la sphère sont gris, mais la couleur du ciel varie entre et bleu à l'horizon et noir à la verticale / au zenith.


pour les curieux : il existe une norme CIE qui interpole la quantité de lumière émise par un ciel parfaitement dégagé en pleine journée en fonction de l'angle \( \theta \) entre le zénith (ie la verticale en simplifiant) et une  direction l :
\[
    L( \vec{l} )= L_{zenith} \frac{ 1 + 2 \cos \theta} {3}
\]

\( L_{zenith} \) représente la lumière émise par la direction du zénith.

il existe aussi des modèles paramétriques du ciel, de la position du soleil en fonction de la date, de l'heure, de la position, de l'orientation etc. avec des formules plus complètes... on peut aussi utiliser une image ! ça doit évoquer quelques souvenirs si vous avez fait l'option LIFGraphique en L2 ?


Intermède : encore plus vite ?

si vous avez écrit la partie 6 "anti-aliasing" du tp1, le temps de calcul pour obtenir une image propre doit commencer à augmenter. (un peu trop)...
pourquoi ? comptez combien de fois vous faites le calcul éclairé / à l'ombre par pixel. si vous avez ajouté plus d'objets, comment évolue le temps de calcul ?
ou rappelez-vous la complexité des algorithmes vu en LIFAPC ? combien y a t il de boucles pour calculer un pixel, pour toute l'image ?

en gros votre code doit ressembler à :

pour chaque pixel :
    pour AA rayons dans le pixel (anti-aliasing / lissage) :
        trouver l'objet visible (ie boucle de calcul d'intersection pour chaque objet)

        pour N directions dans le ciel :
            vérifier que le point p est éclairé (ie boucle de calcul d'intersection pour chaque objet)
            accumuler la lumière réfléchie vers le pixel

au total, on fait AA*N calculs par pixel...

il existe une solution assez simple pour mieux contrôler le temps de calcul complet de l'image en utilisant des directions aléatoires dans la partie 2 pour éclairer les objets  avec N directions vers le ciel. il suffit de n'utiliser qu'une seule direction aléatoire vers le ciel et de recommencer N fois par pixel. en gros :

pour chaque pixel :
    pour N rayons dans le pixel (anti-aliasing / lissage) :
        trouver l'objet visible (ie boucle de calcul d'intersection pour chaque objet)

        pour une direction dans le ciel :
            vérifier que le point p est éclairé (ie boucle de calcul d'intersection pour chaque objet)
            accumuler la lumière réfléchie vers le pixel

au total on ne fait plus que N calculs par pixel...

et oui ca marche, ces 2 manières de faire le calcul convergent vers le même résultat / la même image. les détails seront dans le cours de M2, par contre...
le résultat est plus rapide, mais pas toujours de la même qualité, par contre, le temps de calcul est maintenant proportionnel à N ce qui est plus simple à manipuler.