Éclairage par sources polygonales

L'éclairage par des sources polygonales ne possède pas de solution analytique permettant de calculer celui-ci en temps-réel. Dans le cas général, il faut intégrer sur toute la surface visible du polygone, comme le font les intégrateurs hors-ligne. La publication de Eric Heitz de 2016 propose une approximation de la solution calculable en temps-réel grâce à un pré-calcul et une distribution aux propriétés spécifiques.

Brièvement, la technique repose sur le fait que l'on peut approximer la distribution GGX (cf matériaux physiquement réaliste) décrivant un matériau (qui forme partiellement un modèle basé sur les micro-facettes) avec une transformation linéaire d'une distribution spécifique appelée LTC (Linearly Transformed Cosine). On peut, par différentes techniques, trouver les paramètres de cette transformation (5 au total) pour un angle d'incidence et une rugosité donnée, et par extension, échantillonner ces paramètres pour des variations de ces angle et rugosité. C'est ce qu'on appelle le fitting. Une fois ceci pré-calculé, on peut en faire des textures (en l’occurrence $64 \times 64$) et évaluer une estimation de la distribution facilement depuis un shader OpenGL, en temps réel. Reste à intégrer l'énergie du polygone, ce qui est fait à l'aide du théorème de Stokes.

preview

Une étoile verte et un carré rouge éclairent une scène (vue du dessous) dont les objets sont représentés avec le matériau Substrate

L’éclairage direct de la scène doit être fourni par un ensemble réduit de l’ordre de la dizaine/centaine de scènes polygonales, linéaires, et disques. Les techniques envisageables doivent permettre de contourner l’infaisabilité d’un échantillonnage comme fait en rendu hors-ligne. La technique présentée par Eric Heitz  dont l’idée est de pouvoir approximer la zone éclairée d’un point par une source de forme polygonale à l’aide d’une fonction simple et aux bonnes propriétés (de norme, de distribution, . . . ). Cette technique repose sur le choix d’une distribution sphérique de base, présentée dans l'équation suivante, et sur la trans-formation de ses vecteurs de direction par une matrice $3 \times 3$, qui produit une distribution alternative avec des propriétés similaires, pour simuler le comportement d’une distribution GGX par rapport à une source.

$D_o(w_o = (x,y,z)) = \frac{1}{\pi} \max(0,z)$

Les parties clés de l’algorithme consistent à trouver la matrice de transformation (fitting) et à intégrer la distribution sur la projection du polygone.

Fitting

La transformation de la distribution originale dépend de 2 paramètres : l’angle incident $\theta$ (entre la normale du polygone et la normale d’un point de la sphère) et la rugosité $\alpha$ de la BRDF, et forme une matrice $M$ qui contient 4 paramètres variables :

$M = \begin{bmatrix} a & 0 & b \\ 0 & c & 0 \\ d & 0 & 1 \end{bmatrix}$

Comme on le verra dans la partie Intégration, on a besoin de $M^{-1}$ et non pas de $M$, ce qui fait 4 paramètres plus un cinquième paramètre pour la norme de la BRDF. Ces matrices seront pré-calculées dans des textures de $64 \times 64$ pour tous les $\theta$ dans un sens et tous les $\alpha$ dans l’autre, et sont ensuite retrouvées par interpolation.

roughness anisotropy skewness


La fonction de base $D_o$ et ses transformations,permettant de simuler des BRDF de type GGX

Intégration

Grâce à leurs propriétés linéaires invariantes, l'intégration d'un LTC sur un polygone équivaut à l'intégration de la distribution originale du cosinus sur le polygone transformé par la transformation linéaire inverse : c'est juste l'irradiance (facteur de forme) du polygone transformé pour lequel une expression de forme close est disponible ! L’intégration est faite pour $D_o$ sur la projection du polygone, et non pas l’inverse, ce qui permet de ne stocker que les 5 paramètres cités précédemment et de généraliser l’intégration. On peut faire ceci, car Eric Heitz montre que l’intégrale sur la projection du polygone sur la sphère de la distribution sphérique transformée est égale à l’intégrale sur la projection du polygone transformé de la distribution originale, pour laquelle on dispose d’une expression analytique, de la forme $\int_{P_o} {D_o(w_o) dw_o}$ où les $w_o$ sont les directions associées aux projections des points du polygone transformé $P_o = M^{−1}P$. Cette intégration peut se faire avec le Théorème de Stokes. En considérant la radiance émise $L$ constante sur le polygone, on obtient $I = L \int_{P_o} {D_o(w_o) dw_o}$ avec $j= (i+ 1)%n$ pour décrire localement une arrête du polygone et

