Articulo de referencia

Algoritmo de intersección de Möller-Trumbore

El algoritmo de intersección rayo-triángulo de Möller-Trumbore , que recibe su nombre de sus inventores Tomas Möller y Ben Trumbore, es un método rápido para calcular la interse...

El algoritmo de intersección rayo-triángulo de Möller-Trumbore , que recibe su nombre de sus inventores Tomas Möller y Ben Trumbore, es un método rápido para calcular la intersección de un rayo y un triángulo en tres dimensiones sin necesidad de precalcular la ecuación del plano que contiene el triángulo. [ 1 ] Entre otros usos, puede emplearse en gráficos por computadora para implementar cálculos de trazado de rayos que involucran mallas triangulares . [ 2 ]

Cálculo

Definiciones

El rayo se define mediante un punto de origen.O{\displaystyle O}y un vector de direcciónD{\displaystyle D}Cada punto en el rayo puede expresarse medianter(t)=O+tD{\displaystyle {\vec {r}}(t)=O+tD}donde el parámetrot{\displaystyle t}abarca desde menos infinito hasta infinito. El triángulo está definido por tres vértices, llamadosv1{\displaystyle v_{1}},v2{\displaystyle v_{2}},v3{\displaystyle v_{3}}. El plano sobre el que se encuentra el triángulo, que es necesario para calcular la intersección rayo-triángulo, se define mediante un punto en el plano, como por ejemplo:v1{\displaystyle v_{1}}y un vector que es ortogonal a cada punto de ese plano, como el producto vectorial entre el vector dev1{\displaystyle v_{1}}av2{\displaystyle v_{2}}y el vector dev1{\displaystyle v_{1}}av3{\displaystyle v_{3}}:

norte(PAG1PAG2)=0{\displaystyle {\vec {n}}\cdot (P_{1}-P_{2})=0}, dóndenorte=(v2v1)×(v3v1){\displaystyle {\vec {n}}=(v_{2}-v_{1})\times (v_{3}-v_{1})}, yPAG1{\displaystyle P_{1}}yPAG2{\displaystyle P_{2}}¿Hay algún punto en el avión?

Comprueba si el rayo es paralelo al triángulo.

Primero, determine si la línea generada por el rayo interseca el plano sobre el que se encuentra el triángulo y, de ser así, encuentre las coordenadas de dicha intersección. La única forma en que la línea no interseca el plano es si el vector director del rayo es paralelo al plano. [ 3 ] Cuando esto sucede, el producto escalar entre el vector director del rayo y el vector normal del plano será cero. De lo contrario, la línea interseca el plano en algún punto , pero no necesariamente dentro del triángulo.

Comprueba si la intersección rayo-plano se encuentra fuera del triángulo.

Utilizando coordenadas baricéntricas , cualquier punto del triángulo puede expresarse como una combinación convexa de los vértices del triángulo:

PAG=wv1+v2+vv3{\displaystyle P=wv_{1}+uv_{2}+vv_{3}}

Los coeficientes deben ser no negativos y sumar 1, por lo tantow{\displaystyle w}puede ser reemplazado por1v{\displaystyle 1-uv}:

PAG=(1v)v1+v2+vv3PAG=v1+(v2v1)+v(v3v1){\displaystyle {\begin{aligned}P&=(1-uv)v_{1}+uv_{2}+vv_{3}\\P&=v_{1}+u(v_{2}-v_{1})+v(v_{3}-v_{1})\end{aligned}}}

dóndePAG{\displaystyle P}es cualquier punto del plano. Observa quemi1=v2v1{\displaystyle {\vec {e_{1}}}=v_{2}-v_{1}}ymi2=v3v1{\displaystyle {\vec {e_{2}}}=v_{3}-v_{1}}son vectores en el borde del triángulo y, juntos, abarcan un plano (que pasa por el origen). Cada punto en ese plano se puede escribir comomi1+vmi2{\displaystyle ue_{1}+ve_{2}}y puede ser traducido porv1{\displaystyle v_{1}}"mover" ese punto al plano en el que se encuentra el triángulo.

