| Vous savez que vous avez fait trop de raytracing quand ... |
| ... Vos amis sont habitués au fait que vous vous arrêtez subitement de marcher pour regarder des objets et chercher à savoir comment les faire avec des CSG. |
| -- Jeff Lee |
'Constructive Solid Geometry', ou CSG, est un puissant outil pour combiner des objets primitifs, et construire des objets plus complexes que ceux vus jusqu'alors.
CSG veut dire Constructive Solid Geometry. POV-Ray nous permet la construction de solides complexes, par la combinaison de formes primitives selon quatre modes différents. Il y a l'union, où deux formes ou plus sont combinées pour faire un nouvel objet. L'intersection qui est l'aire commune aux formes combinées ensembles. La difference, où les formes successives se retranchent de la première. Et le dernier mais pas le moindre, la fusion (merge), qui est comme une union où les surfaces internes sont ôtées (utile dans les objets CSG transparents). Nous verrons chacun d'eux dans le détail dans les sections suivantes.
Les objets CSG peuvent être extrêmement complexes. Ils peuvent être profondément emboîtés. En d'autres mots, il peut y avoir des unions de différences, des intersections de fusions ou des différences d'intersections ou même des unions d'intersections de différences de fusions... ad infinitum. Les objets CSG sont (presque toujours) finis, et peuvent donc être encapsulés et transformés comme n'importe quelle autre primitive de POV.
Essayons de faire une simple union. Créez un fichier appelé csgdemo.pov et modifions-le comme suit :
#include "colors.inc" camera { location <0, 1,-10> look_at 0 angle 36 } light_source {<500, 500,-1000> White} plane {y,-1.5 pigment {checker Green White} }
Ajoutons deux sphères, chacune déplacée de 0.5 unités dans les deux directions de l'axe x. L'une sera bleue et l'autre rouge.
sphere {<0, 0, 0>, 1 pigment {Blue} translate -0.5*x } sphere {<0, 0, 0>, 1 pigment {Red} translate 0.5*x }
Nous traçons ce fichier et voyons le résultat.

Maintenant, nous plaçons un bloc union autour des deux sphères. Cela créera une simple union CSG de deux objets.
union { sphere {<0, 0, 0>, 1 pigment {Blue} translate -0.5*x } sphere {<0, 0, 0>, 1 pigment {Red} translate 0.5*x } }
Nous traçons de nouveau ce fichier.

Il n'y a aucune différence, mais maintenant nous pouvons donner une unique texture à l'union et la transformer dans son ensemble. Faisons-le maintenant.
union { sphere {<0, 0, 0>, 1 translate -0.5*x } sphere {<0, 0, 0>, 1 translate 0.5*x } pigment {Red} scale <1, .25, 1> rotate <30, 0, 45> }
Nous traçons le fichier encore une fois.

Comme nous pouvons le voir, l'objet a radicalement changé. Nous pouvons expérimenter d'autres échelles et rotations, ainsi que d'autres textures.
Il y a de nombreux avantages à attribuer une texture à un CSG au lieu de le faire pour chaque élément. Premièrement, changer l'apparence des objets se résume à changer une seule texture. Deuxièmement, le rendu est plus rapide car la texture n'est calculée qu'une fois. Cela peut être important avec de riches scènes ou des animations. Troisièmement, nous sauvegardons de la mémoire, car la texture n'est chargée qu'une fois et référencée par tous les composants du CSG. Assigner la texture à chacun des composants oblige à la stocker autant de fois.
Maintenant, utilisons les mêmes sphères pour illustrer le type suivant de CSG : l'intersection. Nous changeons le mot union par intersection et détruisons les déclarations d'échelle et de rotation :
intersection { sphere {<0, 0, 0>, 1 translate -0.5*x } sphere {<0, 0, 0>, 1 translate 0.5*x } pigment {Red} }
Nous traçons le fichier et voyons une lentille au lieu de deux sphères.

C'est parce que l'intersection représente l'aire commune aux deux sphères. Nous aimons cette lentille, alors nous allons l'utiliser pour démontrer les différences.
Nous faisons tourner la lentille autour de l'axe y pour qu'elle fasse face à la caméra.
intersection { sphere {<0, 0, 0>, 1 translate -0.5*x } sphere {<0, 0, 0>, 1 translate 0.5*x } pigment {Red} rotate 90*y }
Créons un cylindre et plantons-le au milieu de la lentille.
cylinder {<0, 0,-1> <0, 0, 1>, .35 pigment {Blue} }
Nous rendons la scène pour voir la position du cylindre.

