Home Map Index Search News Archives Links About LF
[Top Bar]
[Bottom Bar]
Antonio Castro

A propos de l'auteur: Je suis informaticien de profession Et cela fait quelques années que je gagne ma vie avec cela. Ce que je manie le plus souvent c'est le langage C. J'ai également une expérience d'administrateur Unix bien qu'actuellement je fasse surtout du Visual C++ sous WindowsNT (Puaffff qu'est ce qu'il ne faut pas faire pour gagner son pain quotidien) Dés que j'ai eu connaissance de l'existence de Linux et de son mode de développement je me suis dit que le futur devait aller par là. J'ai mis beaucoup d'espoir dans Linux et pour l'instant je n'ai pas été déçu de Linux contrairement à Microsoft.

Ecrire à l'auteur

Index:
L'art et la technique en Infographie
Objets géométriques simples
Objets géométriques composés
Utilisation des boucles et conditions avec Povray
Essais et Echecs, face aux calculs
Oursins de mer
Génération à l'aide d'un programme externe
Optimisation du temps CPU
Quelques mots encore
Exercices
Contributions des lecteurs

Concevoir des structures itératives avec Povray.

Résumé: dans cet article nous verrons comment utiliser Povray pour concevoir des structures répétées et comment obtenir à partir de celle-ci de belles images.


L'art et la technique en Infographie

Cet article sur Povray traite autant des aspects techniques que de ceux qui ne le sont pas. La technique, nous l'avons déjà dit, est importante mais il faut apprendre à en tirer les maximum de profit. L'infographie est si différentes des autres disciplines que peut-être pour quelques uns sera-t-elle le moyen de découvrir leur aptitudes artistiques. Nous n'abandonnerons pas la technique car elle est nécessaire, mais elle est uniquement un instrument pour maîtriser la forme de l'expression. Pour ceci nous continuerons à mêler de manière libre ce que nous avons appris sur la technique avec des aspects plus créatifs. Il s'agit de donner des idées. Des points de départs à partir desquels on peut suivre de nombreux chemins. Il arrive souvent lorsque je conçois des exemples que je prends tellement de plaisir que les choses que je devais traiter dans cet exemple passent au second plan. Une exposition trop systématique des différents concepts seraient par trop ennuyeuse et trop peut didactique. Le manuel de Povray, lui, suit une exposition systématique des différents thèmes. Comme instrument de consultation, c'est parfait, je l'utilise moi-même souvent. A la différence du système méthodique et séquentiel utilisé dans le manuel, j'utilise un méthode dont on peut dire qu'elle suit un cheminement en " spirale ", revenant à des thèmes déjà vus pour les traiter avec plus d'ampleur.

Les scènes que j'utilise comme exemple pour illustrer certains aspects techniques ne seraient que des exercices techniques si je n'essayait de chercher la beauté esthétique et la complétude de la scène même si cela suppose l'introduction d'éléments externes non expliqués dans cet exemple.

Petit à petit nous revisiterons tous les concepts pour que ce qui ne peut-être compris en première lecture trouve un éclaircissement dans de futurs articles. Au contraire, d'autre concepts sont si visuels que très peu d'explications sont nécessaire à leurs sujet, les voir dans un exemple suffit pour pouvoir les appliquer parfaitement, certainement mieux que si nous le lisions dans le manuel sans une image comme exemple. Cependant ceux qui voudrons avancer plus rapidement peuvent bien entendu recourir au manuel de Povray.

Objets geométriques simples

La majeure partie de ces objets nous les avons déjà vus et utilisés dans quelques exemples. Nous les repassons pour nous les remettre en mémoire.

Le nombre de formes que l'on peut concevoir avec ces formes basiques est énormes, et il faut se souvenir que l'utilisation de forme simple peut faire réaliser d'importantes économies sur le temps de calcul de la scène.

  • La sphère

  • sphere { < x, y, z>, rayon ..... } /
    x, y ,z sont les coordonnées du centre de la sphère.
    dans les points de suspension on peut ajouter des expressions pour
    définir l'échelle, les rotations, translations, pigment, texture, etc...
  • cône

  • En fait la syntaxe permet de définir une portion de cône.
    cone { <x1, y1, z1>, rad1 <x2, y2, z2>, rad2 [open] ..... }
    x1, y1, z1 sont les coordonnées du centre de l'une des extrémités
    du cône et rayon1 son rayon.
    X2, y2, z2 sont les coordonnées du centre de la seconde extrémité, rayon est son rayon, pour obtenir un cylindre ouvert il faut ajouter le mot-clé open, sinon il sera plein.
  • Le cylindre

  • cylinder { <x1, y1, z1>, <x2, y2, z2>, rad [open] ...... }
    x1, y1, z1 sont les coordonnées du centre de l'une des extrémités du cylindre et rayon1 son rayon. X2, y2, z2 sont les coordonnées du centre de la seconde extrémité, rayon est son rayon, pour obtenir un cylindre ouvert il faut ajouter le mot-clé open, sinon il sera plein.
    Rappelons que dans le cas de la sphère, le cône et le cylindre on dispose de la possibilité de déformer ces figures en utilisant un facteur d'échelle adéquate. On peut également tenter de déformer d'autres objets, mais dans ces cas le résultat est intéressant car on obtient une figure différente.
  • Le plan

  • plane { <x, y, z>, dist ..... }
    Ici x, y, z ne représente pas un point mais les coordonnées d'un vecteur perpendiculaire à la surface du plan. Dist représente la distance au repère de coordonnées. Rappelons qu'en Povray on peut abréger l'expression d'un vecteur ainsi x=<0, 1, 0>, -z = <0, 0, -1>
    A la place d'un plan on peut utilise une sphère de très grande dimension, cela ne pose pas de problème, nous l'avons déjà utilisé quelques fois.
  • La boîte

  • box { <x1, y1, z1>, <x2, y2, z2>...... }
    x1, y1, z1 sont les coordonnées d'un angle de la boite. X2, y2, z2 sont les coordonnées du coin opposé.

