Free Electron
RayTriangleIntersect.h
Go to the documentation of this file.
1 /* Copyright (C) 2003-2021 Free Electron Organization
2  Any use of this software requires a license. If a valid license
3  was not distributed with this file, visit freeelectron.org. */
4 
5 /** @file */
6 
7 /* This file is copyrighted only to the extent of adapting it to FE.
8  Substantial source from the original example remains, for which
9  no copyright was indicated. */
10 
11 #ifndef __solve_RayTriangleIntersect_h__
12 #define __solve_RayTriangleIntersect_h__
13 
14 #define FE_RTI_DEBUG FALSE
15 
16 #define FE_MOLLER_EPSILON (1e-6)
17 #define FE_MOLLER_TEST_CULL FALSE //* ignore backside using implied normal
18 
19 namespace fe
20 {
21 namespace ext
22 {
23 
24 /**************************************************************************//**
25  @brief Find intersection between ray and triangle
26 
27  @ingroup solve
28 
29  http://jgt.akpeters.com/papers/MollerTrumbore97
30 *//***************************************************************************/
31 template <typename T>
33 {
34  public:
35 static T solve(const Vector<3,T>& vert0,
36  const Vector<3,T>& vert1,
37  const Vector<3,T>& vert2,
38  const Vector<3,T>& origin,
39  const Vector<3,T>& direction,
40  Barycenter<T>& barycenter);
41 static void resolveContact(
42  const Vector<3,T>& vert0,
43  const Vector<3,T>& vert1,
44  const Vector<3,T>& vert2,
45  const Vector<3,T>& norm0,
46  const Vector<3,T>& norm1,
47  const Vector<3,T>& norm2,
48  const Vector<3,T>& origin,
49  const Vector<3,T>& direction,
50  const Barycenter<T>& barycenter,
51  const T range,
52  Vector<3,T>& intersection,
53  Vector<3,T>& normal);
54 };
55 
56 // direction must be normalized
57 template <typename T>
58 inline T RayTriangleIntersect<T>::solve(const Vector<3,T>& vert0,
59  const Vector<3,T>& vert1,const Vector<3,T>& vert2,
60  const Vector<3,T>& origin,const Vector<3,T>& direction,
61  Barycenter<T>& barycenter)
62 {
63 #if FE_RTI_DEBUG
64  feLog("vert %s %s %s\n",c_print(vert0),c_print(vert1),c_print(vert2));
65  feLog("origin %s\n",c_print(origin));
66  feLog("direction %s\n",c_print(direction));
67 #endif
68 
69  /* find vectors for two edges sharing vert0 */
70  Vector<3,T> edge1=vert1-vert0;
71  Vector<3,T> edge2=vert2-vert0;
72 
73  /* begin calculating determinant - also used to calculate U parameter */
74  Vector<3,T> pvec;
75  cross3(pvec,direction,edge2);
76 
77  /* if determinant is near zero, ray lies in plane of triangle */
78  T det=dot(edge1, pvec);
79 
80 /*****************************************************************************/
81 #if FE_MOLLER_TEST_CULL /* if culling is desired */
82  if(det<T(FE_MOLLER_EPSILON))
83  {
84 #if FE_RTI_DEBUG
85  feLog(" miss: det=%.6G\n",det);
86 #endif
87  return T(-1);
88  }
89 
90  /* calculate distance from vert0 to ray origin */
91  Vector<3,T> tvec=origin-vert0;
92 
93  /* calculate U parameter and test bounds */
94  T u=dot(tvec,pvec);
95  if(u<T(0) || u>det)
96  {
97 #if FE_RTI_DEBUG
98  feLog(" miss: u=%.6G\n",u);
99 #endif
100  return T(-1);
101  }
102 
103  /* prepare to test V parameter */
104  Vector<3,T> qvec;
105  cross3(qvec,tvec,edge1);
106 
107  /* calculate V parameter and test bounds */
108  T v=dot(direction,qvec);
109  if(v<T(0) || u+v>det)
110  {
111 #if FE_RTI_DEBUG
112  feLog(" miss: u=%.6G v=%.6G\n",u,v);
113 #endif
114  return T(-1);
115  }
116 
117  /* calculate t, scale parameters, ray intersects triangle */
118  T range=dot(edge2,qvec);
119  T inv_det=T(1)/det;
120  range*=inv_det;
121  u*=inv_det;
122  v*=inv_det;
123 
124 /*****************************************************************************/
125 #else /* the non-culling branch */
126  if(det>-T(FE_MOLLER_EPSILON) && det<T(FE_MOLLER_EPSILON))
127  {
128 #if FE_RTI_DEBUG
129  feLog(" miss: det=%.6G\n",det);
130 #endif
131  return T(-1);
132  }
133  T inv_det=T(1)/det;
134 
135  /* calculate distance from vert0 to ray origin */
136  Vector<3,T> tvec=origin-vert0;
137 
138  /* calculate U parameter and test bounds */
139  T u=dot(tvec,pvec)*inv_det;
140  if(u<T(0) || u>T(1))
141  {
142 #if FE_RTI_DEBUG
143  feLog(" miss: u=%.6G\n",u);
144 #endif
145  return T(-1);
146  }
147 
148  /* prepare to test V parameter */
149  Vector<3,T> qvec;
150  cross3(qvec,tvec,edge1);
151 
152  /* calculate V parameter and test bounds */
153  T v=dot(direction,qvec)*inv_det;
154  if(v<T(0) || u+v>T(1))
155  {
156 #if FE_RTI_DEBUG
157  feLog(" miss: u=%.6G v=%.6G\n",u,v);
158 #endif
159  return T(-1);
160  }
161 
162  /* calculate t, ray intersects triangle */
163  T range=dot(edge2,qvec)*inv_det;
164 #endif
165 /*****************************************************************************/
166 
167  barycenter.setUV(u,v);
168 
169 #if FE_RTI_DEBUG
170  feLog(" hit: u=%.6G v=%.6G range=%.6G\n",u,v,range);
171 #endif
172 
173  return range;
174 }
175 
176 // direction must be normalized
177 template <typename T>
179  const Vector<3,T>& vert0,
180  const Vector<3,T>& vert1,
181  const Vector<3,T>& vert2,
182  const Vector<3,T>& norm0,
183  const Vector<3,T>& norm1,
184  const Vector<3,T>& norm2,
185  const Vector<3,T>& origin,
186  const Vector<3,T>& direction,
187  const Barycenter<T>& barycenter,
188  const T range,
189  Vector<3,T>& intersection,
190  Vector<3,T>& normal)
191 {
192  intersection=origin+direction*range;
193 
194 #if FALSE
195  Vector<3,T> edge1=vert1-vert0;
196  Vector<3,T> edge2=vert2-vert0;
197  cross(normal,edge1,edge2);
198 #else
199  normal=location(barycenter,norm0,norm1,norm2);
200 #endif
201  normalizeSafe(normal);
202 }
203 
204 } /* namespace ext */
205 } /* namespace fe */
206 
207 #endif /* __solve_RayTriangleIntersect_h__ */
208 
kernel
Definition: namespace.dox:3
Barycentric coordinates for a triangle.
Definition: Barycenter.h:26
Find intersection between ray and triangle.
Definition: RayTriangleIntersect.h:32