**მელერ-ტრამბორის ალგორითმით** დგინდება სხივის კვეთა სამკუთხედთან სამ განზომილებაში. თომას მელერისა და ბენ ტრამბორის ეს ალგორითმი არ საჭიროებს წერტილების სიბრტყეზე გადატანას, ზოგავს მეხსიერებას და თავის თანამედროვე იმპლემენტაციებთან შედარებით სწრაფია. ის პუბლიკაცია ACM-მა გამოსცა 1997 წელს სახელით „სწრაფი, მინიმალური მეხსიერების სამკუთხედ-სხივის კვეთა" და კომპიუტერული გრაფიკის სფეროში ერთ-ერთ ყველაზე ცნობილ ნაშრომს წარმოადგენს. იმის მიუხედავად, რომ უკეთესი ალგორითმებიც არსებობს, მელერ-ტრამბორის ალგორითმი დღესაც ფართოდაა გავრცელებული მისი სიმარტივის გამო.

ალგორითმი
---------

### წერტილი სხივზე:

{\displaystyle R(t)=O+tD} (1)

{\displaystyle O} - საწყისი წერილია, {\displaystyle t} - მანძილი, {\displaystyle D} - სხივის მიმართულება

### წერტილი სამკუთხედზე:

{\displaystyle T(u,v)=(1-u-v)V\_{0}+uV\_{1}+vV\_{2}} (2)

{\displaystyle V\_{0},V\_{1},V\_{2}} სამკუთხედის წვეროს კოორდინატებია

### მთავარი ტოლობა:

სხივი რომ სამკუთხედს კვეთდეს უნდა არსებობდეს წერტილი სხივზე, რომელიც სამკუთხედს ეკუთვნის.

{\displaystyle R(t)=T(u,v)} ანუ:

{\displaystyle O+tD=(1-u-v)V\_{0}+uV\_{1}+vV\_{2}} (3)

გადავანაცვლოთ ცვლადები და ვიღებთ:

{\displaystyle [-D,V\_{1}-V\_{0},V\_{2}-V\_{0}]{\begin{bmatrix}t\\u\\v\end{bmatrix}}=O-V\_{0}} (4)

კვეთის სანახავად უნდა ამოიხსნას განტოლება (4).

### ამოხსნა:

{\displaystyle E\_{1}=V\_{1}-V\_{0}}

{\displaystyle E\_{2}=V\_{2}-V\_{0}}

{\displaystyle T=O-V\_{0}}

{\displaystyle P=(D\times E\_{2})}

{\displaystyle Q=T\times E\_{1}}

განტოლების (4) ამოხსნა ხდება შემდეგნაირად:

{\displaystyle {\begin{bmatrix}t\\u\\v\end{bmatrix}}={\frac {1}{(D\times E\_{2})\cdot E\_{1}}}{\begin{bmatrix}(T\times E\_{1})\cdot E\_{2}\\(D\times E\_{2})\cdot T\\(T\times E\_{1})\cdot D\end{bmatrix}}={\frac {1}{P\times E\_{1}}}{\begin{bmatrix}(Q\times E\_{2})\\(P\times T)\\(Q\times D)\end{bmatrix}}} (6)

მივიღებთ სამეულს {\displaystyle (t,u,v)}

იმპლემენტაცია
-------------