Objets géométriques composés (CSG)

Les primitives CSG permettent de combiner différentes formes simples en une seule plus complète. Après cette composition, nous obtenons un objet que l'on peut manipuler aisément par des changement d'échelle, rotation, translation, textures, etc.. sans avoir à appliquer ces transformations à chaque éléments séparément. Il existe quatre manières de combiner les éléments simples entre eux, plus une cinquième qui s'applique sur un élément seul.
  • Union

  • 'union { object {A} object{B} }'
    Tous les points de appartenant à A ou B
  • Intersection

  • 'intersection { object {A} object {B} }'
    Tous les points de appartenant à A et B
  • Complementaire

  • object {A inverse}
  • Différence

  • 'difference { object {A} object {B} }'
    Tous les points appartenant à A et pas à B
    Equivalent à ' union { object { A } object { B inverse} }'
  • Mélange

  • 'merge { object {A} object {B} }'
    Comme l'union mais supprime les surfaces
    intérieures des composants A et B. Si les objets sont tous les
    deux solides, cela n'a pas d'intérêt.
Dans les exemples qui suivent nous utilisons certaines de ces fonctions.
Afin de construire des objets sans se tromper on peut utiliser le système suivant : Réunissez toutes les primitives qui ajoutent des volumes en un seul objet, ensuite faites l'intersection de cet objet avec les inverses des primitives qui enlève des volumes
#define PommeCroquee = intersection {
 object { PommeEntiere }
 object { Croc1 inverse }
 object { Croc2 inverse }
}
Assurez vous que les figures composées n'aient pas de surfaces en commun car établir à qui appartient cette surface peut conduire à des indéterminations. Pour résoudre ce problème, isoler un des objets.

Utilisation des boucles et conditions avec Povray.

Les éléments d'une scène se décrivent généralement dans un ordre arbitraire. A coté de cela, il y a des situations dans lesquelles il peut être nécessaire d'utiliser des boucles décrivant la scène, pour créer des structures répétitives par exemple. Avec Povray nous avons plusieurs façons de faire cela Un moyen de le faire est d'utiliser les structures de contrôle que propose le langage de Povray. Pour le moment nous avons vu les directives #declare et #include en mentionnant que les autres n'étaient pas aussi importantes. Maintenant nous allons les utiliser car nous verrons qu'elles sont indispensables. Dans l'exemple qui suit, nous utiliserons un programme ecrit directement en langage Povray. Je tiens à dire que personnelement c'est la première fois que j'utilise ceci car je ne le crois pas nécessaire. On peut dire la même chose d'un programme qui créerait le fichier source nécessaire, et nous verrons plus loin un exemple de cette seconde possibilité, que j'utilise peu également. On peut faire un mélange des deux ; Nous verrons que le style de programmation avec Povray n'est pas aussi élégant qu'avec un langage informatique classique. La raison est que Povray se conçoit comme un langage de description de scènes et ces choses sonts des ajouts récents. Nous verrons qu'avec Povray on peut programmer toutes sorte de boucles et d'expressions mathématiques complexes. Mon avis est que cela est bien mais pas indispensable, on peut s'en sortir en utilisant un programme externe qui génère le code source de la scène plus ou mois complexe ou itératif. Je pense que le moyen de réaliser cela n'a rien à voir avec la partie artistique qui est la plus importante et qu'il n'y a pas plus de mérite à le faire par l'une ou l'autre manière. Le plus important c'est l'image finale, dans une moindre mesure cela peut être les effort de développement et la quantité de ressources employées. Si vous connaissez un langage approprié avec lequel vous vous sentez à l'aise utilisez Povray en fin de chaîne de développement. Si vous voulez créer quelque chose de simple, vous vous pouvez utiliser Povray directement. Nous verrons plus loin la manière de le faire, mais avant quelques commentaires.

Essai et erreur, face aux calculs.

Les scènes peuvent se concevoir à partir d'une idée, on la met en oeuvre avec des valeurs approchées, puis l'on va par de petites retouches de preuves en erreurs jusqu'à obtenir le résultat escompté. Si vous pensez que l'on peut tous faire avec ce système vous vous trompez. Dans certaines occasions on est obligé de prendre le crayon une feuille de papier et la calculatrice. Les problèmes que nous avons à résoudre sont des problèmes de géométrie dans l'espace qui nécessite un minimum de connaissances de géométrie et plus particulièrement de trigonométrie si vous voulez réussir certains effets. En règle général il suffit de savoir appliquer quelques formules. Nous en rappelons quelques-unes.

sin(a) = A / C = (Coté opposé / Hypoténuse)
cos(a) = B / C = (Coté adjacent / Hypoténuse)
tan(a) = A / B = (Coté opposé / Coté adjacent)

