Retrouvez cet article dans : Linux Magazine 87
Dans cet article, nous allons approfondir notre connaissance du module Scene, en nous intéressant plus particulièrement aux méthodes et variables liées à la radiosité.
La radiosité est une méthode d’illumination basée sur les échanges lumineux afin de déterminer dans quelle mesure un pixel de votre image est éclairé, soit directement (il est sur la trajectoire directe d’un rayon de lumière émis par une lampe, par exemple), soit indirectement (il est éclairé par les rebonds successifs des rayons lumineux sur les objets de la scène). Dans le second cas, on parle d’illumination globale, c’est-à -dire qu’au lieu de s’arrêter au premier obstacle rencontré, le rayon lumineux va rebondir et, par rebonds successifs, « remplir » la scène entière.

 Figure 01 : Exemple d’éclairage direct (ombre obtenue par raytracing) et indirect (illumination globale par radiosité)
Détail intéressant, qui contribue au réalisme de cette méthode d’éclairage : lorsqu’un rayon lumineux frappe une surface, il perd une partie de son énergie pour éclairer celle-ci, et rebondit avec une intensité moindre et légèrement teintée de la couleur de l’objet frappé.
Les couleurs de base d’une scène bien illuminée se teintent donc de la couleur propre des objets environnants.
Ainsi, sur la figure 01, dans le cas de l’éclairage indirect, on voit que le sol blanc est localement teinté par le pan de mur jaune, par le pan de mur vert, ainsi que par le cube rouge.
Souvent, ces effets sont très subtils et nécessitent un bon sens de l’observation pour être perçus.
1. Blender et la radiosité
La méthode de radiosité mise en œuvre par Blender est une version simplifiée des méthodes classiques de radiosité. Elle nécessite que tous les objets mis en œuvre dans le calcul de la solution soient des maillages, car le résultat des échanges lumineux sont stockés sur les sommets grâce à la technique du vertex painting (peinture sur sommets). Qui plus est, un objet qui est censé émettre de la lumière doit avoir un paramètre Emit supérieur à 0.000. Les maillages sont ensuite morcelés pour constituer des patches (triangles ou quadrangles qui vont émettre de l’énergie) et des éléments (triangles ou quadrangles qui vont recevoir de l’énergie). Un maillage est constitué à la fois de patches et d’éléments : lorsqu’un élément reçoit de l’énergie, il en absorbe une partie (fonction de la couleur du matériau) et transmet ce qui reste au patch, qui va émettre celle-ci.
Les dimensions des patches et des éléments sont essentielles dans la recherche d’un bon compromis entre rapidité du calcul d’une solution de radiosité et finesse des ombres et reflets lumineux à la surface des objets.
1.1 Radiosité au rendu
Cette méthode de calcul a été développée de sorte qu’il soit possible de déterminer une solution de radiosité, assez approximative, pour chaque frame d’une animation. Elle ne nécessite que peu ou pas de réglages de la part de l’utilisateur : chaque matériau devant être pris en considération doit avoir le bouton Radio actif dans l’onglet Shaders et V Col Light dans le panneau Material, des Material buttons (F5). Les matériaux émetteurs d’énergie doivent, en plus, avoir la variable Emit non nulle. Enfin, dans le menu Scene (F10), l’option Radio doit être active dans le panneau Render.
Dans les Material buttons, il existe un sous-menu propre à la radiosité : les Radiosity buttons, que l’on peut afficher en appuyant plusieurs fois sur la touche [F5] ou en cliquant sur l’icône appropriée. Le premier panneau va être le seul qui va vous intéresser dans le cadre de l’usage de la radiosité lors du rendu.
- Hemires : ce paramètre permet de déterminer la qualité de l’échantillonnage de l’environnement à l’élément considéré. Attention, car des résultats trop élevés peuvent conduire à un effet de crénelage si les maillages sont fins. Littéralement, l’Hemires détermine la quantité d’énergie émise par un patche (voir figure 2).
- Max iterations et Convergence : tant que les éléments continuent à recevoir de l’énergie, les patches associés vont en émettre et le calcul de la solution de radiosité va se poursuivre ; théoriquement, cela pourrait durer indéfiniment. Deux mécanismes permettent de limiter les calculs dans le temps, en mettant fin artificiellement : Max iterations permet de définir le nombre de « rebonds » lumineux maximum au-delà duquel on estime que la solution est suffisamment bonne.

