L3 synthèse d'images
2023

à lire : et avec des reflets ?

pour l'instant les matières des objets sont toutes identiques, on ne peut modifier que la couleur de base. ces matières utilisent le modèle de Lambert.


mais toutes les matières ne réfléchissent pas la lumière de la même manière dans toutes les directions. par exemple, on peut créer des reflets plus ou moins concentrés et intenses :





comment ça marche ?
pour un miroir parfait, la lumière se réfléchit dans la direction miroir, symétrique à la normale, c'est le modèle de Fresnel.
si la matière n'est pas un miroir parfait, la lumière se réfléchit de manière plus ou moins concentrée autour de la direction miroir. pour reproduire ce comportement, on peut se demander quelle devrait être la direction de la normale pour créer un reflet miroir visible.

si la camera se trouve dans la direction \( \vec{d} \) et la lumière dans la direction \( \vec{l} \), comment devrait être orientée la normale du point p, pour que \( \vec{l} \) soit la direction miroir de \( \vec{d} \) ?

réponse : dans la direction \( \vec{h} \), la bissectrice des directions \( \vec{d} \) et \( \vec{l} \). \( \vec{h} \) se calcule assez facilement :

\[ \vec{h}= \frac{\vec{d} + \vec{l}}{2} \]
 
si la normale en p était orientée dans la direction \( \vec{h} \), alors \( \vec{l} \) serait la direction miroir de \( \vec{d} \)... mais en général ce n'est pas le cas... par contre, on peut calculer à quelle "distance" \( \vec{h} \) se trouve de \( \vec{n} \)... on pourait utiliser le cosinus de l'angle entre les 2 vecteurs pour les comparer, mais cette fonction ne décroit pas très vite et le reflet est très étalé...




pour vraiment concentrer le reflet, il faut une fonction qui décroit plus vite vers 0 lorsque l'angle entre \( \vec{n} \) et \( \vec{h} \) passe de 0° à 90°. on souhaite aussi pouvoir régler facilement la concentration du reflet, avec un paramètre supplémentaire. une manière très simple de modifier le cosinus de l'angle pour le faire décroite plus vite vers 0 est de l'élever à une certaine puissance. voila à quoi ressemblent ces puissances d'un cosinus (avec un coeff k en plus) :


il ne reste plus qu'à choisir l'exposant pour définir la taille et l'intensité du reflet.