Egalement:
A = sin(a)/C
B = cos(a)/C
C = sqrt(A^2 + B^2)
Como 2* Pi radians = 360º

1 Radian = 180 / Pi = 57,29577951308232
1º = Pi / 180 = 0,174532925199432957

Ainsi que les domaines de définitions des principales fonctions trigonométriques en fonction du quadrant du cercle trigonométrique.

Quadrante Sinus Cosinus Tangente
0 .. 90 0 .. +1 +1 .. 0 0 .. +Infini
90 .. 180 +1 .. 0 0 .. -1 -Infini .. 0
180 .. 270 0 .. -1 -1 .. 0 0 .. +Infini
270 .. 360 -1 .. 0 0 .. +1 -Infinito .. 0

a = atan(A/B)

Cette dernière fonction est un peu ambiguë car en fait on ne peux pas connaître la valeur de alpha si nous ne connaissons pas le quadrant, c'est pourquoi il est préférable d'utiliser :
a = atan2(A,B)

Distance entre P1(x1, y1, z1) et P2 (x2, y2, z2) égale à

D = sqrt( (x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2 )

Il y a beaucoup de formules utiles en trigonométrie mais avec celles-ci on doit pouvoir résoudre la majeur partie des cas. En Povray, on notera que les fonctions trigonométriques marchent avec des radians et que l'on peut utiliser la fonction de conversion radians(). Au contraire pour les rotations, Povray suppose que l'on travaille en degrés :-(

Oursins de mer

L'exemple suivant est un bon exercice pour réviser sa géométrie. Vous pouvez remarquez que les piquants d'un oursin on un placement bien particuliers que l'on ne peut pas improviser, il faut l'analyser, choisir un algorithme et l'implémenter en connaissant exactement l'effet recherché. Le code source est largement commenté afin d'être le plus clair possible. C'est un cas pratique de déclaration de structure itérative, dans ce cas nous avons choisi d'utiliser Povray comme langage d'implémentation mais il n'existe aucune raisons qui empêchent de le faire d'une autre manière comme nous le verrons plus tard avec un programme externe.

oursins

Nous commençons par le code sources des différentes parties, il s'agit d'une figure composée dans laquelle nous utilisons les primitives CSG décrites plus haut.

// (Copyright) (No modificar estas 11 primeras Lineas) 
// Autor: Antonio Castro Snurmacher  
// (E-mail acastro@ctv.es ) 
// 
// Este fuente puede ser utilizado, distribuido, y modificado
// libremente pero siempre se deberá respetar la propiedad
// intelectual de su autor.  El autor renuncia a todo tipo de
// beneficio económico y no se hace responsable de los
// posibles perjuicios derivados del uso del mismo.  Toda
// modificación queda sujeta a las mismas condiciones de uso
// que el original.  En caso de traducción deberá conservarse
// el texto original de esta cabecera y añadirse la traducción
// a continuación de ella.
// 
// Ce code source peut-être librement utilisé modifié et distribué
// mais doit toujours rester la propriété intellectuelle de l'auteur
// l'auteur renonce à tous bénéfices économiques et ne peut-être
// être tenu responsable des préjudices éventuels causé par son utilisation.
// Toute modification reste sujette aux mêmes conditions que l'original
// En cas de traduction le présent texte doit être conservé et la traduction
// ajoutée à la suite de celui-ci
///////////////////////////////////////////////////// 

//------------------------------------------------------------ 
// balistap.inc (1-Mayo-1998) 
//------------------------------------------------------------ 
// Cette version est destinée à la revue 
//                     LinuxFocus 
//------------------------------------------------------------ 
  

#declare Color1 = color red 0.5 green 0.2 blue 0.4 
#declare ColorEye = color red 0.5 green 0.5 blue 0.5 

// Nageoire inférieure (aleta en esp.)
#declare AletDown =
intersection {
   sphere { <-10,-7,0> 10
      scale <2, 1, 0.1>
   }
   sphere { <-15,-17,0> 10
      scale <2, 1, 1>
      inverse<
   }
   cone { <-10, 0, 0>, 0 <-45, 0, 0>, 20 inverse }
   pigment { color Color1 }
}

// Nageoire supérieure
#declare AletUp =
intersection {
   sphere { <-10,7,0>, 10 
         scale <2, 1, 0.1>
   }
   sphere { <-15, 17,0>, 10 
         scale <2, 1, 1>
         inverse
   }
   cone { <-10, 0, 0>, 0 <-45, 0, 0>, 20 inverse }
   pigment { color Color1 }
}

// nageoire caudale (queue)
#declare Tail =
intersection {
            sphere { <-19,0,0>, 10
                    scale <2, 1, 0.1>
             }
             sphere { <-25,0,0>, 10
             scale <2, 1.3, 1>
             inverse
             }
             pigment { color Color1 }
}

// Poison complet
#declare Balistap =
union{
   sphere { <10, 4,0>,4 
      pigment { color ColorEye }
         scale <1,1, 0.6>
   }
   sphere { <10.2, 4.35,0>,3.43
      pigment { color Gray20 }
         scale <1,1, 0.7>
   }
   sphere { <0,0,0> 10 
         scale <2, 1, 0.3>
        pigment { 
           gradient y 
           colour_map {
                [0.0  colour White]
                [0.1  colour Grey]
                [0.99  colour Black]
           }
          scale <1, 17, 1>
          translate <0, -7, 0>
        }
   }

   cone {<19, 0, 0>, 1.5 <-2, 0, 0> 8
        scale <1,1, 0.5>
        pigment { color Color1 }
   }
   cone {<21, 0, 0>, 1 <0, 0, 0> 13
        scale <1,1, 0.1>
        pigment { color Color1 }
   }
  object {AletUp}
  object {AletDown}
  object {Tail}
}

Maintenant le code principal où l'on défini le reste de la scène. Le plus important est la définition des oursins qui sont indubitablement les protagonistes de la scène.
/////////(Copyright) (No modificar estas 11 primeras Lineas)  
// Autor: Antonio Castro Snurmacher (E-mail acastro@ctv.es ) 
// 
// Este fuente puede ser utilizado, distribuido, y modificado
// libremente pero siempre se deberá respetar la propiedad
// intelectual de su autor.  El autor renuncia a todo tipo de
// beneficio económico y no se hace responsable de los
// posibles perjuicios derivados del uso del mismo.  Toda
// modificación queda sujeta a las mismas condiciones de uso
// que el original. En caso de traducción deberá conservarse
// el texto original de esta cabecera y añadirse la traducción
// a continuación de ella.
//
// Ce code source peut-être librement utilisé modifié et distribué
// mais doit toujours rester la propriété intellectuelle de l'auteur
// l'auteur renonce à tous bénéfices économiques et ne peut-être
// être tenu responsable des préjudices éventuels causé par son utilisation.
// Toute modification reste sujette aux mêmes conditions que l'original
// En cas de traduction le présent texte doit être conservé et la traduction
// ajoutée à la suite de celui-ci
/////////////////////////////////////////////////// 
  

//-----------------------------------------------------------
//erizo.pov (1-Mayo-1998)
//-----------------------------------------------------------
// Cette version est destinée à la revue LinuxFocus
//-----------------------------------------------------------

#include "colors.inc"
#include "textures.inc"
#include "balistap.inc"

#declare RadioCuerpo = 5
#declare NumEspinasMeridiano = 40

// Nous définissons la tailles des piquants en fonction de la taille du
// corps des oursins de mer Dans la nature ils ont des piquants plus
// grands en haut et plus petits en bas
#declare LongitudMaximaPua  = RadioCuerpo * 2
#declare LongitudMinimaPua  = RadioCuerpo / 4

// Couler de l'oursin
#declare TexturePua = texture { pigment {VeryDarkBrown} }
#declare TextureCuerpo = texture { pigment {DarkBrown} }

// toutes les définitions qui suivent dépendent des définitions
// précédentes. Nous supposons tout d'abord que le corps des 
// oursins est sphérique. Pi est une constante prédéfini
// comme

#declare pi = 3.1415926535897932384626
#declare LongitudMeridiano  = 2 * pi * RadioCuerpo

// nous supposons qu'ils sont totalement recouverts de piquants coniques
// le rayon à la base d'un piquant sera : 'RadioPua'  

#declare MeridianoPua =  LongitudMeridiano / NumEspinasMeridiano
#declare RadioPua     =  MeridianoPua / 2

// Nous utilisons la notation longitude/latitude sur l'oursin en
// faisant l'analogie avec les parallèles et méridiens terrestres
// Pour recouvrir totalement l'oursin de piquants
// on trace différents cercles : les parallèles, et pour chaque
// on prends un point de départ ; le méridien de l'oursin
// Nous appellerons angle vertical l'angle
// formé entre l'axe de l'oursin et le point de départ d'un 
// parallèle. Aux pôles c'est angle vaudra 0 et 180 et à l'équateur
//  90. En incrémentant régulièrement cet angle on passera par tous les 
// piquants d'un parallèle. Pour calculer l'incrément angulaire
// on fait une règle de trois LongitudMeridiano
// ---> 360 MeridianoPua ---> IncAngVert

#declare IncAngVert   = 360 * MeridianoPua / LongitudMeridiano

// pour que l'oursin ne soit pas dans le sable ni ne flotte dans
// l'eau on calcule ladistance du centre au bout des piquants
// situés sur la partie basse de l'oursin.

#declare CorreccionY = RadioCuerpo + LongitudMinimaPua
camera {
        location < -40, 40, -40>
        look_at < 25, CorreccionY , 25>
}

// Au fond de la mer la lumière vient de plusieurs points à cause de
// la houle en surface. Pour simuler cela on utilise plusieurs
// sources de lumière

light_source { <-200, 300, -200> color White}
light_source { <-300, 300, -100> color White}
light_source { <-100, 300, -300> color White}
light_source { <0, 1200, 0> color White}

// Ensuite pour la coloration de l'eau on utilise en effet atmosphérique

fog { distance 250 color SeaGreen   }

// Le sable est défini de couleur Sienne avec des ondulations de
// grande amplitude.

plane { y, 0
  pigment { Sienna }
  normal {
  ripples 1.0
  frequency 300.0
  }
  finish {
  ambient 0.1
  diffuse 0.9
  }
  scale <3000, 3000, 3000>
}

// ******************* Définition de l'oursin ****************

#declare erizo = object {
union {

// On calcule un parallèle pour chaque valeur de AngVert
// en partant de 0. (0 piquants dans la direction de l'axe
// vertical.  La seconde valeur sera à peut prés située sur le premier
// parallèle, la valeur maximale sera pour 
// AngVert == a 90 car c'est dans la zone de l'équateur qu'il y a
// le maximum de piquants.  les piquants sur un même méridien 
// se calcule en faisant varier l'angle horizontal :
// 'AngHoriz'

#declare AngVert=0
#while (AngVert < 180 )
#declare RadParalelo = abs ( RadioCuerpo * sin(radians(AngVert)))
#declare LongitudParalelo = 2 * pi * RadParalelo
#declare NumEspinasParalelo = LongitudParalelo / MeridianoPua
#declare LongitudPua = LongitudMinimaPua + (   \
     (LongitudMaximaPua-LongitudMinimaPua) * ((180-AngVert)/180) )
// #declare LongitudPua = LongitudMaximaPua
#declare IncAngHoriz = 360 / NumEspinasParalelo
#declare Ybase = RadioCuerpo * cos (radians(AngVert))
#debug concat("\nAngVert=", str(AngVert,5,0), \
   " LongitudPua=", str(LongitudPua,5,0),     \
   "Ybase=", str(Ybase,5,0), "  ");
#declare Ypunta = (RadioCuerpo + LongitudPua)* \
                      cos (radians(AngVert))
#declare AngHoriz=0
#while (AngHoriz < 360)
#declare Xbase = RadParalelo * cos (radians(AngHoriz))
#declare Xpunta = (RadParalelo + LongitudPua) * \ 
                      cos (radians(AngHoriz))
#declare Zbase = RadParalelo * sin (radians(AngHoriz))
#declare Zpunta = (RadParalelo + LongitudPua) * \
                      sin (radians(AngHoriz))  
//#debug concat( "Vert=", str(AngVert,5,0), \
//               "  Horiz=", str(AngHoriz,5,0), \
//               "\n")     
cone { , RadioPua, , 0 
texture { TexturePua }
}
#declare AngHoriz =AngHoriz + IncAngHoriz
#end
#declare AngVert=AngVert+IncAngVert
#end


// Le corps est une sphère.
sphere { <0,0,0> RadioCuerpo
texture { TextureCuerpo }
}

} // end union
// On le situe à une altitude convenable.
translate y*CorreccionY