Nous allons placer un bloc différence autour des deux objets, comme ceci :
difference { intersection { sphere {<0, 0, 0>, 1 translate -0.5*x } sphere {<0, 0, 0>, 1 translate 0.5*x } pigment {Red} rotate 90*y } cylinder {<0, 0,-1> <0, 0, 1>, .35 pigment {Blue} } }
Nous rendons la scène et voyons que la lentille est trouée là où se trouvait le cylindre.

Le cylindre a été soustrait de l'intersection. Notez que la pigmentation du cylindre a coloré la surface du trou en bleu. Si nous enlevons ce pigment, la surface sera noire, car c'est la couleur par défaut si aucune n'est spécifiée.
OK, soyons un peu fou maintenant. Déclarons notre lentille perforée comme un objet pour la nommer. Eliminons aussi toutes les textures, parce que nous voulons plutôt les placer sur l'union finale.
#declare Lens_With_Hole = difference { intersection { sphere {<0, 0, 0>, 1 translate -0.5*x } sphere {<0, 0, 0>, 1 translate 0.5*x } rotate 90*y } cylinder {<0, 0,-1> <0, 0, 1>, .35} }
Utilisons une union pour construire un objet complexe de copies de notre lentille.
union { object {Lens_With_Hole translate <-.65, .65, 0>} object {Lens_With_Hole translate <.65, .65, 0>} object {Lens_With_Hole translate <-.65,-.65, 0>} object {Lens_With_Hole translate <.65,-.65, 0>} pigment {Red} }
Nous rendons la scène.

C'est un objet intéressant, sûr. Mais essayons quelque chose de plus. Ajoutons un peu de filtre au bloc pigment pour faire un objet partiellement transparent.
union { object {Lens_With_Hole translate <-.65, .65, 0>} object {Lens_With_Hole translate <.65, .65, 0>} object {Lens_With_Hole translate <-.65,-.65, 0>} object {Lens_With_Hole translate <.65,-.65, 0>} pigment {Red filter .5} }
Nous rendons encore la scène.

Cela semble bon... sauf... nous pouvons distinguer chaque objet lentille de l'union ! Ce n'est pas bon.
Cela nous amène au quatrième type de CSG, la fusion. Les fusions sont identiques aux unions, mais les surfaces internes à la CSG ne sont pas dessinées. Cela devrait éliminer le problème précédent. Essayons.
merge { object {Lens_With_Hole translate <-.65, .65, 0>} object {Lens_With_Hole translate <.65, .65, 0>} object {Lens_With_Hole translate <-.65,-.65, 0>} object {Lens_With_Hole translate <.65,-.65, 0>} pigment {Red filter .5} }

Absolument, elle le fait !
Il y a des pièges sérieux dans le code CSG dont vous devez vous méfier.
POV-Ray utilise des tests interne/externe pour déterminer les points d'une CSG qui interceptent les rayons. Un problème survient quand les surfaces de deux différentes formes coïncident parce qu'il n'y a aucun moyen (dû aux problèmes de précision numérique) de dire si un point appartient à l'un ou l'autre des objets.
Regardez l'exemple suivant, où un cylindre est utilisé pour trouer une boîte plus large.
difference { box {-1, 1 pigment {Red}} cylinder {-z, z, 0.5 pigment {Green}} }
Note : les vecteurs -1 et 1 de la définition de la boîte correspondent respectivement à <-1,-1,-1> et <1, 1, 1>.
Si nous traçons cette image, nous verrons des points rouges là où est censé se trouver le trou.

Cela est dû à la coïncidence des surfaces de la boîte et du cylindre. Une fois, c'est la surface du cylindre qui est touchée en premier, rendant correctement le trou, l'autre fois, c'est la boîte, laissant un point rouge. Ce problème peut être résolu en augmentant la taille du cylindre pour se débarrasser des surfaces coïncidentes. C'est fait par :
difference { box {-1, 1 pigment {Red}} cylinder {-1.001*z, 1.001*z, 0.5 pigment {Green}} }

En général, dans une différence, nous devons faire en sorte que l'objet soustrait soit le plus large. Nous devons surveiller les coïncidences, et augmenter judicieusement la taille de l'objet soustrait pour éliminer le problème.
Le même problème apparaît dans les intersections, et est aussi éliminé en modifiant des tailles.
| 2.2.4 La source de lumière |