en résumé, on peut calculer les reflets avec cette fonction :
\[
    f_r( \vec{d}, \vec{l} )= \frac{8+\alpha}{8 \pi} ( \cos \theta_h )^\alpha \mbox{ avec } \vec{h}= \frac{\vec{d}+\vec{l}}{2}
\mbox{ et } \theta_h \mbox{, l'angle entre } \vec{n}, \vec{h}
\]
et c'est le paramètre \( \alpha \) qui permet de concentrer, ou pas, les reflets, plus la valeur est importante plus le reflet est petit.

ce modèle à été crée en 1976 par J. Blinn en modifiant le modèle précédent de B.T. Phong présenté en 1975.
ce modèle s'appelle donc Blinn-Phong. attention, de nombreuses ressources sur le web oublient les coeffs magiques \( \frac{8+\alpha}{8 \pi}\), mais ils sont nécessaires !!
les détails sont dans la doc en ligne. les modèles de matières plus récents sont également décrits, cf Disney BRDF / Principled BRDF / PBR.

exemples : pour \( \alpha= \) 2, 8, et 16



et pour des reflets plus concentrés \( \alpha= \) 128, 512, 1024





quelles matières peut-on reproduire ?
d'après les travaux de Fresnel, il y a 2 types de matières, les métaux et les autres... la lumière se réfléchit directement à la surface des métaux et reste très concentrée, le reflet prend la couleur du métal. à l'inverse, pour les dielectriques, ie les non-métaux, la lumière se réfléchit en partie à la surface mais se diffuse aussi dans l'épaisseur de la matière et se colore. c'est le même comportement que le modèle de Lambert, le reflet reste neutre, ie de la même couleur que la lumière (blanc en général).

les exemples précédents sont donc des... dielectriques, la matière est rouge et le reflet blanc. un métal sera noir en dehors du reflet et le reflet sera coloré. par exemple :



ce sont les mêmes paramètres, à gauche un dielectrique et à droite un métal.



et alors ?
avec ces 3 paramètres : couleur, métal et alpha, on peut écrire la brdf, ie la fonction qui décrit une matière pour les métaux et les dielectriques, ie les non métaux :

\[
\begin{eqnarray*}
    \mbox{(métaux) } f_r( \vec{d}, \vec{l} ) &= &black + color \times \frac{8+\alpha}{8 \pi} ( \cos \theta_h )^\alpha \\
    \mbox{(non-métaux) } f_r( \vec{d}, \vec{l} )&= & \frac{color}{\pi} + white \times \frac{8+\alpha}{8 \pi} ( \cos \theta_h )^\alpha
\end{eqnarray*}
\]

chaque modèle est composé de 2 termes : la partie diffuse, qui correspond à la diffusion de la lumière dans l'épaisseur de la matière, comme prédit par Lambert, ainsi que la partie spéculaire, qui correspond au reflet à la surface de la matière, comme prédit par Fresnel. Les métaux ne diffusent pas la lumière, il n'y a qu'une réflexion colorée en surface, alors que pour les autres matières la couleur correspond à la diffusion colorée de la lumière et à un reflet en surface de couleur neutre / blanc.

on peut également construire un modèle unique, utilisable avec les métaux et les non-métaux mais paramétré avec une couleur de diffusion et une couleur de surface :
\[
    f_r( \vec{d}, \vec{l} )= \frac{diffuse}{\pi} + specular \times \frac{8+\alpha}{8 \pi} ( \cos \theta_h )^\alpha \\
\]

il suffit d'initialiser ces couleurs en fonction des paramètres de base de la matière, métal, couleur et alpha :
\[
\begin{eqnarray*}
    diffuse &= & (1-metal) \times color + metal \times black \\
    specular &= & (1-metal) \times white + metal \times color
\end{eqnarray*}
\]



bilan...
ce modèle est toujours très utilisé, il est assez simple à comprendre, facile à programmer, mais c'est un modèle empirique, ie une grosse approximation de la physique. pour faire mieux et reproduire correctement plus de types de matières, il faut regarder un peu plus en détail les travaux des physiciens, les formules sont moins simples mais le résultat est quand même un peu plus subtil... les principes de Fresnel sont dans la doc en ligne (cf lumière et matière), et la suite, la construction de la nouvelle génération de modèles de matières se trouve sur cette page (cf lumière et reflets)



comment ça se code ?
après les calculs d'intersections, on connait le point p, sa normale n, et sa matière, c'est à dire les paramètres du modèle : métal, couleur et alpha.
les directions vers la camera et la source de lumière sont nécessaire également.
attention !! à l'orientation des vecteurs, leur origine se trouve sur le point p...

// paramètres de la matière
Color color;

float metal;
float alpha;

Color fr( const Vector& d, const Vector& n, const Vector& l )
{
    // verifie que les vecteurs sont bien orientes. d vers la camera, l vers la lumiere
    assert(dot(n, d) >= 0);
    assert(dot(n, l) >= 0);
   
    // calcule h
    Vector h= normalize(d+l);
    // et le cosinus avec la normale
    float cos_theta_h= dot( normalize(n), h );
   
    if(metal)
        // pour les metaux
        return (alpha+8) / float(8*M_PI) * std::pow(cos_theta_h, alpha) * color;
    else
        // pour les autres
        return color + (alpha+8) / float(8*M_PI) * std::pow(cos_theta_h, alpha) * White();
}

on peut aussi éviter de faire le test sur métal en séparant les 2 couleurs, celle du reflet et celle de la matière :

// paramètres de la matière
Color color;

Color specular;
float alpha;

Color fr( const Vector& d, const Vector& n, const Vector& l )
{
    // verifie que les vecteurs sont bien orientes. d vers la camera, l vers la lumiere
    assert(dot(n, d) >= 0);
    assert(dot(n, l) >= 0);
   
    // calcule h
    Vector h= normalize(d+l);
    // et le cosinus avec la normale
    float cos_theta_h= dot( normalize(n), h );
   
    return color + (alpha+8) / float(8*M_PI) * std::pow(cos_theta_h, alpha) * specular;
}


remarques : pour reproduire les exemples de cette page, il faut programmer l'éclairage par un soleil et par un ciel avec des directions aléatoires, cf les tps et le cours.