Figure 02 : Une sorte d’effet Moiré fait son apparition lorsque Hemires a une valeur trop élevée pour un maillage fin.
De même, Convergence définit l’énergie en dessous de laquelle on considère que le patch n’a plus de lumière à émettre, mettant également fin au calcul de la solution.
- Mult et Gamma : la valeur Mult permet de multiplier par un facteur l’intensité de la distribution lumineuse dans la scène ; avec une valeur supérieure à 10.000 la scène est plus illuminée, avec une valeur inférieure, elle s’assombrit. Pour sa part, Gamma permet de définir le contraste de la solution de radiosité. Des valeurs inférieures à 1.000 tendent à augmenter le contraste.

Figure 03 : Au centre, les paramètres par défaut; à gauche, une valeur Mult plus faible ; à droite, une valeur Gamma plus faible
L’avantage de la radiosité au rendu tient au fait que la solution de radiosité est peinte sur les sommets à chaque frame d’une animation : on peut donc obtenir des éclairages dynamiques. Malheureusement, cette méthode ne permet pas d’employer la subdivision adaptive propre à la radiosité pré-calculée (voir ci-après) ; il en résulte que la qualité de la solution de radiosité dépend très fortement de la densité des maillages de la scène : une densité élevée permettra de restituer toute la richesse des ombres et lumières, aux prix de calculs plus lourds et plus longs. Le maillage sera uniformément serré là où, avec la subdivision adaptive, elle ne l’aurait été que là où réellement nécessaire. Surtout, cette méthode convient très bien à des scènes faisant appel à des textures.
Le mode Gouraud est le seul qui permette d’obtenir une illumination lissée sur les surfaces courbes de vos objets ; les autres modes laisseront entrevoir les facettes, un peu comme si Set Smooth et Set Solid étaient employés en modélisation.
1.2 Radiosité pré-calculée
Cette méthode permet d’obtenir des solutions de radiosité plus fidèles, avec une plus grande richesse de gradients d’ombres et de lumières. Le moteur de radiosité fonctionne toutefois très différemment de la méthode précédente. Pour la mettre en œuvre, il faut dans un premier temps sélectionner tous les objets devant entrer dans le calcul de la solution de radiosité, puis dans le panneau Radio Tool, cliquer sur le bouton Collect Meshes. La vue 3D bascule automatiquement en ombrage de Gouraud, ne montrant que les objets prenant part à la simulation. Une mire étrange, constituée de rectangles imbriqués, fait son apparition au centre géométrique de la scène : ils délimitent les dimensions max et min des patches (blancs) et des éléments (cyan).

Figure 04 : La scène en affichage de Gouraud, juste avant le calcul de la solution de radiosité
En appuyant sur la touche Go, les objets de la vue 3D vont s’illuminer progressivement, à mesure des rebonds des rayons lumineux, et les éléments recevant l’énergie apparaîtront régulièrement, laissant entrevoir la taille des patches et éléments qui iront s’affinant, le moteur de radiosité utilisant la subdivision adaptive. Les critères d’arrêt de la simulation sont les mêmes que pour la radiosité au rendu : Max Iteration et Convergence du panneau Radio Render. Mais il est également possible de mettre fin à la simulation, lorsque le résultat visuel vous satisfait, en appuyant sur la touche ESC.

