ce sont les mêmes paramètres, à gauche un dielectrique et à
droite un métal.
et alors ?
On va utiliser 3 paramètres : métal, bien sur, plus une
couleur, et alpha pour la concentration des reflets, ce qui
permet de décrire l'état de la surface d'un objet : poli
comme un miroir ou complètement rugueux comme les dalles du
plafond ou du plâtre sur un mur. On peut écrire la brdf, ie
la fonction qui décrit une matière pour les métaux et une
autre pour 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.
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 spéculaire qui décrit la
réflexion 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*}
\]
quelles valeurs / couleurs peut-on utiliser ?
Les matières naturelles non métalliques, les diélectriques,
comme l'eau, le verre, le plastique, la végétation, le
béton, les peintures, etc utilisent des valeurs assez
faibles pour le reflet spéculaire, de l'ordre de 0.05, leur
surface ne réfléchit max que 5% de l'énergie reçue, par
contre la lumière se transmet sous la surface et se colore.
La surface des métaux réfléchit plutôt 50% ou 60% (voire 90%
pour un miroir poli en aluminium) mais sans transmission
dans l'épaisseur de la matière.
Dans tous les cas, il faut quand même vérifier que les
composantes des couleurs diffuse et spéculaire ne soit pas
plus grandes que 1 :
\[
\max(diffuse_r, diffuse_g, diffuse_b) +
\max(specular_r, specular_g, specular_b) <= 1
\]
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 / float(M_PI) + (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 /
float(M_PI) + (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.