// Mais comme les oursins ne sont pas sphériques, se que l'on fait est
// est de conserver les proportions sur l'axe des Y et nous augmentons 
// dans un rapport 1.5 les dimensions sur les axes X et Z.

scale <1.5, 1, 1.5>
} // end object erizo

// Ca y est nous avons un oursin parfait, nous allons le dupliquer
// d'abord nous définissons une distance minimale entre eux.

#declare DistanciaMinima = 3 * (RadioCuerpo+LongitudMaximaPua)

// Nous allons les disposer sur un carré 5 * 5.  Pour éviter 
// qu'ils donnent une impression trop géométrique, nous les déplaçons 
// légèrement en X d'une quantité aléatoire.

#declare Xi=0
#declare R1 = seed(0);
#while (Xi < 5)
#declare Yi=0
#while (Yi<5)
#declare Xpos= Xi * DistanciaMinima + \
           ( rand(R1) * DistanciaMinima * 0.5 )

#declare Ypos= Yi * DistanciaMinima + \
           ( rand(R1) * DistanciaMinima * 0.5 )

#debug concat ("\nXpos=", str(Xpos, 5, 0), \
               "  Ypos=", str(Ypos, 5,0))

object {erizo
translate
}
#declare Yi= Yi+1
#end
#declare Xi= Xi+1
#end