Figure 05 : La même scène, après le calcul de la solution de radiosité
Mais le résultat de la simulation n’est qu’en mémoire, elle n’a aucunement été transposée à la scène. La solution de radiosité sera peinte sur les sommets d’un maillage unique, regroupant les maillages de tous les objets impliqués dans la simulation (ceux sélectionnés précédemment). Mais il vous est possible de spécifier que ce nouveau maillage remplace totalement les anciens objets (qui seront alors supprimés de la scène), ou bien qu’il existe en plus de chacun des maillages individuels : pour effectuer ce choix, cliquez sur les boutons Replace Meshes ou Add new Meshes dans le panneau Radio Tool. Pour quitter le mode de la simulation de radiosité, cliquez tout simplement sur le bouton Free Radio Data, dans le même panneau.
Si l’option V Col Light est active pour chacun des matériaux du maillage contenant la solution de radiosité, lors du rendu il sera possible de visualiser les échanges lumineux de la scène, aboutissant à une illumination bien plus réaliste que par l’usage de simples lampes.

 Figure 06 : La solution de radiosité, après rendu de la scène finale
ElMax et ElMin : ces deux paramètres définissent la taille max et la taille min d’un élément. Dans la mire qui apparaît au centre de la scène de radiosité, les échelles respectives apparaissent en cyan.
- PaMax et PaMin : ces deux paramètres définissent la taille max et la taille min d’un patch. Dans la mire qui apparaît au centre de la scène de radiosité, les échelles respectives apparaissent en blanc.
- Limit Subdivide : permet de subdiviser les patches ; cette commande est automatiquement lancée lorsque vous pressez le bouton Go.
- Les boutons, du panneau Calculation, qui suivent permettent d’améliorer la qualité de la simulation :
- Face Filter : les éléments sont convertis en facettes à l’affichage ; le résultat est un petit peu plus lissé, sans pour autant toucher à la valeur d’un élément.
- Element Filter : les éléments sont nettoyés des artefacts et du phénomène de crénelage, les ombres sont adoucies aux frontières, et les couleurs générées par l’option Remove Doubles sont uniformisées.
- RemoveDoubles : si les couleurs affichées par deux éléments ne diffèrent que très peu (dans les proportions déterminées par le bouton Lim), les deux éléments en question sont fusionnés.
Enfin, les autres paramètres du panneau Calculation permettent de contrôler le calcul de la solution de radiosité, mais nous ne les recommandons qu’à ceux qui savent ce qu’ils font et ce qu’ils attendent comme résultat.
 2. Le sous-module Radiosity
La radiosité est un sous-module du module Scene. Il conviendra donc d’importer celui-ci avant toute chose :
import Blender from Blender import Scene
Tous les paramètres de radiosité sont stockés dans un contexte spécifique; toutefois, seule la scène courante possède un contexte de radiosité. Par exemple,
scn = Scene.GetCurrent()
permet de donner à Python accès à la scène courante. Vous pouvez bien évidemment sélectionner toute autre scène (par exemple en citant son nom) et en la définissant comme la scène courante :
scn = Scene.Get(‘[Nomdelascene]’) scn.makeCurrent()
ainsi que nous l’avons vu dans le précédent article. Vous accéderez ensuite au contexte de radiosité de la scène grâce à la ligne :
radio = scn.getRadiosityContext()
Dans les lignes d’exemple précédentes, scn et radio sont des noms de variables arbitraires que vous êtes libre de modifier à votre guise.
2.1 Radio Render
Les méthodes qui suivent permettent de mettre en œuvre des fonctions relatives aux boutons du panneau Radio Render. Ce sont des méthodes communes à toutes les opérations de radiosité, qu’elles soient pré-calculées ou effectuées au moment du rendu.

 Figure 07 : Le panneau Radio Render
