Intersection rayon-triangle (ray-triangle intersection) avec Away3D
Le 17 mai 2011
Comment tester l’intersection d’un rayon avec un triangle sous Away3D 3.6? Facile, il suffit d’utiliser la classe Ray du package away3d.materials.utils.data. Sauf que je n’ai jamais réussi à faire fonctionner la méthode getIntersect(). Après avoir passée une soirée à faire des essais sans le moindre résultat, j’ai finalement du créer ma propre fonction pour venir à bout de ce problème.
Voici une explication rapide de la méthode employée pour détecter l’intersection d’une droite et d’un triangle. Il y a un peu de math mais ce n’est pas si compliqué que cela à comprendre. Je précise que je ne fais que regrouper et traduire des sources en anglais trouvées ici et la sur Internet.
Concrètement, si une droite coupe un triangle, il existe un point p appartenant à la fois à la droite et au triangle.
L’appartenance d’un point à un triangle peut être définie ainsi:
(1) point(u,v) = (1-u-v)*p0 + u*p1 + v*p2
ou p0, p1, p2 sont les vertices du triangle
avec:
u >= 0
v >= 0
u + v <= 1.0
On défini l’équation paramétrique d’une droite par:
(2) point(t) = p + t * d
où:
p est un point de la droite
d est un vecteur directeur de la droite
Si il existe un point p appartenant à la fois à la droite et au triangle on peut écrire:
(3) p + t * d = (1-u-v) * p0 + u * p1 + v * p2
Donc, si il existe un triplet (t,u,v) solution de l’équation (3), dont les vecteurs u et v vérifient les conditions énoncées en (1) alors le rayon de vecteur directeur d, passant par p coupe le triangle p0, p1, p2 et les coordonnées du point d’intersection sont égales à p + t * d.
Ce qui donne en As3:
public function getIntersect( p:Vector3D, d:Vector3D, v0:Vector3D, v1:Vector3D, v2:Vector3D ):Boolean
{
var e1:Vector3D = new Vector3D();
var e2:Vector3D = new Vector3D();
var h:Vector3D = new Vector3D();
var s:Vector3D = new Vector3D();
var q:Vector3D = new Vector3D();
var a:Number;
var f:Number;
var u:Number;
var v:Number;
var t:Number;
e1.x = v1.x - v0.x;
e1.y = v1.y - v0.y;
e1.z = v1.z - v0.z;
e2.x = v2.x - v0.x;
e2.y = v2.y - v0.y;
e2.z = v2.z - v0.z;
h.x = d.y * e2.z - d.z * e2.y;
h.y = d.z * e2.x - d.x * e2.z;
h.z = d.x * e2.y - d.y * e2.x;
a = e1.x * h.x + e1.y * h.y + e1.z * h.z;
if ( a > -0.00001 && a < 0.00001 ) return( false );
f = 1/a;
s.x = p.x - v0.x;
s.y = p.y - v0.y;
s.z = p.z - v0.z;
u = f * ( s.x * h.x + s.y * h.y + s.z * h.z );
if ( u < 0.0 || u > 1.0 ) return( false );
q.x = s.y * e1.z - s.z * e1.y;
q.y = s.z * e1.x - s.x * e1.z;
q.z = s.x * e1.y - s.y * e1.x;
v = f * ( d.x * q.x + d.y * q.y + d.z * q.z );
if ( v < 0.0 || u + v > 1.0 ) return( false );
t = f * ( e2.x * q.x + e2.y * q.y + e2.z * q.z );
if ( t > 0.00001 )
{
intersectionPoint.x = p.x + t * d.x;
intersectionPoint.y = p.y + t * d.y;
intersectionPoint.z = p.z + t * d.z;
return(true); // intersection
}
// pas d'interscetion
else return (false);
}
Vous pouvez récupérer le code source de l’animation ici. Le rayon est représenté par le segment blanc. En jaune, le triangle coupé par le rayon et le segment joignant l’origine du repère de la scène au point d’intersection. Pour que le test fonctionne il est important de convertir, si nécessaire, les coordonnées dans un même repère, le plus simple étant d’utiliser le repère de la scène.
Posté dans Code source, Flash | Laisser un commentaire
Commentaires
Laisser une réaction