TD5 - Photon Mapping
L'objectif de cette partie est d'implémenter une version simple de l'algorithme de photon mapping qui permettra la visualisation directe (sans final gather) de la photon map pour les surfaces diffuses et utilisera le path tracer pour les autres matériaux.
Commencez par télécharger la correction des TP précédent, incluant le pathtracing : pathtracer.zip.
La structure de données représentant une
photon map vous est fournie dans les fichiers
PhotonMapper. Durant la première passe de l'algorithme, dans la méthode PhotonMapper::preprocess, vous devrez remplir cette
photon map en générant des photons depuis toutes les sources lumineuses et en les traçant dans la scène. Durant la seconde passe, dans la méthode
PhotonMapper::Li, vous tracerez des chemins depuis la caméra, comme pour le
path tracer, sauf que vous utiliserez la photon map à chaque intersection avec une surface diffuse.
Seules les sources étendues émettront des photons. Modifiez les méthodes samplePhoton des classes
Scene et AreaLight. La première sélectionnera aléatoirement une source étendue et appellera la seconde. Celle-ci tirera uniformément une position aléatoire sur la source, puis une direction aléatoire sur l'hémisphère orientée selon la normale à la surface (avec
Material::squareToCosineHemisphere). Dans le cas particulier d'une source étendue carrée, la puissance du photon est \(Phi = \pi ~ A ~ L_e\) avec \(L_e\) la radiance émise par la source et \(A\) l'aire de la lampe (donc du rectangle).
Chaque photon généré est alors tracé dans la scène, comme une chemin lumineux, c'est-à-dire en échantillonnant récursivement une direction de la BRDF (avec importance sampling), en traçant un rayon dans cette direction, et en utilisant le mécanisme de roulette Russe comme critère d'arrêt (utilisez le ratio entre la puissance du photon avant et après le rebond). La pondération associé au matériau (BRDF et PDF) et à la roulette Russe doit être progressivement multipliée à la puissance du photon. À chaque fois qu'une surface diffuse est intersectée, un photon est enregistré dans la photon map. Une fois le nombre visé de photons \(N\) atteint (m_photonCount), le KdTree est construit en appelant sa méthode build.
La seconde passe est presque identique à votre implémentation de
PathMats::Li. La seule différence est que, lorsqu'un rayon intersectera une surface diffuse, l'algorithme devra chercher directement dans la
photon map les photons à proximité du point d'intersection (dans le rayon
m_photonRadius) pour calculer une estimation de la radiance, et stopper la récursion.
Vous utiliserez le noyau de reconstruction de Simpson :
$$K(x) =
\begin{cases}
\frac{3}{\pi} \left(1-||x||^2 \right)^2 & \text{si } x \in [0,1] \\
0 & \text{sinon}
\end{cases}
$$
avec \(w\) le rayon de recherche / bande passante du noyau de reconstruction.
La radiance sortante peut alors être estimée par :
$$L_{o}(p \leftarrow \omega) \approx \frac{1}{N~w^2} \sum_{i=0}^{N} K\left(\frac{p-p_i}{w}\right) ~ \Phi_i ~ \rho(p,\omega_o,\omega_i)$$
Pour la Cornell Box, vous devriez obtenir :
Remerciements