```
/\* Ray-Triangle Intersection Test Routines \*/
/\* Different optimizations of my and Ben Trumbore's \*/
/\* code from journals of graphics tools (JGT) \*/
/\* http://www.acm.org/jgt/ \*/
/\* by Tomas Moller, May 2000 \*/

#include <math.h>

#define EPSILON 0.000001
#define CROSS(dest,v1,v2) \
 dest[0]=v1[1]\*v2[2]-v1[2]\*v2[1]; \
 dest[1]=v1[2]\*v2[0]-v1[0]\*v2[2]; \
 dest[2]=v1[0]\*v2[1]-v1[1]\*v2[0];
#define DOT(v1,v2) (v1[0]\*v2[0]+v1[1]\*v2[1]+v1[2]\*v2[2])
#define SUB(dest,v1,v2) \
 dest[0]=v1[0]-v2[0]; \
 dest[1]=v1[1]-v2[1]; \
 dest[2]=v1[2]-v2[2]; 

/\* the original jgt code \*/
int intersect\_triangle(double orig[3], double dir[3],
 double vert0[3], double vert1[3], double vert2[3],
 double \*t, double \*u, double \*v)
{
 double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
 double det,inv\_det;

 /\* find vectors for two edges sharing vert0 \*/
 SUB(edge1, vert1, vert0);
 SUB(edge2, vert2, vert0);

 /\* begin calculating determinant - also used to calculate U parameter \*/
 CROSS(pvec, dir, edge2);

 /\* if determinant is near zero, ray lies in plane of triangle \*/
 det = DOT(edge1, pvec);

 if (det > -EPSILON && det < EPSILON)
 return 0;
 inv\_det = 1.0 / det;

 /\* calculate distance from vert0 to ray origin \*/
 SUB(tvec, orig, vert0);

 /\* calculate U parameter and test bounds \*/
 \*u = DOT(tvec, pvec) \* inv\_det;
 if (\*u < 0.0 || \*u > 1.0)
 return 0;

 /\* prepare to test V parameter \*/
 CROSS(qvec, tvec, edge1);

 /\* calculate V parameter and test bounds \*/
 \*v = DOT(dir, qvec) \* inv\_det;
 if (\*v < 0.0 || \*u + \*v > 1.0)
 return 0;

 /\* calculate t, ray intersects triangle \*/
 \*t = DOT(edge2, qvec) \* inv\_det;

 return 1;
}

/\* code rewritten to do tests on the sign of the determinant \*/
/\* the division is at the end in the code \*/
int intersect\_triangle1(double orig[3], double dir[3],
 double vert0[3], double vert1[3], double vert2[3],
 double \*t, double \*u, double \*v)
{
 double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
 double det,inv\_det;

 /\* find vectors for two edges sharing vert0 \*/
 SUB(edge1, vert1, vert0);
 SUB(edge2, vert2, vert0);

 /\* begin calculating determinant - also used to calculate U parameter \*/
 CROSS(pvec, dir, edge2);

 /\* if determinant is near zero, ray lies in plane of triangle \*/
 det = DOT(edge1, pvec);

 if (det > EPSILON)
 {
 /\* calculate distance from vert0 to ray origin \*/
 SUB(tvec, orig, vert0);
 
 /\* calculate U parameter and test bounds \*/
 \*u = DOT(tvec, pvec);
 if (\*u < 0.0 || \*u > det)
 return 0;
 
 /\* prepare to test V parameter \*/
 CROSS(qvec, tvec, edge1);
 
 /\* calculate V parameter and test bounds \*/
 \*v = DOT(dir, qvec);
 if (\*v < 0.0 || \*u + \*v > det)
 return 0;
 
 }
 else if(det < -EPSILON)
 {
 /\* calculate distance from vert0 to ray origin \*/
 SUB(tvec, orig, vert0);
 
 /\* calculate U parameter and test bounds \*/
 \*u = DOT(tvec, pvec);
/\* printf("\*u=%f\n",(float)\*u); \*/
/\* printf("det=%f\n",det); \*/
 if (\*u > 0.0 || \*u < det)
 return 0;
 
 /\* prepare to test V parameter \*/
 CROSS(qvec, tvec, edge1);
 
 /\* calculate V parameter and test bounds \*/
 \*v = DOT(dir, qvec) ;
 if (\*v > 0.0 || \*u + \*v < det)
 return 0;
 }
 else return 0; /\* ray is parallell to the plane of the triangle \*/

 inv\_det = 1.0 / det;

 /\* calculate t, ray intersects triangle \*/
 \*t = DOT(edge2, qvec) \* inv\_det;
 (\*u) \*= inv\_det;
 (\*v) \*= inv\_det;

 return 1;
}

/\* code rewritten to do tests on the sign of the determinant \*/
/\* the division is before the test of the sign of the det \*/
int intersect\_triangle2(double orig[3], double dir[3],
 double vert0[3], double vert1[3], double vert2[3],
 double \*t, double \*u, double \*v)
{
 double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
 double det,inv\_det;

 /\* find vectors for two edges sharing vert0 \*/
 SUB(edge1, vert1, vert0);
 SUB(edge2, vert2, vert0);

 /\* begin calculating determinant - also used to calculate U parameter \*/
 CROSS(pvec, dir, edge2);

 /\* if determinant is near zero, ray lies in plane of triangle \*/
 det = DOT(edge1, pvec);

 /\* calculate distance from vert0 to ray origin \*/
 SUB(tvec, orig, vert0);
 inv\_det = 1.0 / det;
 
 if (det > EPSILON)
 {
 /\* calculate U parameter and test bounds \*/
 \*u = DOT(tvec, pvec);
 if (\*u < 0.0 || \*u > det)
 return 0;
 
 /\* prepare to test V parameter \*/
 CROSS(qvec, tvec, edge1);
 
 /\* calculate V parameter and test bounds \*/
 \*v = DOT(dir, qvec);
 if (\*v < 0.0 || \*u + \*v > det)
 return 0;
 
 }
 else if(det < -EPSILON)
 {
 /\* calculate U parameter and test bounds \*/
 \*u = DOT(tvec, pvec);
 if (\*u > 0.0 || \*u < det)
 return 0;
 
 /\* prepare to test V parameter \*/
 CROSS(qvec, tvec, edge1);
 
 /\* calculate V parameter and test bounds \*/
 \*v = DOT(dir, qvec) ;
 if (\*v > 0.0 || \*u + \*v < det)
 return 0;
 }
 else return 0; /\* ray is parallell to the plane of the triangle \*/

 /\* calculate t, ray intersects triangle \*/
 \*t = DOT(edge2, qvec) \* inv\_det;
 (\*u) \*= inv\_det;
 (\*v) \*= inv\_det;

 return 1;
}

/\* code rewritten to do tests on the sign of the determinant \*/
/\* the division is before the test of the sign of the det \*/
/\* and one CROSS has been moved out from the if-else if-else \*/
int intersect\_triangle3(double orig[3], double dir[3],
 double vert0[3], double vert1[3], double vert2[3],
 double \*t, double \*u, double \*v)
{
 double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
 double det,inv\_det;

 /\* find vectors for two edges sharing vert0 \*/
 SUB(edge1, vert1, vert0);
 SUB(edge2, vert2, vert0);

 /\* begin calculating determinant - also used to calculate U parameter \*/
 CROSS(pvec, dir, edge2);

 /\* if determinant is near zero, ray lies in plane of triangle \*/
 det = DOT(edge1, pvec);

 /\* calculate distance from vert0 to ray origin \*/
 SUB(tvec, orig, vert0);
 inv\_det = 1.0 / det;
 
 CROSS(qvec, tvec, edge1);
 
 if (det > EPSILON)
 {
 \*u = DOT(tvec, pvec);
 if (\*u < 0.0 || \*u > det)
 return 0;
 
 /\* calculate V parameter and test bounds \*/
 \*v = DOT(dir, qvec);
 if (\*v < 0.0 || \*u + \*v > det)
 return 0;
 
 }
 else if(det < -EPSILON)
 {
 /\* calculate U parameter and test bounds \*/
 \*u = DOT(tvec, pvec);
 if (\*u > 0.0 || \*u < det)
 return 0;
 
 /\* calculate V parameter and test bounds \*/
 \*v = DOT(dir, qvec) ;
 if (\*v > 0.0 || \*u + \*v < det)
 return 0;
 }
 else return 0; /\* ray is parallell to the plane of the triangle \*/

 \*t = DOT(edge2, qvec) \* inv\_det;
 (\*u) \*= inv\_det;
 (\*v) \*= inv\_det;

 return 1;
}

```

სქოლიო
------

1. ↑  Möller, Tomas; Trumbore, Ben (1997). „Fast, Minimum Storage Ray-Triangle Intersection". *Journal of Graphics Tools*. **2** (1): 21–28. doi:10.1080/10867651.1997.10487468.