Para encontrar{\displaystyle u}yv{\displaystyle v}Para una intersección particular, iguale la expresión del rayo a la expresión del plano y coloque las variables a un lado y las constantes al otro.

O+tD=v1+(v2v1)+v(v3v1)Ov1=tD+(v2v1)+v(v3v1){\displaystyle {\begin{aligned}O+tD&=v_{1}+u(v_{2}-v_{1})+v(v_{3}-v_{1})\\O-v_{1}&=-tD+u(v_{2}-v_{1})+v(v_{3}-v_{1})\end{aligned}}}

Este es un sistema de ecuaciones lineales con tres ecuaciones (una para cada una)incógnita{\displaystyle x},y{\displaystyle y},z{\displaystyle z}) y tres incógnitas (t{\displaystyle t},{\displaystyle u}, yv{\displaystyle v}), y puede representarse como una multiplicación matriz-vector.

[|||D(v2v1)(v3v1)|||][tv]=Ov1{\displaystyle {\begin{bmatrix}\vert &\vert &\vert \\-D&(v2-v1)&(v3-v1)\\\vert &\vert &\vert \end{bmatrix}}{\begin{bmatrix}t\\u\\v\end{bmatrix}}=O-v_{1}}

Esta ecuación siempre tendrá una solución cuando la matriz tenga tres vectores columna linealmente independientes enR3{\displaystyle \mathbb {R} ^{3}}y por lo tanto es invertible . Esto sucede si y solo si los vértices del triángulo no son colineales y el rayo no es paralelo al plano.

El algoritmo puede utilizar la regla de Cramer para encontrar lat{\displaystyle t},{\displaystyle u}, yv{\displaystyle v}valores para una intersección, y si se encuentra dentro del triángulo, las coordenadas exactas de la intersección se pueden encontrar introduciendot{\displaystyle t}a la ecuación del rayo.

Implementaciones

Implementación en C++

A continuación se muestra una implementación del algoritmo en C++ utilizando la biblioteca glm:

