Sur ce détail
d'une image faite avec POV, on peut voir de l'herbe sur la côte. L'herbe
épouse les courbes du terrain et ne pousse pas en dessous d'un certain
niveau ni à partir d'un certaine pente.La côte est un height_field
(HF) et l'herbe est une union de quelques meshs plantée dessus en balayant
toute l'étendue du HF.
Comme dans un texte tapé à la machine, on tape une ligne puis,
arrivé au bout de la ligne, on passe à la suivante en effectuant
un retour charriot.
De cette maniere on scanne la surface du HF (ce pourrait etre n'importe quel
objet, primitive, mesh, CSG etc...)
Nous allons étudier comment réaliser cela.
Posons quelques préliminaires
à notre scène :une caméra othographique pour garder une
vision claire des choses) et une lumière.
Nous ne les répèterons
pas dans les versions successives du code.
#include "colors.inc" background { color White } camera { orthographic location <-1,3,-2> look_at 0 right 1.33*x *2.5 up y*2.5 } light_source {0 color rgb 2 translate <-20, 400, 0>}
//Créons
un objet exemple. Ce pourrait être n'importe quoi, un brin d'herbe, un
bonhomme, un arbre...mais restons modestes pour l'instant ;-)
#declare Mon_objet= sphere {0,0.02 pigment { Yellow}}
Ceux qui n'ont pas de problèmes avec les boucles peuvent passer directement à la page suivante pour étudier la fonction trace()
Etudions
d'abord le balayage.
Commençons
simple, essayons de voir comment répartir régulièrement
des copies d'un objet.
On pourrait faire
object{Mon_objet translate <0,0,0>} object{Mon_objet translate <1,0,0>} object{Mon_objet translate <2,0,0>} /... .../ object{Mon_objet translate <100,0,0>} // nouvelle ligne object{Mon_objet translate <0,0,1>} object{Mon_objet translate <1,0,1>} object{Mon_objet translate <2,0,1>} /... .../ object{Mon_objet translate <2,0,100>} etc...
Ce serait cependant
(très) fastidieux et pas (du tout) très paramétrable.
Tâchons d'automatiser un peu les choses.
Nous avons dans le SDL (Scene Description Language), le langage de POV, la possibilité
de faire effectuer des boucles c'est à dire que quand POV lit (parse)
le code avant de calculer (trace) l'image il lit une section du code en boucle.
Evidemment, il ne faut pas oublier de lui offrir une sortie sinon, il parse
sans arrêt la boucle.
On pose donc une condition à la poursuite de la boucle.
#while (Condition) // Corps de la boucle #end
Au début de la boucle, POV teste si la condition est toujours
remplie, si oui il recommence, sinon, il continue la lecture du code après
la fin de boucle (#end).
Vous pouvez consulter "Boucles
while/end" dans la Référence, excellent site explicatif
sur POV,en Français
Faisons une ligne.
Avant d'entamer
la boucle, il faut initialiser quelques variables comme un pointeur de balayage
qu'on va changer à chaque passage dans la boucle.
Il servira à recalculer une ou des variables à chaque passage
dans la boucle (pour déterminer de nouvelles coordonnées par exemple).
Il servira également à déterminer s'il faut sortir de la
boucle ou la recommencer.
C'est une forme tres classique de boucle.
Nous allons en
profiter pour déclarer aussi quelques paramètres comme les coordonnées
de départ et d'arrivée du balayage ainsi que le pas de balayage
(l'intervalle entre les objets).
Chaque fois que possible, on déclarera les coordonnées sous forme
de vecteur, cela permet de les regrouper dans une seule variable.
Si nécessaire, on peut extraire une composante, x, y ou z à l'aide
de ".x",
".y" ou
".z"
#declare Debut=<-1,0,-1>;// C'est un vecteur, il contient les coordonnées dans l'espace du début du balayage // On n'oublie pas le point virgule, comme apres toute déclaration de vecteur out de nombre, sinon "BLING!" #declare Fin=<1,0,1>; // Pareil pour le point de fin de balayage #declare Pas=0.1;// distance entre deux copies successives de l'objet #declare Pointeur_x=Debut.x; //on initialise le pointeur de balayage en lui //assignant la composante x du vecteur de Debut #while (Pointeur_x<Fin.x) //Tant que le pointeur x est plus petit que la coordonnée x //de la Fin, le code revient dans la boucle et pose des copies de l'objet #declare Position=<Pointeur_x,0,0>; //on compose le vecteur contenant les coordonnées où poser l'objet à chaque passage dans la boucle object { Mon_objet translate Position} #declare Pointeur_x=Pointeur_x+Pas; //On augmente le pointeur de la valeur de l'intervalle entre les objets #end //Fin de la boucle
Bon c'est sympa mais ça ne fait qu'une ligne :-/.
Faisons plusieurs lignes
Comment faire
pour obtenir plusieurs lignes?
Bon sang, mais c'est bien sur! Une autre boucle (qu'on va appeler "boucle
Z" entre nous) qui répetera notre boucle X plusieurs fois.
Il faudra que la boucle X soit à
l'intérieur de la boucle Z.
Le code donne ça
#declare Debut=<-1,0,-1>; #declare Fin=<1,0,1>; #declare Pas=0.1; #declare Pointeur_z=Debut.z; //On met le pointeur z au depart #while (Pointeur_z<Fin.z) //Debut boucle z et test #declare Pointeur_x=Debut.x; //remise du pointeur x au départ à chaque boucle z #while (Pointeur_x<Fin.x) //début de boucle x #declare Position=<Pointeur_x,0,Pointeur_z>; object { Mon_objet translate Position} #declare Pointeur_x=Pointeur_x+Pas; #end //Fin de la boucle x #declare Pointeur_z=Pointeur_z+Pas; #end //Fin de la boucle z
Vous pouvez vous amuser avec différentes valeurs de Debut, Fin et Pas.
bon, vous allez me dire que c'est tres régulier, et vous aurez raison.
Introduisons un peu de désordre:
Il existe une fonction intéressante dans pov: vturbulence(Lambda, Omega, Octaves, A)Nous allons prendre le vecteur Position et lui ajouter la vturbulence en lui appliquant un taux nommé Turb (dont la composante Y restera nulle pour ne pas turbuler l'objet verticalement.)
#declare Pas=0.1; #declare Debut=<-1,0,-1>; #declare Fin=<1,0,1>; #declare Turb=<1,0,1>*0.2; // taux de turbulence nul sur y pour laisser les objets au meme niveau #declare Pointeur_z=Debut.z; #while (Pointeur_z<Fin.z) #declare Pointeur_x=Debut.x; #while (Pointeur_x<Fin.x) #declare Position=<Pointeur_x,0,Pointeur_z>; #declare Position=Position +vturbulence(2,.5,6,Position)*Turb; // ici vturbulence object { Mon_objet translate Position} #declare Pointeur_x=Pointeur_x+Pas; #end #declare Pointeur_z=Pointeur_z+Pas; #end
On obtient ceci:
On a effectivement
de la turbulence mais le "mouvement" semble ample, de basse fréquence.
Les objets ont des positions liées (corrélées?) à
celles de leurs voisins, un peu comme sur des vagues.
On peut désirer cet effet, on peut aussi désirer des positions
plus indépendantes.
Cela changerait si on multipliait le vecteur d'entrée ("A"
dans le modèle de vtubulence) par une valeur appelée euh... au
hasard Frequence.
On peut décrire cela en disant que la position d'un objet serait moins
liée à celle de ses voisins.
En effet, vturbulence irait chercher des positions plus distantes les unes des
autres pour déterminer la turbulence des objets voisins .
#declare Pas=0.1; #declare Debut=<-1,0,-1>; #declare Fin=<1,0,1>; #declare Turb=<1,0,1>*0.2; #declare Frequence=4; // Déclaration de la Frequence #declare Pointeur_z=Debut.z; #while (Pointeur_z<Fin.z) #declare Pointeur_x=Debut.x; #while (Pointeur_x<Fin.x) #declare Position=<Pointeur_x,0,Pointeur_z>; #declare Position=Position +vturbulence(2,.5,6,Position*Frequence)*Turb; // ici Frequence object { Mon_objet translate Position} #declare Pointeur_x=Pointeur_x+Pas; #end #declare Pointeur_z=Pointeur_z+Pas; #end
Voila:
Nous pouvons maintenant passer à la page suivante pour étudier la fonction trace() Retour page d'accueil