Par exemple, le script suivant :
01: import Blender 02: from Blender import Scene 03: 04: scn = Scene.Get(‘Scene’) 05: scn.makeCurrent() 06: 07: radio = scn.getRadiosityContext() 08: radio.setHemiRes(600) 09: radio.setMaxIter(100) 10: radio.setMult(40) 11: radio.setGamma(3.5) 12: radio.setConvergence(0.05) 13: 14: context = scn.getRenderingContext() 15: context.enableRadiosityRender(1) 16: context.render()
permet de définir les paramètres de calcul de la solution de radiosité au rendu (lignes 07 à 12), et de lancer celui-ci (lignes 14 à 16). Les autres lignes du script sont expliquées ci-après.
La méthode setHemiRes()
Cette méthode permet de définir la résolution de l’hémi-cube, en lui attribuant une valeur comprise entre [100,1000]. De la même façon, la méthode getHemiRes() permet de lire la valeur HemiRes de la scène courante.
La méthode setMaxIter()
Cette méthode détermine le nombre d’itérations de calcul de la solution de radiosité. Elle admet des valeurs comprises entre [0, 10000]. De la même façon, la méthode getMaxIter() permet de lire le nombre max d’itérations utilisé dans la scène courante.
La méthode setMult()
Cette méthode détermine le multiplicateur de l’énergie lumineuse de la scène. Elle admet des valeurs comprises entre [0.001, 250.000]. De la même façon, la méthode getMult() permet de lire le multiplicateur utilisé dans la scène courante.
La méthode setGamma()
Cette méthode permet de modifier le contraste entre les valeurs d’énergie de radiosité. Elle admet des valeurs comprises entre [0.2, 10.0]. De la même façon, la méthode getGamma() permet de lire la valeur de contraste utilisée dans la scène courante.
La méthode setConvergence()
Cette méthode permet de définir le seuil d’énergie inférieur en deçà duquel l’énergie n’est plus émise. Elle admet des valeurs comprises entre [0.0, 1.0]. De la même façon, la méthode getConvergence() permet de lire la valeur de convergence utilisée dans la scène courante.
2.2 Radio Tool
Les méthodes qui suivent permettent de mettre en œuvre des fonctions relatives aux boutons du panneau Radio Tool. Ce sont des méthodes propres à la radiosité pré-calculée, et qui permettent de définir le comportement général du simulateur de radiosité. Vous noterez que certaines méthodes (replaceMeshes() et addMesh() en particulier) ne peuvent être utilisées qu’après go(), tandis que celle-ci doit impérativement être précédée de collectMeshes(). Les autres méthodes, étant optionnelles ou acceptant des valeurs par défaut peuvent être omises, mais doivent tout de même précéder go() pour être prises en compte.

 Figure 08 : Le panneau Radio Tool
La méthode collectMeshes()
Cette méthode permet de convertir les maillages visibles et sélectionnés en patches utilisables pour le calcul d’une solution de radiosité. La sélection d’objets au travers de Python est également possible afin de sélectionner ou désélectionner des objets. L’usage de cette méthode est obligatoire dans le cadre de radiosité pré-calculée.
La méthode freeData()
Cette méthode permet de libérer la mémoire allouée à la radiosité, et, par conséquent, de rajouter toute solution déjà établie.
La méthode replaceMeshes()
Comme nous l’avons expliqué, la solution de radiosité est stockée au moyen de la couleur des sommets. Cette méthode permet de remplacer les maillages individuels d’origine en un maillage unique portant la solution de radiosité au niveau de la couleur de ses sommets. La méthode addMesh() est une alternative non destructive de celle-ci, dans la mesure où elle n’autorise pas la destruction des maillages d’origine. Les méthodes replaceMeshes() et addMesh() ne peuvent être employées qu’après la fonction go().
La méthode addMesh()
Cette méthode permet de créer un maillage unique, somme des maillages individuels d’origine, portant la solution de radiosité au niveau de la couleur de ses sommets. La méthode replaceMeshes() est une alternative destructive dans le sens où les maillages d’origine sont effacés. Les méthodes replaceMeshes() et addMesh() ne peuvent être employées qu’après la fonction go().
La méthode setDrawType()
Cette méthode permet de définir le mode d’affichage de la solution de radiosité, en spécifiant entre parenthèses et entre apostrophes le mode d’affichage souhaité parmi ‘Wire’ (fil de fer), ‘Solid’ (facettes colorées) et ‘Gouraud’ (lissage de l’ombrage par la méthode de Gouraud). La méthode getDrawType() permet de lire la méthode d’affichage de la scène courante.
La méthode setMode()
Cette méthode permet d’afficher les modes d’affichage des patches et éléments de la solution de radiosité. Elle accepte comme mode, entre parenthèses et apostrophes, les chaînes de caractères ‘ShowLimits’ et ‘Z’. Vous pouvez activer un mode ou les deux. Pour désactiver ces modes, ne passez aucun argument à la méthode : setMode() désactive alors les deux options. La méthode getMode() permet de lire les modes de la scène courante.
Les méthodes setElemMax() et setElemMin()
Ces méthodes permettent respectivement de déterminer la taille maximale et la taille minimale d’un élément de radiosité. Les valeurs acceptées sont comprises entre [1, 100]. Les méthodes getElemMax() et getElemMin(), pour leur part, permettent de lire les tailles max et min des éléments de radiosité dans la scène courante.
Les méthodes setPatchMax() et setPatchMin()
Ces méthodes permettent respectivement de déterminer la taille maximale et la taille minimale d’un patch de radiosité. Les valeurs acceptées sont comprises entre [10, 1000]. Les méthodes getPatchMax() et getpatchMin(), pour leur part, permettent de lire les tailles max et min des patches de radiosité dans la scène courante.
La méthode limitSubdivide()
Cette méthode optionnelle permet de subdiviser les patches, ce qui peut améliorer les résultats. Lorsque vous appuyez sur le bouton GO du panneau Calculation, elle est automatiquement prise en compte, mais vous devez spécifier son usage lorsque vous passez par Python.
2.3 Calculation
Les méthodes qui suivent permettent de mettre en œuvre des fonctions relatives aux boutons du panneau Calculation. Ce sont des méthodes propres à la radiosité pré-calculée, et permettent d’affiner le comportement particulier du simulateur de radiosité. L’usage de collectMeshes() avant go() est obligatoire, sinon le simulateur de radiosité n’aura aucun élément sur lequel baser ses calculs. La plupart des méthodes doivent être utilisées avant go() pour être prises en compte, à l’exception de celles fonctionnant intervenant sur la solution calculée, comme filterElems() ou filterFaces().