std :: optional <vec3> ray_intersects_triangle ( const vec3 & ray_origin , const vec3 & ray_vector , const triangle3 & triangle ) { constexpr float epsilon = std :: numeric_limits <float> :: epsilon ( ) ;vec3 edge1 = triángulo . b - triángulo . a ; vec3 edge2 = triángulo . c - triángulo . a ;// Eliminación de caras posteriores, asumiendo triángulos enrollados en sentido antihorario. const vec3 normal = cross ( edge1 , edge2 ); // No es necesario normalizar if ( dot ( normal , ray_vector ) > 0 ) return {};vec3 ray_cross_e2 = cross ( ray_vector , edge2 ); float det = dot ( edge1 , ray_cross_e2 );if ( abs ( det ) < epsilon ) return {}; // El rayo es paralelo al triángulofloat inv_det = 1.0 / det ; vec3 s = ray_origin - triangle . a ; float u = inv_det * dot ( s , ray_cross_e2 );if ( u < - epsilon || u - 1 > epsilon ) return {}; // El rayo pasa fuera de los límites de edge2vec3 s_cross_e1 = cross ( s , edge1 ); float v = inv_det * dot ( ray_vector , s_cross_e1 );if ( v < - epsilon || u + v - 1 > epsilon ) return {}; // El rayo pasa fuera de los límites de edge1// La línea del rayo interseca con el triángulo. // Calculamos t para encontrar dónde en el rayo está la intersección. float t = inv_det * dot ( edge2 , s_cross_e1 );if ( t > epsilon ) // Intersección de rayos { return vec3 ( ray_origin + ray_vector * t ); } else // Esto significa que hay una intersección de líneas pero no una intersección de rayos. return {}; }

Implementación en Rust

A continuación se muestra una implementación del algoritmo en Rust utilizando la biblioteca glam:

fn moller_trumbore_intersection ( origin : Vec3 , direction : Vec3 , triangle : Triangle ) -> Option < Vec3 > { let e1 = triangle . b - triangle . a ; let e2 = triangle . c - triangle . a ;let ray_cross_e2 = direction.cross ( e2 ) ; let det = e1.dot ( ray_cross_e2 ) ;Si det > - f32 :: EPSILON && det < f32 :: EPSILON { return None ; // Este rayo es paralelo a este triángulo. }let inv_det = 1.0 / det ; let s = origin - triangle.a ; let u = inv_det * s.dot ( ray_cross_e2 ) ; if u < 0.0 || u > 1.0 { return None ; }let s_cross_e1 = s . cross ( e1 ); let v = inv_det * direction . dot ( s_cross_e1 ); if v < 0.0 || u + v > 1.0 { return None ; } // En esta etapa podemos calcular t para averiguar dónde está el punto de intersección en la línea. let t = inv_det * e2 . dot ( s_cross_e1 );if t > f32 :: EPSILON { // Intersección de rayos let intersection_point = origin + direction * t ; return Some ( intersection_point ); } else { // Esto significa que hay una intersección de líneas pero no una intersección de rayos. return None ; } }

Implementación en Java

A continuación se muestra una implementación del algoritmo en Java utilizando javax.vecmathla API de Java 3D :

clase pública MollerTrumbore {privado estático final doble EPSILON = 0.0000001 ;public static boolean rayIntersectsTriangle ( Point3d rayOrigin , Vector3d rayVector , Triangle inTriangle , Point3d outIntersectionPoint ) { Point3d vertex0 = inTriangle . getVertex0 (); Point3d vertex1 = inTriangle . getVertex1 (); Point3d vertex2 = inTriangle . getVertex2 (); Vector3d edge1 = new Vector3d (); Vector3d edge2 = new Vector3d (); Vector3d h = new Vector3d (); Vector3d s = new Vector3d (); Vector3d q = new Vector3d (); double a , f , u , v ; edge1 . sub ( vertex1 , vertex0 ); edge2 . sub ( vertex2 , vertex0 ); h . cross ( rayVector , edge2 ); a = edge1 . dot ( h );if ( a > - EPSILON && a < EPSILON ) { return false ; // Este rayo es paralelo a este triángulo. }f = 1.0 / a ; s . sub ( rayOrigin , vertex0 ); u = f * ( s . dot ( h ));Si ( u < 0.0 || u > 1.0 ) { devolver falso ; }q . cruz ( s , borde1 ); v = f * rayoVector . punto ( q );Si ( v < 0.0 || u + v > 1.0 ) { devolver falso ; }// En esta etapa podemos calcular t para averiguar dónde está el punto de intersección en la línea. double t = f * edge2 . dot ( q ); if ( t > EPSILON ) // intersección de rayos { outIntersectionPoint . set ( 0.0 , 0.0 , 0.0 ); outIntersectionPoint . scaleAdd ( t , rayVector , rayOrigin ); return true ; } else // Esto significa que hay una intersección de línea pero no una intersección de rayos. { return false ; } } }

Véase también

Referencias

  1. Möller, Tomas; Trumbore, Ben (1997). "Intersección rápida de rayos y triángulos con almacenamiento mínimo". Journal of Graphics Tools . 2 : 21–28 . doi : 10.1080/10867651.1997.10487468 .
  2. "Intersección rayo-triángulo" . lighthouse3d. 26 de marzo de 2011. Consultado el 10 de septiembre de 2017 .
  3. Nota: Si el origen del rayo se encuentra en el plano, además de que su vector de dirección es paralelo al plano, entonces técnicamente todo el rayo está sobre el plano. Sin embargo, dado que los planos teóricos son infinitamente delgados, en ese caso se consideraría que el rayo no interseca el plano.
  • Intersección rápida de rayo-triángulo con almacenamiento mínimo
  • Optimizaciones del algoritmo básico de Möller y Trumbore , código de la revista Journal of Graphics Tools.
  • Trazado de rayos: Renderizado de un triángulo
  • Versión de este algoritmo en MATLAB (altamente vectorizada).
  • Algoritmo de intersección rayo-triángulo de Baldwin-Weber
  • Algoritmo de Schlick-Subrenat [ 1 ] para la intersección rayo-cuadrilátero
  1. Intersección de rayos en superficies teseladas: cuadriláteros versus triángulos , Schlick C., Subrenat G. Graphics Gems 1993