root/trunk/dep/include/g3dlite/G3D/Ray.h @ 2

Revision 2, 8.2 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
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
19namespace G3D {
20
21/**
22 A 3D Ray.
23 */
24class Ray {
25private:
26    Ray(const Vector3& origin, const Vector3& direction) {
27        this->origin    = origin;
28        this->direction = direction;
29    }
30
31public:
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
194inline 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
253inline 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
Note: See TracBrowser for help on using the browser.