// Nous allons placer les poissons en utilisant une méthode 
// analogue à celle des oursins. Nous allons les placer en
// trois groupes de 4 * 4. Nous allons tout d'abord définir une
// distance minimale entre eux.

#declare DistanciaMinima = 90
#declare Xi=0
#declare R1 = seed(0);
#while (Xi < 4)
#declare Yi=0
#while (Yi<4)
#declare Xpos= Xi * DistanciaMinima + \
       ( rand(R1) * DistanciaMinima * 0.5 )

#declare Ypos= Yi * DistanciaMinima + \
      ( rand(R1) * DistanciaMinima * 0.5 )

#debug concat ("\nXpos=", str(Xpos, 5, 0), \ 
      "  Ypos=", str(Ypos, 5,0))

object { Balistap 
         scale  1.2
         rotate y*50*rand(R1)
         translate
        }

object { Balistap 
         scale  1.2
         rotate y*50*rand(R1)
         translate
        }

object { Balistap 
         scale  1.2
         rotate y*50*rand(R1)
         translate
        }
#declare Yi= Yi+1
#end
#declare Xi= Xi+1
#end

// Nous allons placer l'un deux comme s'il mangeait des
// algues au fond de l'eau.

object { Balistap
         scale 1.1
         rotate z* -45
         rotate y*200
         translate<80, 19, 360>
        }

