Brett Ridel

About Me

-
Publications
-
Teaching
-
The Revealing Flashlight

TD3 - BRDF de Ward

L'objectif de ce TD est d'ajouter la BRDF anisotrope de Ward à votre projet, de l'évaluer efficacement et de façon physiquement réaliste.

1. Éclairage direct
Vous allez maintenant implémenter la BRDF de Ward dans votre raytracer. Vous trouverez les détails de ce modèle dans ce document, et plus particulièrement à l'équation 4. Rappelons qu'une BRDF anisotrope a besoin d'être orientée sur le maillage à l'aide d'un repère \((x,y,n)\) où \(n\) est la normale à la surface et \((x,y)\) sont deux vecteurs orthogonaux dans le plan tangent. Dans le cadre de ce TD, vous utiliserez un champ de direction vertical, c'est à dire que nous prendrons pour le vecteur tangent \(x\), la projection du vecteur \((0,1,0)\) sur le plan tangent défini par la normale \(n\). Le vecteur \(y\) est alors obtenu à partir de \(x\) et \(n\) par produit vectoriel.

Implémentez un nouveau matériau Ward héritant de Diffuse (inspirez-vous de la classe Phong). Dans un premier temps, vous utiliserez l'intégrateur Direct pour tester votre code avec la scène "sphereWard.scn" en faisant varier les paramètres \(\alpha_x\) et \(\alpha_y\).

ward ward ward ward
\(\alpha_x = \alpha_y = 0.01\) \(\alpha_x = \alpha_y = 0.1\) \(\alpha_x = \alpha_y = 0.25\) \(\alpha_x = \alpha_y = 0.5\)
Ward isotrope (éclairage direct)
ward ward ward ward
\(\alpha_x = 0.2 ~~~ \alpha_y = 0.1\) \(\alpha_x = 0.5 ~~~ \alpha_y = 0.1\) \(\alpha_x = 0.1 ~~~ \alpha_y = 0.2\) \(\alpha_x = 0.1 ~~~ \alpha_y = 0.5\)
Ward anisotrope (éclairage direct)
2. Échantillonnage de Monte-Carlo 1D
Complétez le code ci-joint pour calculer l'intégrale de la fonction \(f(x) = 5x^4\) sur l'intervalle \([0,1]\), c'est-à-dire \(I = \int_0^1 5x^4 dx\). Implémentez la fonction int_mc qui doit retourner l'estimation de l'intégrale selon l'estimateur de Monte-Carlo \(\langle I \rangle\) avec une densité de probabilité uniforme, soit : $$\langle I \rangle = \frac{1}{N} \sum_{i=1}^N \frac{f(x_i)}{pdf(x_i)} = \frac{1}{N} \sum_{i=1}^N 5x_i^4$$ Ignorez pour l'instant la variable de sortie varest. Pour générer une variable aléatoire entre \(0\) et \(1\), utilisez (double)rand() / (double)RAND_MAX. Pour changer la graine du générateur aléatoire à chaque appel, utilisez la fonction suivante srand(time(NULL)).

Le main appelle int_mc avec un nombre croissant d'échantillons puis dessine avec gnuplot l'erreur d'estimation en fonction de \(N\). Exécutez plusieurs fois le programme et comparez les tracés.

Calculez maintenant la variance analytique en fonction de N : $$\sigma^2_{est} = \frac{1}{N} \int_0^1 \left(\frac{f(x)}{pdf(x)} - I \right)^2 pdf(x) dx = \frac{1}{N} \int_0^1 (5x^4 - 1)^2 dx$$ Tracez sur le graphique précédent cette variance.

Estimez enfin la variance numérique (variable de sortie varest) à l'aide de l'estimateur : $$ \langle \sigma^2_{est} \rangle = \frac{1}{N-1} \left\{ \frac{1}{N} \sum_{i=1}^N \left(\frac{f(x_i)}{pdf(x_i)}\right)^2 - \left( \frac{1}{N} \sum_{i=1}^N \frac{f(x_i)}{pdf(x_i)}\right)^2 \right\} $$ Affichez là sur le même graphique.

Monte-Carlo 1D
Erreur d'estimation, variance analytique et numérique en fonction du nombre d'échantillons.
3. Échantillonnage uniforme
Pour simuler fidèlement un matériau glossy, vous allez intégrer – au sens de Monte-Carlo – le modèle d'éclairement sur tout l’hémisphère. Pour cela, la principale difficulté consiste à générer un échantillonnage uniforme sur l'hémisphère (c.f. cours). Implémentez un nouvel intégrateur DirectMats s'inspirant de Whitted mais où la réflexion miroir sera remplacée par l'échantillonnage uniforme de la BRDF (ignorez la réfraction).

Chargez les deux paramètres suivants dans le constructeur de la classe DirectMats :

<integrator type="direct_mats">
    <integer name="samples" value="100"/>  <!-- nombre d'échantillions -->
    <boolean name="IS" value="false"/>     <!-- utilisation de l'échantillonage préférentiel -->
</integrator>

