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 &amp;&amp; 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