vers l'index général de l'aide

la fonction trace

objectif

Trouver, sur la surface d'un objet, le premier point d'intersection avec une droite donnée. Une application courante est la disposition automatique de plein de petits objets sur un grand objet (arbres sur un terrain,...).

trace est une fonction qui retourne un vecteur. On peut l'utiliser partout où un vecteur est demandé.

compatibilité

MegaPOV

syntaxe

#declare Normale_du_Point = <0,0,0>;
#declare Point_Intersection = 
  trace ( Objet,             //définition d'objet, ou objet déclaré
          Point_Depart,      //vecteur
          Direction_Rayon,   //vecteur
          [Normale_du_Point] //identification de vecteur
          );

L'objet vers lequel on va "lancer un rayon" peut être n'importe quel type d'objet, peu importe sa complexité. Bien entendu, la détermination d'une intersection sur un objet complexe prend plus de temps que sur un objet simple. En fait, c'est l'algorithme d'intersection déjà présent dans POV-Ray qui est mis à la disposition de l'utilisateur.

Le rayon envoyé sur l'objet a deux caractéristiques : son point de départ et son orientation. Le point de départ est un simple point dans l'espace, tandis que la direction est définie à l'aide d'un vecteur partant de l'origine. Le rayon d'intersection pointera dans la même direction que ce vecteur.

Enfin, il est possible de spécifier le nom d'un vecteur dans lequel la normale de la surface de l'objet au point d'intersection sera stockée. N'oubliez pas d'initialiser préalablement ce vecteur.

La fonction trace renvoie, au final, un vecteur qui correspond aux coordonnées du premier point d'intersection entre le rayon lancé et l'objet testé.

et si il n'y a pas d'intersection ?

Dans ce cas, la fonction retourne <0,0,0> comme position du point d'intersection, et place <0,0,0> dans le vecteur qui stocke la normale de la surface en ce point. Ceci est très important, car c'est le seul moyen de vérifier si une intersection a eu lieu ou pas. En effet, une normale de <0,0,0> n'existe pas, et il suffit de vérifier si ce vecteur est nul ou pas pour savoir si une intersection a eu lieu. Par exemple, si on "bombarde" un objet de rayons aléatoires, afin d'y placer des petits objets, sans faire cette vérification, beaucoup de petits objets se retrouveront inutilement placés à <0,0,0>. Il est donc utile de conditionner le placement de ces objets à la non-nullité de la normale. Nous verrons cela dans les exemples.

exemple

Un exemple très basique, une sphère bombardée de quelques rayons, avec placement de petites sphères aux intersection. Le code est très détaillé, mais la plupart du temps, on prendra quelques raccourcis.

//directives classiques...
#version unofficial MegaPov 0.5;
#include "colors.inc"

//environnement
camera {location <100,100,60> direction z*1 look_at <0,15,0>}
light_source {<400,500,300> White*2}
plane {y,0 pigment {SteelBlue}}

//une ch'tite macro pour faire des flèches...
#macro Fleche (Pt1,Pt2,Rayon)
 union {
 cylinder {Pt1,Pt2,Rayon}         
 cone {0,Rayon,(vnormalize(Pt1-Pt2))*(Rayon*20),Rayon*3 translate Pt2}
 no_shadow
 }
#end                                        

//l'objet à tester
#declare Obj1 = 
  sphere {<0,20,-10>,30 pigment {OrangeRed}}

//rien à déclarer ?
#declare Normale_du_Point = <0,0,0>;
#declare r1=seed(0);

//c'est ici que ça se passe !
#declare I=0;
#while (I < 1)                                                        
  //définition des coordonnées du rayon
  #declare Point_Depart = <rand(r1)*35+50,rand(r1)*25+60,rand(r1)*25+50>;
  #declare Orientation = <-1,-1,-1>;     
  
  
  //une flèche pour matérialiser le rayon
  object {Fleche (Point_Depart,Point_Depart+Orientation*20,.2) pigment {OrangeRed}}
  
  //trouver l'intersection
  #declare Point_Intersection = 
    trace (Obj1, Point_Depart, Orientation, Normale_du_Point);
  
  //vérifier si la normale est à <0,0,0>
  #if (Normale_du_Point.x = 0 & Normale_du_Point.y = 0 & Normale_du_Point.z = 0) 
   //oui, alors ne fais rien, puisque pas d'intersection
  #else
   //non, alors vas-y !
   sphere {Point_Intersection,2 pigment {YellowGreen}}
  #end
  
#declare I=I+.1;
#end

//placement de l'objet
object {Obj1}

La perspective est trompeuse, mais les flèches sont tout à fait parallèles entre elles.

Pour voir comment on exploite la normale stockée pour placer les objets, remplacez le code de la sphère par ceci :

   cylinder {<0,0,0>,
             15*vnormalize (Normale_du_Point),
             2 
             translate Point_Intersection
             pigment {YellowGreen}
             }

Et voilà, les petits cylindres se placent bien perpendiculairement à la surface, et ça marche avec n'importe quel objet.

remarques

Le comportement de la fonction trace avec les isosurfaces est parfois capricieux, notamment en version Unix. Si vous avez des problèmes, n'hésitez pas à en faire part dans les forums de dicussion.

auteur : Fabien Mosen