/** Ceci peut nous servir à voir le poisson en entier *****

object { Balistap 
         scale  1.1
         rotate y*225
         translate<25, 40, 25>
        }

**********************
Il y a des choses dans cette scène que nous n'avons pas commenté. Ce sont les effets sur les surfaces (ondulation du sable). Nous n'avons pas non plus traité des effets atmosphériques (Dans ce cas il s'agit plus d'une purée de pois vert d'eau plus épaisse qu'humide.) :-), de même nous venons d'utiliser les figures composées et nous ne l'avons pas expliqué. Il s'agit de définir une figure comme l'union, l'intersection, la différence ou le complémentaire d'autres formes. En résumé il s'agit de combiner des formes élémentaires pour en obtenir d'autres plus compliquées nous verrons cela dans la suite de cet article.

La lumière de cette scène s'obtient en utilisant de nombreuses sources de lumière pour simuler l'illumination sous-marine caractérisée par le désordre introduit par la houle en surface. Une seule source de lumière nous aurait trahie car l'ombre des oursins sur le sol aurait été trop net.


Génération par un programme externe

Un lanceur de rayon est uniquement un outil pour réaliser le rendu d'une scène que nous avons défini à l'aide d'un langage formel particulier. Celui-ci est capable de comprendre les spécifications de formes, couleurs, lumière mais la plupart du temps il y a un travail inévitable pour obtenir ce que l'on veut en utilisant les modeleurs d'objets et de scènes, les programmes de conversion de formats, programmations. etc.. On peut utiliser toutes sortes d'outils générant un code interprétable par le lanceur de rayons afin de réaliser notre idée. Nous pouvons ainsi générer toutes classes de figures complètes hautement répétitives ou récursives.

Nous allons donner un exemple de ce que nous venons de dire. Le programme qui suit est écrit en C et réalise les choses suivantes : il définit un espace avec les ratios de la résolutions utilisées (1000*750). Une fois que cela est fait le programme place des sphères à des positions aléatoires. Après avoir détecté que la position générée n'est utilisée par une autre sphère il génère la sphère de manière à ce qu'elles ne s'interpénètrent pas. Pour contrôler cela nous garderons en mémoire la position de chaque sphère ainsi que sa taille. Si la position généré tombe sur une sphère existante on essaye une autre position, sinon on calcule la distance minimale à la plus proche des sphères en réduisant la taille si nécessaire, elle sera alors plus petite que la taille initiale et en contact avec une autre sphère. Après un grand nombre d'itérations on obtient une surface pleine de sphère de tailles différentes sans espace entre elles. Ce programme utilise beaucoup de puissance de calcul car à chaque fois que l'on place une sphère on consulte toute la liste des sphères précédemment placées.

/////////(Copyright) (No modificar estas 11 primeras Lineas)
// Autor: Antonio Castro Snurmacher (E-mail acastro@ctv.es ) 
//
// Este fuente puede ser utilizado, distribuido, y modificado
// libremente pero siempre se deberá respetar la propiedad
// intelectual de su autor.  El autor renuncia a todo tipo de
// beneficio económico y no se hace responsable de los
// posibles perjuicios derivados del uso del mismo.  Toda
// modificación queda sujeta a las mismas condiciones de uso
// que el original. En caso de traducción deberá conservarse
// el texto original de esta cabecera y añadirse la traducción
// a continuación de ella.  
//
// Ce code source peut-être librement utilisé modifié et distribué
// mais doit toujours rester la propriété intellectuelle de l'auteur
// l'auteur renonce à tous bénéfices économiques et ne peut-être
// être tenu responsable des préjudices éventuels causé par son utilisation.
// Toute modification reste sujette aux mêmes conditions que l'original
// En cas de traduction le présent texte doit être conservé et la traduction
// ajoutée à la suite de celui-ci
/////////////////////////////////////////////////////////////

//-----------------------------------------------------------
//burbujas.c (1-Mayo-1998) */
//-----------------------------------------------------------
//Cette version est destinée à la revue
//LinuxFocus
//-----------------------------------------------------------

  

/*************************************************************/ 
/** compilation : cc balls.c -lm -o balls **/
/*************************************************************/ 

#include 
#include 
#include 

#define MAX_X       1000.0
#define MAX_Z        750.0
#define MAX_BALLS   10000
#define MIN_RAD     3.0
#define MAX_RAD     55.0

double PosX[MAX_BALLS];
double PosZ[MAX_BALLS];
double Rad[MAX_BALLS];
int contBall=0;
int contIter=0;
int i;

/*****************************************/
void intento(double x, double z, int cont){
   double distX2;
   double distZ2;
   double rad, cur_rad;

   contIter++;
   rad=MAX_RAD;
   for (i=0; i MAX_RAD)
         rad = MAX_RAD;
   if (rad >= MIN_RAD ){
       Rad[contBall]=rad;
       PosX[contBall]=x;
       PosZ[contBall]=z;
       printf("sphere { <%4.0f, 0, %4.0f> %3.7f
               texture { textureBall } } //(%d/%d)\n",
               x, z, rad, contBall,contIter);
       contBall++;
       if ( (contBall >= MAX_BALLS) )  ){
              exit(0);
       }
          else{
              return;   /** boule suivante **/
          }
   }
   return;
}

/****************************************/
int r_rand(int m){
   return (int) ( (double)m * rand()/(RAND_MAX+1.0));
}