$\int_{P_o} {D_o(w_o) dw_o} = E(P_o) = E(p_1, \dots, p_n) = \frac{1}{2\pi} \sum_{i=1}^{n}{\text{acos}(p_i \cdot p_j) (\frac{p_i \times p_j}{||p_i \times p_j||} \cdot [0,0,1]^T) }$

LTC-polygon integral ..equivalent to.. cosine-polygon integral
    analytic solution!

L’intégration de la partie diffuse se fait comme celle de la partie spéculaire, mais avec la distribution originale clampée. C’est important à noter, car cela implique que c’est le calcul de la source qui fait appel aux propriétés du matériau et renvoie la réponse finale de la BSDF. Pour cette partie Eric, propose un outil pour faire le fitting et généré les textures de $64 \times 64$, il suffie de télécharger le zip, puis de compilé

Rendue

  1. Récuperation des paramètres par interpolation dans les textures
  2. Reconstruction de la matrice inverse $M^{-1}$
  3. Calcul de la partie spéculaire
    1. Transformation du polygone avec $M^{-1}$ et clipping
    2. Intégration
  4. Calcul de la partie diffuse
    1. Clipping seulement (transformation avecI3)
    2. Intégration
  5. Addition des deux parties

Stockage des données

Pour stocker : le polygone et ses transformations, deux buffers de tailles MAX_V ERT ICES et 2MAX_V ERT ICES sont utilisées. Celui de taille MAX_V ERT ICES contient le résultat de la transformation, et l’autre contient le résultat du clipping du précédent. Nous n’avons pas de démonstration formelle quel nombre de vertices ne dépassera jamais 2 fois le nombre original, mais nous nous sommes basé sur l’intuition fournie par le schéma suivant, que nous croyons représenter un cas limite. Aucun bug n’est apparu jusque-là à cause de ça, mais il est bon de le garder à l’esprit.

Cas considéré presque limite (toutes les arrêtes sauf une sont coupées).
Le nombre de points initial est $N= 11$, et devient $15$.
Il est possible que le nombre total puisse être borné par $\frac{3}{2}N$, mais il faudrait le prouver

La transformation et le clipping : sont les étapes qui contiennent les détails importants. D’abord, la transformation se fait non seulement en fonction de la matrice de transformation, mais prend également en compte la rotation faisant en sorte que la normale du point (de la surface) devienne $(0;0;1)$. C’est le rôle du vec3 basis.

Le clipping à l’horizon change le nombre de points. Il procède en itérant sur les vertices une première fois en déterminant s'ils sont valides ou non (c’est-à-dire, qu’ils sont au-dessus de l’horizon) et une deuxième fois, en créant cette fois les points au fur et à mesure, suivant les observations précédentes. Ce n’est pas un algorithme en place, et surtout, il est générique et fonction du critère de validité, il est donc imaginable qu’il existe un algorithme plus ad hoc et efficace.

L’intégration : une fois arrivé là, est relativement simple et consiste juste à appliquer la formule de la publication, autrement dit sommer le résultat du calcul sur chaque arête du polygone.

Limitations

Deux problèmes ont été spécialement identifiés.

Le premier est la dépendance forte à l’ordre des points donnés au shader. En effet, si les points ne suivent pas le contour, le résultat sera faux. Ce n’est pas anormal, et même totalement lié à la technique d’intégration utilisée, mais c’est un fait notable qui est à prendre en compte lors de l’import depuis le Mesh. Pour l’instant,le Mesh est supposé contenir des vertices ordonnés.

Le second devrait théoriquement intervenir lors du clipping du polygone. En effet, la forme analytique trouvée dépend du fait que le polygone soit integré sur la demi-sphère et non pas sur la sphère. Ceci implique le clipping en question. Le clipping en soi ne pose pas de problèmes, mais la manière dont est faite l’intégration dans le shader ne tient pas compte de la possibilité qu’un polygone devienne plusieurs polygones. Par exemple, si on intègre une étoile, il existe forcément une configuration où le point ne ”voit” que les bouts de deux branches de l'étoile, soit deux triangles.

Cela n’est pas géré, et en fait aucun problème n’a été constaté en pratique, mais c’est étonnant. L’une des solutions envisagées avant que la première implémentation soit fonctionnelle était de gérer une liste de polygonespar défaut, et de scinder explicitement le polygone lors du clipping. Cela aurait permis, en supplément, de gérerle rendu de plusieurs sources lors du même appel de shader. C’est probablement une amélioration possible (quiaurait un impact sur le passage des données, cependant).

Exemple d’un polygone qui, une fois clippé, donne deux polygones

Copyrigth

Les résultats et les codes présenter ont été effectuer lors de mon projet de M2, en collaboration avec Hugo Rens principalement en chage de cette partie et visais à ajouter certaines fonctionnalités au moteur graphique de l'IRIT, le RadiumEngine