Figure 09Â : Le panneau Calculation
La méthode filterElems()
Cette méthode permet d’appliquer un filtre aux éléments afin de limiter ou supprimer les artefacts dus au crénelage. Cette méthode ne peut être appelée qu’après qu’une solution de radiosité ait été calculée par la fonction go().
La méthode filterFaces()
Cette méthode oblige le simulateur à appliquer un lissage supplémentaire sur les facettes. Cette méthode ne peut être appelée qu’après qu’une solution de radiosité ait été calculée par la fonction go().
La méthode go()
Cette méthode démarre la simulation de radiosité. Il est absolument nécessaire d’avoir collecté tous les maillages au préalable grâce à la méthode collectMeshes().
La méthode removeDoubles()
Cette méthode permet de fusionner les éléments dont la couleur ne diffère que très peu, en fonction de la variation tolérée déterminée par la méthode setElemLimit(). Cette méthode ne peut être appelée qu’après qu’une solution de radiosité ait été calculée par la fonction go().
La méthode setElemLimit()
Cette méthode permet de déterminer l’intervalle sur lequel les éléments seront fusionnés dans le cadre de l’usage de la méthode removeDoubles(). Elle accepte des valeurs comprises entre [0, 50], et l’usage de la méthode getElemLimit() permet de lire la limite de la scène courante.
La méthode setMaxElems()
Cette méthode permet de déterminer le nombre maximum d’éléments pour la solution de radiosité. Elle accepte des valeurs comprises entre [1, 250000], et l’usage de la méthode getMaxElems() permet de lire le nombre maximum d’éléments de la scène courante.
La méthode setMaxSubdivSh()
Cette méthode permet de déterminer le nombre maximal de patches qui sont évalués lors de la première émission d’énergie. Elle admet des valeurs comprises entre [1, 250]. La méthode getMaxSubdivSh() permet de lire la valeur qui a été spécifiée dans la scène courante.
La méthode setSubShElem()
Cette méthode définit le nombre de fois que l’environnement est exploré pour la détection d’éléments. Elle admet des valeurs comprises entre [0, 10]. La méthode getSubShElem() permet de lire la valeur qui a été spécifiée dans la scène courante.
La méthode setSubShPatch()
Cette méthode définit le nombre de fois que l’environnement est exploré pour la détection de patches. Elle admet des valeurs comprises entre [0, 10]. La méthode getSubShPatch() permet de lire la valeur qui a été spécifiée dans la scène courante.
La méthode subdivideElems()
En utilisant cette méthode, les éléments dotés d’une énergie élevée sont détectés et subdivisés. Cette opération est optionnelle, mais permet d’améliorer les résultats de la simulation.
La méthode subdividePatches()
En utilisant cette méthode, les patches dotés d’une énergie élevée sont détectés et subdivisés. Cette opération est optionnelle, mais permet d’améliorer les résultats de la simulation.
2.4 Exemple
Le script suivant permet de préparer la scène pour le calcul d’une solution de radiosité, lance celle-ci et effectue le rendu de la scène. Les lignes 07 à 12 permettent de définir les paramètres généraux de la solution de radiosité. Les lignes 14 à 25 définissent les éléments (récepteurs d’énergie) et les patches (émetteurs d’énergie) de la scène, tandis que les lignes 27 à 30 lancent le calcul de la solution et lui appliquent des traitements destinés à améliorer le résultat visuel. Enfin, les lignes 32 à 34 permettent de lancer le rendu en lui-même.
01: import Blender 02: from Blender import Scene 03: 04: scn = Scene.Get(‘Scene’) 05: scn.makeCurrent() 06: 07: radio = scn.getRadiosityContext() 08: radio.setHemiRes(600) 09: radio.setMaxIter(100) 10: radio.setMult(40) 11: radio.setGamma(3.5) 12: radio.setConvergence(0.1) 13: 14: radio.collectMeshes() 15: radio.setDrawType(‘Gouraud’) 16: radio.setMode(‘ShowLimits’) 17: radio.setElemMax(125) 18: radio.setElemMin(25) 19: radio.limitSubdivide() 20: radio.setMaxElems(100000) 21: radio.setMaxSubdivSh(250) 22: radio.setSubShElem(10) 23: radio.setSubShPatch(10) 24: radio.subdivideElems() 25: radio.subdividePatches() 26: 27: radio.go() 28: radio.addMesh() 29: radio.filterElems() 30: radio.filterFaces() 31: 32: context = scn.getRenderingContext() 33: context.enableRadiosityRender(0) 34: context.render()
A noter qu’en l’état, le maillage unique créé lors de la simulation se superpose à ceux d’origine ; nous vous renvoyons à l’article précédent, sur la manipulation des calques, qui propose un code simple à mettre en œuvre, et qui permet de déplacer des objets sur des calques invisibles. De même, les paramètres passés aux méthodes setSubShElem() et setSubShPatch() sont très élevés : ils testent l’environnement pour localiser les éléments et patches les plus pertinents. Avec une valeur de 0, le test n’est réalisé qu’une seule fois. Avec une valeur de 10, il est réalisé 11 fois. Le test étant réalisé à la fois pour les éléments et les patches, les temps de calcul vont donc être considérablement allongés si vous ré-employez telles quelles ces méthodes ! Dans la vue 3D, la scène va donc être colorée puis réinitialisée 22 fois, avant que le calcul final ne soit lancé.
Conclusion
Le sous-module de radiosité ne pose aucun problème insurmontable ; la première contrainte est de bien comprendre l’ordre dans lequel les méthodes doivent être employées, avec deux pivots incontournables : collectMeshes() et go(), qui doivent nécessairement apparaître dans cet ordre. Certaines autres méthodes doivent impérativement définir les paramètres de simulation avant l’usage de la méthode go(), qui calcule la solution, tandis que d’autres doivent être utilisées après go(), car elles s’appliquent à la solution calculée. La seconde contrainte est bien évidemment de comprendre à quoi servent tous les boutons et paramètres de l’interface de Blender relative à la radiosité, même s’il est possible d’expérimenter en aveugle ; c’est à ce titre que la première partie de cet article est dédiée à une compréhension minimale des mécanismes de radiosité.
Retrouvez cet article dans : Linux Magazine 87