/****************************************/
main (){
  int X, Z;

  for(;;){
        X=r_rand(MAX_X);
        Z=r_rand(MAX_Z);
        X -= MAX_X/2;
        Z -= MAX_Z/2;
        intento(X, Z, contBall);
   }
}
Une fois compilé nous l'exécutons avec la sortie redirigée dans un fichier 'burbujas.inc' ou l'on récolte les données. burbujas > burbujas.inc La sortie obtenue ressemble à ceci:
sphere{<-375, 0,   33> 55.0000000 texture{Gold_Metal}} //(0/1)
sphere{< -86, 0,   62> 55.0000000 texture{Gold_Metal}} //(1/2)
sphere{<-326, 0,  346> 55.0000000 texture{Gold_Metal}} //(2/3)
sphere{< 190, 0, -156> 55.0000000 texture{Gold_Metal}} //(3/4)
sphere{<  62, 0, -293> 55.0000000 texture{Gold_Metal}} //(4/5)
sphere{< 323, 0,  161> 55.0000000 texture{Gold_Metal}} //(5/6)
sphere{< 341, 0,  -15> 55.0000000 texture{Gold_Metal}} //(6/7)
...................

Il faut prendre patience mais si nous voyons que cela prends beaucoup de temps et n'avance pas, on peut interrompre le programme. Il suffi d'éditer le fichier et de s'assurer que les dernières lignes sont enregistrées sinon on le quitte. Le code source de pov sera le suivant:

/////////(Copyright) (No modificar estas 11 primeras Lineas)
//Autor: Antonio Castro Snurmacher (E-mail acastro@ctv.es )
// 
// Este fuente puede ser utilizado, distribuido, y modificado
// libremente pero siempre se deberá respetar la propiedad
// intelectual de su autor.  El autor renuncia a todo tipo de
// beneficio económico y no se hace responsable de los
// posibles perjuicios derivados del uso del mismo.  Toda
// modificación queda sujeta a las mismas condiciones de uso
// que el original. En caso de traducción deberá conservarse
// el texto original de esta cabecera y añadirse la traducción
// a continuación de ella.
//
// Ce code source peut-être librement utilisé modifié et distribué
// mais doit toujours rester la propriété intellectuelle de l'auteur
// l'auteur renonce à tous bénéfices économiques et ne peut-être
// être tenu responsable des préjudices éventuels causé par son utilisation.
// Toute modification reste sujette aux mêmes conditions que l'original
// En cas de traduction le présent texte doit être conservé et la traduction
// ajoutée à la suite de celui-ci

//////////////////////////////////////////////////////////////
  

//------------------------------------------------------------

// burbujas.pov (1-Mayo-1998) 
//------------------------------------------------------------

// Cette version est destinée à la revue
// LinuxFocus
//------------------------------------------------------------

// Il est recommandé d'utiliser la commande suivante pour 'pov'
//        pov burbujas 6 9 1 4  
//                     ^ ^ ^ ^  
//                     | | | |  
//  Résolution ________/ | | |  
//  Qualité _____________/ | |
//  A partir de Clock = 1 _/ |  
//  jusqu'à Clock = 4 _______/  

#include "colors.inc"
#include "textures.inc"

// Par défaut max_trace_level vaut 5 . On l'augmente à 15
// afin d'obtenir un meilleur niveau de détail dans les images
// générées par les reflets

global_settings {
#max_trace_level 15
}

// On définit différent points de vue en en utilisant qu'un
// en fonction de la valeur de Clock

#declare img1 =
camera {
  location <0, 10000 ,0 >
  look_at <0, 0, 0>
  angle 7
}

#declare img2 =
camera {
  location <0, 250 ,0 >
  look_at <0, 0, 0>
  angle 130
}

#declare img3 =
camera {
  location <12, 3 ,12 >
  look_at <200, 3, 50>
  angle 30
}

#declare img4 =
camera {
  location <12, 3 ,12 >
  look_at <200, 3, 50>
  angle 120
}

  #switch (clock)
    #case (1)
      // This section is parsed if clock=1
       camera {img1}
    #break  
    #case (2)
      // This section is parsed if clock=2
       camera {img2}
    #break  
    #case (3)
      // This section is parsed if clock=4
       camera {img3}
    #break 
    #case (4)
      // This section is parsed if clock=5
       camera {img4}
    #break 
    #else
      #warning "Clock outside expected range\n"
  #end // End of conditional part

// Une source de lumière blanche
object {
  light_source {
  <100, 1000, 100>
  color White
  }
}

#declare textureBall = texture { Gold_Metal }

// le fichier inclus 'burbujas.inc' est un fichier obtenu
// à partir de la sortie d'un programme C.

#include "burbujas.inc"
Nous venons d'utiliser la valeur clock mais dans ce cas avec un but différent. Dans ce cas nous ne cherchions pas à définir une séquence d'images correspondant à une animation, mais à quatre images différentes par la variation de la position, l'angle et la focale de la caméra.

Je vous avais dit dans un article précédent que nous verrions l'utilisation de la caméra. Nous pouvons nous référer à cet exemple : on peut y voir les effets de perspective obtenu par l'utilisation d'un angle très petit ou bien très lointain. Ou bien l'utilisation d'un angle très ouvert puis très fermé. l'angle maximal d'ouverture est de 180 degrés. C'est un cas extrême où l'on ne distingue plus les formes. Comme vous pouvez le constater une simple utilisation de la caméra peut produire des effets intéressants.

Les rendus ont été effectués sur un Pentium 200 MMX 48 MB Ram. En utilisant 'pov' avec la commande suivante:


pov burbujas 6 9 1 5 1 5

