on vient de voir dans le cours comment calculer l'intersection
d'un rayon avec un plan ou avec une sphère. ça marche plutôt bien,
mais si on souhaite créer un objet avec un logiciel 3d comme Blender,
on ne pourra pas l'utiliser pour calculer une image. la plupart
des logiciels de modélisation 3d enregistrent uniquement des
triangles. mais il n'est pas trop difficile de calculer
l'intersection entre un rayon et un triangle...
après tout, un triangle n'est qu'un morceau de plan délimité par 3 sommets. on sait déjà comment calculer le point d'intersection du rayon avec un plan, il ne reste plus qu'à vérifier que le point est aussi à l'intérieur du triangle !
une solution consiste à vérifier que le point est du bon coté de
chaque arête du triangle. on va utiliser une propriété du produit
vectoriel : selon l'ordre des vecteurs, le résultat n'est pas
orienté de la même manière !

le schéma permet de vérifier : si on calcule le produit des
vecteurs ab et ac, ie de ab vers ac (noté ab x ac), on obtient le
vecteur orienté vers le haut. si on calcule le produit dans
l'autre sens, de ac vers ab (noté ac x ab), le résultat aussi est
orienté dans l'autre sens.
en pratique, ca veut aussi dire que le triangle abc n'est pas
orienté dans le même sens que le triangle acb. un triangle abc est
orienté comme le produit de ses 2 aretes : ab et ac. le triangle
abc est donc orienté comme le produit de ab vers ac et le triangle
acb est orienté comme le produit de ac vers ab.
c'est cette propriété que l'on va utiliser pour vérifier que le
point est du "bon" coté de chaque arête du triangle. par exemple,
pour l'arếte ab, le point p peut se trouver à l'intérieur du
triangle ou pas. c'est l'orientation du triangle abp qui permet de
décider :

on va donc tester 3 triangles, un par arête. si les 3 triangles
abp, bcp, et cap sont orientés comme le triangle abc, le point est
du bon coté de chaque arête et il est à l'intérieur du triangle.
sinon, il est du mauvais coté d'une arête et donc, à l'extérieur
du triangle :

il ne reste plus qu'à comparer les orientations de 3 vecteurs
pour écrire le test ! et on sait déja que l'on peut utiliser le
produit scalaire de 2 vecteurs pour comparer leur orientation, ie
u . v sera positif si les vecteurs u et v sont orientés dans le
même sens et négatif sinon.
on peut maintenant écrire le test pour une arête : dot()
permet de calculer le produit scalaire et cross()
le produit vectoriel.
pour tester p par rapport à l'arête ab :
cross( Vector(a, b),
Vector(a, p) ) ce qui s'écrit directement :
Vector abc= cross(
Vector(a, b), Vector(a, c) );
// orientation du triangle abc : ab x ac
Vector abp= cross( Vector(a, b),
Vector(a, p) ); // orientation du triangle
apb : ab x ap
if(dot(abc, abp) <
0)
// comparaison des
orientations
return false;
// le point p est du mauvais coté de l'arete ab !
...
il ne reste plus qu'à recommencer pour les arêtes bc et ca. on
peut aussi éviter de calculer 3 fois l'orientation du triangle
abc...
le test complet va ressembler à :
bool intersect( /* rayon */
const Point& o, const Vector& d, const float tmax, /*
triangle */ const Point& a, const Point& b, const
Point& c )
{
// on commence par calculer la
normale du triangle, ie son orientation, ab x ac
Vector n= cross( Vector(a, b),
Vector(a, c) );
//
intersection du plan (a, n) avec le rayon (o, d) float t= dot(n, Vector(o,
a)) / dot(n, d); if(t < 0 || t > tmax)
return
false; // l'intersection n'est pas valide,
soit derriere la camera soit trop loin // point d'intersection avec
le plan Point p= o + t*d; // tester le triangle abp /
orientation des aretes ab et ap Vector abp= cross( Vector(a,
b), Vector(a, p) ); if(dot(n, abp) < 0)
return
false; // p est à l'extérieur de l'arête ab // tester le
triangle bcp / orientation des aretes bc et bp
...
// tester le triangle cap
/ orientation des aretes ca et cp
...
// le point est du bon coté
des 3 aretes, il est donc à l'intérieur du triangle !return true;
}
read_positions() définie dans
mesh_io.h. #include "mesh_io.h"
std::vector<Point> positions;
if(!read_positions("data/robot.obj", positions))
return "erreur";
for(unsigned i=
0; i +2 < positions.size(); i += 3){ // triangle abc Point a= positions[ i ]; Point b= positions[ i +1 ];
Point c= positions[ i +2 ];
...
}// parcours les triangles for(unsigned i= 0; i < positions.size()/3;
i++){ // triangle abc Point a= positions[ 3*i ]; Point b= positions[ 3*i +1
]; Point c= positions[ 3*i +2
]; ...
}
