1 | /** |
---|
2 | @file Ray.h |
---|
3 | |
---|
4 | Ray class |
---|
5 | |
---|
6 | @maintainer Morgan McGuire, matrix@graphics3d.com |
---|
7 | |
---|
8 | @created 2002-07-12 |
---|
9 | @edited 2006-02-21 |
---|
10 | */ |
---|
11 | |
---|
12 | #ifndef G3D_RAY_H |
---|
13 | #define G3D_RAY_H |
---|
14 | |
---|
15 | #include "G3D/platform.h" |
---|
16 | #include "G3D/Vector3.h" |
---|
17 | #include "G3D/Triangle.h" |
---|
18 | |
---|
19 | namespace G3D { |
---|
20 | |
---|
21 | /** |
---|
22 | A 3D Ray. |
---|
23 | */ |
---|
24 | class Ray { |
---|
25 | private: |
---|
26 | Ray(const Vector3& origin, const Vector3& direction) { |
---|
27 | this->origin = origin; |
---|
28 | this->direction = direction; |
---|
29 | } |
---|
30 | |
---|
31 | public: |
---|
32 | Vector3 origin; |
---|
33 | |
---|
34 | /** |
---|
35 | Not unit length |
---|
36 | */ |
---|
37 | Vector3 direction; |
---|
38 | |
---|
39 | Ray() : origin(Vector3::zero()), direction(Vector3::zero()) {} |
---|
40 | |
---|
41 | virtual ~Ray() {} |
---|
42 | |
---|
43 | /** |
---|
44 | Creates a Ray from a origin and a (nonzero) direction. |
---|
45 | */ |
---|
46 | static Ray fromOriginAndDirection(const Vector3& point, const Vector3& direction) { |
---|
47 | return Ray(point, direction); |
---|
48 | } |
---|
49 | |
---|
50 | Ray unit() const { |
---|
51 | return Ray(origin, direction.unit()); |
---|
52 | } |
---|
53 | |
---|
54 | /** |
---|
55 | Returns the closest point on the Ray to point. |
---|
56 | */ |
---|
57 | Vector3 closestPoint(const Vector3& point) const { |
---|
58 | float t = direction.dot(point - this->origin); |
---|
59 | if (t < 0) { |
---|
60 | return this->origin; |
---|
61 | } else { |
---|
62 | return this->origin + direction * t; |
---|
63 | } |
---|
64 | } |
---|
65 | |
---|
66 | /** |
---|
67 | Returns the closest distance between point and the Ray |
---|
68 | */ |
---|
69 | float distance(const Vector3& point) const { |
---|
70 | return (closestPoint(point) - point).magnitude(); |
---|
71 | } |
---|
72 | |
---|
73 | /** |
---|
74 | Returns the point where the Ray and plane intersect. If there |
---|
75 | is no intersection, returns a point at infinity. |
---|
76 | |
---|
77 | Planes are considered one-sided, so the ray will not intersect |
---|
78 | a plane where the normal faces in the traveling direction. |
---|
79 | */ |
---|
80 | Vector3 intersection(const class Plane& plane) const; |
---|
81 | |
---|
82 | /** |
---|
83 | Returns the distance until intersection with the (solid) sphere. |
---|
84 | Will be 0 if inside the sphere, inf if there is no intersection. |
---|
85 | |
---|
86 | The ray direction is <B>not</B> normalized. If the ray direction |
---|
87 | has unit length, the distance from the origin to intersection |
---|
88 | is equal to the time. If the direction does not have unit length, |
---|
89 | the distance = time * direction.length(). |
---|
90 | |
---|
91 | See also the G3D::CollisionDetection "movingPoint" methods, |
---|
92 | which give more information about the intersection. |
---|
93 | */ |
---|
94 | float intersectionTime(const class Sphere& sphere) const; |
---|
95 | |
---|
96 | float intersectionTime(const class Plane& plane) const; |
---|
97 | |
---|
98 | float intersectionTime(const class Box& box) const; |
---|
99 | |
---|
100 | float intersectionTime(const class AABox& box) const; |
---|
101 | |
---|
102 | /** |
---|
103 | The three extra arguments are the weights of vertices 0, 1, and 2 |
---|
104 | at the intersection point; they are useful for texture mapping |
---|
105 | and interpolated normals. |
---|
106 | */ |
---|
107 | float intersectionTime( |
---|
108 | const Vector3& v0, const Vector3& v1, const Vector3& v2, |
---|
109 | const Vector3& edge01, const Vector3& edge02, |
---|
110 | double& w0, double& w1, double& w2) const; |
---|
111 | |
---|
112 | /** |
---|
113 | Ray-triangle intersection for a 1-sided triangle. Fastest version. |
---|
114 | @cite http://www.acm.org/jgt/papers/MollerTrumbore97/ |
---|
115 | http://www.graphics.cornell.edu/pubs/1997/MT97.html |
---|
116 | */ |
---|
117 | inline float intersectionTime( |
---|
118 | const Vector3& vert0, |
---|
119 | const Vector3& vert1, |
---|
120 | const Vector3& vert2, |
---|
121 | const Vector3& edge01, |
---|
122 | const Vector3& edge02) const; |
---|
123 | |
---|
124 | |
---|
125 | inline float intersectionTime( |
---|
126 | const Vector3& vert0, |
---|
127 | const Vector3& vert1, |
---|
128 | const Vector3& vert2) const { |
---|
129 | |
---|
130 | return intersectionTime(vert0, vert1, vert2, vert1 - vert0, vert2 - vert0); |
---|
131 | } |
---|
132 | |
---|
133 | |
---|
134 | inline float intersectionTime( |
---|
135 | const Vector3& vert0, |
---|
136 | const Vector3& vert1, |
---|
137 | const Vector3& vert2, |
---|
138 | double& w0, |
---|
139 | double& w1, |
---|
140 | double& w2) const { |
---|
141 | |
---|
142 | return intersectionTime(vert0, vert1, vert2, vert1 - vert0, vert2 - vert0, w0, w1, w2); |
---|
143 | } |
---|
144 | |
---|
145 | /* One-sided triangle |
---|
146 | */ |
---|
147 | inline float intersectionTime(const Triangle& triangle) const { |
---|
148 | return intersectionTime( |
---|
149 | triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), |
---|
150 | triangle.edge01, triangle.edge02); |
---|
151 | } |
---|
152 | |
---|
153 | inline float intersectionTime( |
---|
154 | const Triangle& triangle, |
---|
155 | double& w0, |
---|
156 | double& w1, |
---|
157 | double& w2) const { |
---|
158 | return intersectionTime(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), |
---|
159 | triangle.edge01, triangle.edge02, w0, w1, w2); |
---|
160 | } |
---|
161 | |
---|
162 | /** Refracts about the normal |
---|
163 | using G3D::Vector3::refractionDirection |
---|
164 | and bumps the ray slightly from the newOrigin. */ |
---|
165 | Ray refract( |
---|
166 | const Vector3& newOrigin, |
---|
167 | const Vector3& normal, |
---|
168 | float iInside, |
---|
169 | float iOutside) const; |
---|
170 | |
---|
171 | /** Reflects about the normal |
---|
172 | using G3D::Vector3::reflectionDirection |
---|
173 | and bumps the ray slightly from |
---|
174 | the newOrigin. */ |
---|
175 | Ray reflect( |
---|
176 | const Vector3& newOrigin, |
---|
177 | const Vector3& normal) const; |
---|
178 | }; |
---|
179 | |
---|
180 | |
---|
181 | #define EPSILON 0.000001 |
---|
182 | #define CROSS(dest,v1,v2) \ |
---|
183 | dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \ |
---|
184 | dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \ |
---|
185 | dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; |
---|
186 | |
---|
187 | #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) |
---|
188 | |
---|
189 | #define SUB(dest,v1,v2) \ |
---|
190 | dest[0]=v1[0]-v2[0]; \ |
---|
191 | dest[1]=v1[1]-v2[1]; \ |
---|
192 | dest[2]=v1[2]-v2[2]; |
---|
193 | |
---|
194 | inline float Ray::intersectionTime( |
---|
195 | const Vector3& vert0, |
---|
196 | const Vector3& vert1, |
---|
197 | const Vector3& vert2, |
---|
198 | const Vector3& edge1, |
---|
199 | const Vector3& edge2) const { |
---|
200 | |
---|
201 | (void)vert1; |
---|
202 | (void)vert2; |
---|
203 | |
---|
204 | // Barycenteric coords |
---|
205 | float u, v; |
---|
206 | |
---|
207 | float tvec[3], pvec[3], qvec[3]; |
---|
208 | |
---|
209 | // begin calculating determinant - also used to calculate U parameter |
---|
210 | CROSS(pvec, direction, edge2); |
---|
211 | |
---|
212 | // if determinant is near zero, ray lies in plane of triangle |
---|
213 | const float det = DOT(edge1, pvec); |
---|
214 | |
---|
215 | if (det < EPSILON) { |
---|
216 | return (float)inf(); |
---|
217 | } |
---|
218 | |
---|
219 | // calculate distance from vert0 to ray origin |
---|
220 | SUB(tvec, origin, vert0); |
---|
221 | |
---|
222 | // calculate U parameter and test bounds |
---|
223 | u = DOT(tvec, pvec); |
---|
224 | if ((u < 0.0f) || (u > det)) { |
---|
225 | // Hit the plane outside the triangle |
---|
226 | return (float)inf(); |
---|
227 | } |
---|
228 | |
---|
229 | // prepare to test V parameter |
---|
230 | CROSS(qvec, tvec, edge1); |
---|
231 | |
---|
232 | // calculate V parameter and test bounds |
---|
233 | v = DOT(direction, qvec); |
---|
234 | if ((v < 0.0f) || (u + v > det)) { |
---|
235 | // Hit the plane outside the triangle |
---|
236 | return (float)inf(); |
---|
237 | } |
---|
238 | |
---|
239 | |
---|
240 | // Case where we don't need correct (u, v): |
---|
241 | const float t = DOT(edge2, qvec); |
---|
242 | |
---|
243 | if (t >= 0.0f) { |
---|
244 | // Note that det must be positive |
---|
245 | return t / det; |
---|
246 | } else { |
---|
247 | // We had to travel backwards in time to intersect |
---|
248 | return (float)inf(); |
---|
249 | } |
---|
250 | } |
---|
251 | |
---|
252 | |
---|
253 | inline float Ray::intersectionTime( |
---|
254 | const Vector3& vert0, |
---|
255 | const Vector3& vert1, |
---|
256 | const Vector3& vert2, |
---|
257 | const Vector3& edge1, |
---|
258 | const Vector3& edge2, |
---|
259 | double& w0, |
---|
260 | double& w1, |
---|
261 | double& w2) const { |
---|
262 | |
---|
263 | (void)vert1; |
---|
264 | (void)vert2; |
---|
265 | |
---|
266 | // Barycenteric coords |
---|
267 | float u, v; |
---|
268 | |
---|
269 | float tvec[3], pvec[3], qvec[3]; |
---|
270 | |
---|
271 | // begin calculating determinant - also used to calculate U parameter |
---|
272 | CROSS(pvec, direction, edge2); |
---|
273 | |
---|
274 | // if determinant is near zero, ray lies in plane of triangle |
---|
275 | const float det = DOT(edge1, pvec); |
---|
276 | |
---|
277 | if (det < EPSILON) { |
---|
278 | return (float)inf(); |
---|
279 | } |
---|
280 | |
---|
281 | // calculate distance from vert0 to ray origin |
---|
282 | SUB(tvec, origin, vert0); |
---|
283 | |
---|
284 | // calculate U parameter and test bounds |
---|
285 | u = DOT(tvec, pvec); |
---|
286 | if ((u < 0.0f) || (u > det)) { |
---|
287 | // Hit the plane outside the triangle |
---|
288 | return (float)inf(); |
---|
289 | } |
---|
290 | |
---|
291 | // prepare to test V parameter |
---|
292 | CROSS(qvec, tvec, edge1); |
---|
293 | |
---|
294 | // calculate V parameter and test bounds |
---|
295 | v = DOT(direction, qvec); |
---|
296 | if ((v < 0.0f) || (u + v > det)) { |
---|
297 | // Hit the plane outside the triangle |
---|
298 | return (float)inf(); |
---|
299 | } |
---|
300 | |
---|
301 | float t = DOT(edge2, qvec); |
---|
302 | |
---|
303 | if (t >= 0) { |
---|
304 | const float inv_det = 1.0f / det; |
---|
305 | t *= inv_det; |
---|
306 | u *= inv_det; |
---|
307 | v *= inv_det; |
---|
308 | |
---|
309 | w0 = (1.0f - u - v); |
---|
310 | w1 = u; |
---|
311 | w2 = v; |
---|
312 | |
---|
313 | return t; |
---|
314 | } else { |
---|
315 | // We had to travel backwards in time to intersect |
---|
316 | return (float)inf(); |
---|
317 | } |
---|
318 | } |
---|
319 | |
---|
320 | #undef EPSILON |
---|
321 | #undef CROSS |
---|
322 | #undef DOT |
---|
323 | #undef SUB |
---|
324 | |
---|
325 | }// namespace |
---|
326 | |
---|
327 | #endif |
---|