Et maintenant si on essayait de semer nos billes sur une surface non plane?
Créons donc cette surface.
un petit height_field fera l'affaire, je ne développe pas ce n'est pas
le sujet: je vous renvoie à nouveau vers la Référence:
height_fields
(en bas de la page pour les heigth_fields générés par
fonction)
#declare Terrain=height_field{ function 100,100 {pattern{bozo scale 0.2}} smooth translate <-.5,0,-.5> scale <2,.5,2> pigment{color rgb <1,0.5,0.3>} } object{Terrain}
Vu que nous allons déposer nos objets sur un objet fini,
il serait intéressant d'automatiser encore les choses en demandant à
POV où se situe le terrain.
Dans notre cas présent il est centré sur l'origine mais il pourrait
avoir été déplacé.
min_extent() et son frère max font ça très bien à
condition qu'on ne transforme pas l'objet apres leur appel.
Ils renvoient respectivement les coordonnées minimum et maximum de la
boite englobant un objet
Remplaçons les declarations de Debut et de Fin.
#declare Debut=min_extent(Terrain);
#declare Fin=max_extent(Terrain);
Maintenant, notre balayage se fera sur le height_field où qu'il soit et quelle que soit son échelle.
Fonction trace
Aaaaaahhh voila une fonction qu'elle est intéressante!
trace(Un_objet, A, B, Norm) teste l'intersection d'un rayon sur Un_objet.
Le rayon est lancé à partir du point décrit par le vecteur
A dans la direction décrite par le vecteur B.
Si intersection il y a, trace retourne les coordonnées de cette intersection.
Sinon trace retourne <0,0,0>.
Si on fournit à trace un vecteur optionnel "Norm", trace place
dans ce vecteur la normale de l'objet au point d'intersection (sans inclure
les perturbations éventuelles apportées par une texture). S'il
n'y a pas intersection trace remet ce vecteur à <0,0,0>.
Il faut noter que le test de cette normale est le seul moyen fiable de déterminer
s'il y a intersection ou pas, car une intersection pourrait éventuellement
se faire aux coordonnées <0,0,0> .
Expliquons par la pratique: imaginez une "pluie" de
rayons venant d'au dessus de notre height_field et tombant à la verticale.
On va obtenir cela en gardant le même balayage que précédemment
mais partant d'une altitude arbitrairement au dessus du h_f.
Quelle altitude choisir? Pas vraiment important mais plus haut que le point
le plus haut du h_f semble logique.
Voilà juste pour montrer les départs de rayons
#declare Pas=.1;
#declare Debut=min_extent(Terrain); #declare Fin=max_extent(Terrain); #declare Hauteur_depart=max_extent(Terrain).y+1;// Ici on determine une altitude de départ supérieure au point le plus haut de l'objet-cible #declare Direction=-y; #declare Norm=<0,0,0>; #declare Turb=<1,0,1>*0.0;// Turbulence à 0 pour mieux voir #declare Frequence=4;
#declare Pointeur_z=Debut.z; #while (Pointeur_z<Fin.z) #declare Pointeur_x=Debut.x; #while (Pointeur_x<Fin.x) #declare Position=<Pointeur_x,Hauteur_depart,Pointeur_z>;// Ici, composante y du départ de rayon fixée au dessus de l'objet cible
object { Mon_objet translate Position} #declare Pointeur_x=Pointeur_x+Pas; #end #declare Pointeur_z=Pointeur_z+Pas; #end![]()
Bieeeeeeeen allons y pour trace
#declare Pas=.1;
#declare Debut=min_extent(Terrain);
#declare Fin=max_extent(Terrain);
#declare Hauteur_depart=max_extent(Terrain).y+1;
#declare Direction=-y;// on indique la direction de visée, ici, vers le bas
#declare Norm=<0,0,0>;// on initialise Norm pour en faire un vecteur qui va recueillir la normale
#declare Turb=<1,0,1>*0.2;// on remet de la turbulence(plus bô)
#declare Frequence=4;
#declare Pointeur_z=Debut.z;
#while (Pointeur_z<Fin.z)
#declare Pointeur_x=Debut.x;
#while (Pointeur_x<Fin.x)
#declare Position=<Pointeur_x,Hauteur_depart,Pointeur_z>;
#declare Position=Position +vturbulence(2,.5,6,Position*Frequence)*Turb;
#declare Intersect=trace(Terrain,Position,Direction,Norm);//l'appel de trace()
#if (vlength(Norm))// on teste s'il y a bien intersection (Norm non nul)
object { Mon_objet translate Intersect }// On pose l'objet à l'intersection trouvée
#end
#declare Pointeur_x=Pointeur_x+Pas;
#end
#declare Pointeur_z=Pointeur_z+Pas;
#end
Ici on n'a utilisé la normale que pour tester l'intersection... On pourrait utiliser la normale pour déterminer la pente et éviter de poser des objets là où il y en a trop.
Ah changeons un peu d'objet.
#declare Mon_objet= cone {0,0.02, y*0.1,0 pigment { Yellow}}
Sachant que la longueur (module) de Norm est =1, Norm.y, (la composante verticale de Norm) est le cosinus de l'angle de pente (Angle horizontal=0, Norm.y=1)
Donc par la fonction réciproque et en n'oubliant pas de déclarer Pente_max avant les boucles:
#declare Pente_max=30;
on rajoute un test au coeur de la boucle
#declare Pente=degrees(acos(Norm.y));// degrees() convertit les radians en degrés
#if(Pente<Pente_max)
object { Mon_objet translate Intersect }
#end
Avec Pas=.05 et Pente_max=30 cela donne
Nous pourrions vouloir que notre objet s'oriente suivant la pente du terrain. Par exemple pour un dallage ou des poils ou un aspect velours ou peluche. (Si vous désirez cet aspect velours à moindre coût de calculs, vous pouvez essayez le pattern "aoi" disponible dans mlpov, une version non-officielle de POV). Nous allons utiliser pour cela une macro tres commode contenue dans le fichier "transforms.inc" des includes standards de POV. Il suffit de lui indiquer un vecteur de départ (ici, la verticale de notre objet, c'est à dire y) et un vecteur sur lequel aligner le premier (ici Norm) et le tour est joué.
#include "colors.inc" #include"transforms.inc" // Ne pas oublier d'inclure transforms.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>} #declare Terrain=height_field{ function 100,100 {pattern{bozo scale 0.2}} smooth translate <-.5,0,-.5> scale <2,.5,2> pigment{color rgb <1,0.5,0.3>}} object{Terrain} #declare Mon_objet= cone {0,0.02, y*0.1,0 pigment { Yellow}} #declare Pas=.02;// on diminue le Pas pour reserrer les cônes #declare Debut=min_extent(Terrain); #declare Fin=max_extent(Terrain); #declare Hauteur_depart=max_extent(Terrain).y+1; #declare Direction=-y; #declare Norm=<0,0,0>; #declare Turb=<1,0,1>*0.1; #declare Frequence=4; #declare Pente_max=180;// On accepte toutes les pentes #declare Pointeur_z=Debut.z; #while (Pointeur_z<Fin.z) #declare Pointeur_x=Debut.x; #while (Pointeur_x<Fin.x) #declare Position=<Pointeur_x,Hauteur_depart,Pointeur_z>; #declare Position=Position +vturbulence(2,.5,6,Position*Frequence)*Turb; #declare Intersect=trace(Terrain,Position,Direction,Norm); #if (vlength(Norm)) #declare Pente=degrees(acos(Norm.y)); #if(Pente<Pente_max) object { Mon_objet Reorient_Trans(y,Norm) translate Intersect }// On réoriente l'objet avant de le poser sur l'intersection trouvée #end #end #declare Pointeur_x=Pointeur_x+Pas; #end #declare Pointeur_z=Pointeur_z+Pas; #end plane {y,-.02 pigment{color rgb 0.6}} background {color rgb .6}![]()