Afin d'obtenir un rendu plus réaliste nous utiliserons une carte d’environnement. Lorsqu'un rayon (primaire comme réfléchi) n'intersecte aucun objet, au lieu de lui donner la couleur de fond de la scène, on va chercher sa couleur dans une image représentant l'environnement. Téléchargez l'archive lightprobe.zip et intégrez la classe LightProbe à votre code. Cette classe permet de charger des light probes OpenEXR au format panoramic latitude-longitude, comme celles fournis par l'USC.

Chargez la carte d'environnement "ennis.exr" dans votre scène en utilisant la méthode LightProbe::load. Pour obtenir la radiance dans la direction d'un rayon, il vous suffit ensuite d'appeler la fonction LightProbe::intensity.

Testez avec le fichier de scène "sphereWardEnvMap.scn" (qui utilise l'envmap "ennis.exr") :

ward ward ward ward
\(\alpha_x = \alpha_y = 0.01\) \(\alpha_x = \alpha_y = 0.1\) \(\alpha_x = 0.5 ~~~ \alpha_y = 0.1\) \(\alpha_x = 0.1 ~~~ \alpha_y = 0.5\)
Échantillonnage uniforme (100 échantillons)
4. Échantillonnage préférentiel de la BRDF
Les images obtenues souffrent d'une forte variance se traduisant par un bruit important, même avec de nombreux échantillons, en particulier lorsque le lobe spéculaire est très fin. La technique d'importance sampling a pour objectif de réduire la variance en concentrant l’échantillonnage dans les directions contribuant majoritairement au résultat final (dans le lobe spéculaire, par exemple). Avec une BRDF analytique comme celle de Ward, il est possible de calculer exactement la distribution de probabilité idéale pour effectuer cet échantillonnage.

Les équations 6 à 8 du même document vous permettront de générer les directions d'échantillonnage. Ajouter une méthode d'importance sampling à la classe Material qui retournera une nouvelle direction d'échantillonnage à chaque appel.

Dans RenderingWidget::drawContents, lorsque un rayon lancé par un clic utilisateur intersecte un objet, tirez et affichez avec Line::draw une centaine de directions d'échantillonnage. Assurez-vous que la distribution de ces directions varie en accord avec les paramètres de la BRDF (taille et anisotropie du lobe).

ward ward ward ward
\(\alpha_x = \alpha_y = 0.01\) \(\alpha_x = \alpha_y = 0.1\) \(\alpha_x = 0.5 ~~~ \alpha_y = 0.1\) \(\alpha_x = 0.1 ~~~ \alpha_y = 0.5\)
Directions préférentielles (100 échantillons)

N'oubliez pas que vous devez également diviser la radiance obtenue dans la direction d'échantillonnage par la probabilité associée (\(pdf\) décrite par l'équation 9). Pour une plus grande stabilité numérique (et pour réduire le coût de calcul), il est conseillé de pré-diviser la BRDF par cette probabilité. Dans le cas de Ward, implémentez l'équation 10 dans une méthode Ward::premultBrdf. Notez que le \(\cos(\theta)\) est désormais inclus dans le calcul de la BRDF ; ne le re-multipliez pas dans l'intégrateur. Conservez bien la fonction Ward::brdf qui sera appelée lors du calcul de l'éclairage directe.

ward ward ward ward
\(\alpha_x = \alpha_y = 0.01\) \(\alpha_x = \alpha_y = 0.1\) \(\alpha_x = 0.5 ~~~ \alpha_y = 0.1\) \(\alpha_x = 0.1 ~~~ \alpha_y = 0.5\)
Échantillonnage préférentiel (100 échantillons)

Nous n'avons considéré dans les exemples précédents que des matériaux de Ward purement métalliques. La BRDF de Ward comporte néanmoins une composante diffuse qu'il vous faut également intégrer. Vous pouvez soit utiliser l'échantillonnage uniforme sur l'hémisphère \((pdf=1/2\pi)\), soit intégrer le \(\cos(\theta)\) dans la distribution d'échantillonnage (cosine weighted hemisphere sampling) qui générera une proportion moins importante de directions à la base de l'hémisphère (dont la contribution est plus faible en raison du \(\cos(\theta)\)).

Modifiez votre fonction d'importance sampling de la classe Ward pour tirer aléatoirement une direction spéculaire ou diffus. La probabilité de choisir la première par rapport à la seconde devra être proportionnelle au rapport des réflectivités moyennes : Avg(m_specularColor) / (Avg(m_specularColor) + Avg(m_diffuseColor)).

Notez à quel point la contribution diffuse ré-introduit du bruit dans l'image.

ward ward ward ward
\(\alpha_x = \alpha_y = 0.01\) \(\alpha_x = \alpha_y = 0.1\) \(\alpha_x = 0.5 ~~~ \alpha_y = 0.1\) \(\alpha_x = 0.1 ~~~ \alpha_y = 0.5\)
Échantillonnage préférentiel (100 échantillons)

Remerciements

Ce projet est basé sur celui de Pierre Bénard.