Les paramètres et leurs significations sont:

  • On utilise le source $HOME/dat/pov/LF2-Burb1/LF2-Burb1.pov
  • taille 6 = (400x300)
  • Qualité 9
  • image initiale = 1
  • image finale = 5
  • clock initiale = 1
  • clock finale = 5
La différence de temps entre les différentes images est importantes. Pour la meilleur qualité on obtient les temps suivants :
pov burbujas 9 9 1 5 1 5

Temps total = 4 heures et demi.
première image 2 minutes.
seconde image 5 minutes.
troisième image 10 minutes.
quatrième image 13 minutes.
cinquième image 4 heures !!

Regardons les résultats. Tout d'abord sur les quatre premières images seule la caméra varie. (position, angle, direction, etc.)

Il manque une image que nous montrerons plus tard, mais d'abord nous allons traiter quelques questions en relation avec cette dernière image.

Optimisation du temps de calcul

Comme nous l'avons vu la dernière image est la plus complexe et Povray n'a pas sut l'optimiser. Quand on définit une figure composée le programme essaye de trouver une figure plus simple l'englobant.

Dans les versions antérieures de Povray il fallait le faire à la main. Cela se faisait par la primitive 'bounded_by' qui permet de définir une primitive qui englobe un ou plusieurs objets et de cela le programme suppose que les rayons ne passant pas dans ce volume ne passent pas non plus sur les objets à l'intérieur. Aujourd'hui il reste peut de cas où une optimisation manuelle reste nécessaire, mais ici c'est le cas.

La dernière image est une figure composée très complexe. Pour améliorer cela nous allons grouper les sphères par zones ou bien toutes les grouper comme dans l'exemple mais par groupes bien localisés et délimités par une primitive englobante en utilisant 'bounded_by'. La syntaxe sera la suivante:

    union {
    sphere { <x1, y1, z1>, r1 } 
    sphere { <x2, y2, z2>, r1 }
    sphere { <x3, y3, z3>, r1 }
    ..........................
    bounded_by { sphere { <xb, yb, zb>, rb } }
  }

On peut appliquer des formes obtenue par unions ou intersections etc. mais également n'importe quel objet et l'on peut utiliser dans 'bounded_by' une forme quelconque bien que les meilleurs résultats s'obtiennent avec les sphères et les boites.

Si la forme choisie n'inclue pas tout l'objet le résultat peut-être mauvais. Je rappelle que la plupart du temps il n'est pas nécessaire de faire cette optimisation. Ce dernier exemple est un cas particulier où l'optimisateur de Povray ne pouvais pas faire mieux. Il s'agit tout de même d'un objet composé de 2154 sphères. Vous pouvez les compter si vous ne me croyez pas. :-) La dernière image est le résultat d'expérimentation avec Pov.

La plupart du temps, d'une même idée on peut faire plusieurs choses et c'est ici qu'entre en scène notre imagination et notre créativité La plupart du temps il n'est pas suffisant de partir d'une bonne idée mais il faut aussi se laisser à imaginer et à jouer avec les différentes possibilités que nous avons rencontrées et qui nous plaisent.

On peut imaginer des quantité de scènes dans lesquelles la programmation peut servir de base à la génération d'images de synthèse statiques ou dynamiques.

Encore quelques mots.

Povray fournit de nombreuses fonctions mathématiques plus ou moins intéressantes, mais il y en a une très intéressantes qui manque. Je veux parler de la fonction spline. Il n'y a rien de plus commode que de tracer avec un crayon et du papier ne série de points et d'appliquer une fonction qui nous donne une courbe passant par chacun de ces points. La primitive Spline de Povray ne peut pas s'utiliser comme une fonction, elle sert à générer une ligne pour construire des formes de bases, mais cela serait bien mieux si l'on pouvait l'appliquer aux variables que l'on veut. On pourrait en faire des trajectoires de caméra par exemple. Il serait bien également que l'on puise implémenter n'importe quelle fonction...

Quoiqu'il en soit cela peut se contourner en utilisant les inclusion et la programmation. Nous avons sous Linux un utilitaire appelé 'spline'. Il s'utilise comme une commande et génère en sortie la courbe désirée à partir d'une entrée qui peut-être une suite de points. Il peut-être très utile de combiner cette commande avec un programme externe pour obtenir des trajectoires ou bien des animations.

Exercices

  • Si certains en ont la curiosité il peuvent essayer comme exercice d'optimiser la dernière image en suivant les recommandations que nous venons de faire.
  • Passer le programme burbujas.c en langage Povray.
  • Passer le erizos.c dans un langage de programmation classique.

Contributions des lecteurs.

Si des lecteurs implémentent des algorithmes pour la construction de formes récursives ou itératives Ils peuvent m'envoyer leurs expérimentations sous forme de sources comprimées en gzip ou d'image comprimées sous n'importe quel format. S'il y a assez de matière nous pourrons les inclure dans un article dédié à Povray les images les plus curieuses accompagnée des sources. Veillez à n'utilisez aucun outils intermédiaires pouvant poser des problèmes de licences, de droit ou de royalties. Je suis intéressé par toutes sources Povray.

pov3.tar.gz, source des programmes de cet articles (42652 bytes)


Texto original en Castellano
Traduction Mathieu Veron


© Antonio Castro 1998
LinuxFocus 1998