6 @maintainer Morgan McGuire, matrix@graphics3d.com
15 #include "G3D/platform.h"
16 #include "G3D/Vector3.h"
17 #include "G3D/Triangle.h"
26 Ray(const Vector3
& origin
, const Vector3
& direction
) {
27 this->origin
= origin
;
28 this->direction
= direction
;
39 Ray() : origin(Vector3::zero()), direction(Vector3::zero()) {}
44 Creates a Ray from a origin and a (nonzero) direction.
46 static Ray
fromOriginAndDirection(const Vector3
& point
, const Vector3
& direction
) {
47 return Ray(point
, direction
);
51 return Ray(origin
, direction
.unit());
55 Returns the closest point on the Ray to point.
57 Vector3
closestPoint(const Vector3
& point
) const {
58 float t
= direction
.dot(point
- this->origin
);
62 return this->origin
+ direction
* t
;
67 Returns the closest distance between point and the Ray
69 float distance(const Vector3
& point
) const {
70 return (closestPoint(point
) - point
).magnitude();
74 Returns the point where the Ray and plane intersect. If there
75 is no intersection, returns a point at infinity.
77 Planes are considered one-sided, so the ray will not intersect
78 a plane where the normal faces in the traveling direction.
80 Vector3
intersection(const class Plane
& plane
) const;
83 Returns the distance until intersection with the (solid) sphere.
84 Will be 0 if inside the sphere, inf if there is no intersection.
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().
91 See also the G3D::CollisionDetection "movingPoint" methods,
92 which give more information about the intersection.
94 float intersectionTime(const class Sphere
& sphere
) const;
96 float intersectionTime(const class Plane
& plane
) const;
98 float intersectionTime(const class Box
& box
) const;
100 float intersectionTime(const class AABox
& box
) const;
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.
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;
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
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;
125 inline float intersectionTime(
126 const Vector3
& vert0
,
127 const Vector3
& vert1
,
128 const Vector3
& vert2
) const {
130 return intersectionTime(vert0
, vert1
, vert2
, vert1
- vert0
, vert2
- vert0
);
134 inline float intersectionTime(
135 const Vector3
& vert0
,
136 const Vector3
& vert1
,
137 const Vector3
& vert2
,
142 return intersectionTime(vert0
, vert1
, vert2
, vert1
- vert0
, vert2
- vert0
, w0
, w1
, w2
);
145 /* One-sided triangle
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
);
153 inline float intersectionTime(
154 const Triangle
& triangle
,
158 return intersectionTime(triangle
.vertex(0), triangle
.vertex(1), triangle
.vertex(2),
159 triangle
.edge01
, triangle
.edge02
, w0
, w1
, w2
);
162 /** Refracts about the normal
163 using G3D::Vector3::refractionDirection
164 and bumps the ray slightly from the newOrigin. */
166 const Vector3
& newOrigin
,
167 const Vector3
& normal
,
169 float iOutside
) const;
171 /** Reflects about the normal
172 using G3D::Vector3::reflectionDirection
173 and bumps the ray slightly from
176 const Vector3
& newOrigin
,
177 const Vector3
& normal
) const;
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];
187 #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
189 #define SUB(dest,v1,v2) \
190 dest[0]=v1[0]-v2[0]; \
191 dest[1]=v1[1]-v2[1]; \
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 {
204 // Barycenteric coords
207 float tvec
[3], pvec
[3], qvec
[3];
209 // begin calculating determinant - also used to calculate U parameter
210 CROSS(pvec
, direction
, edge2
);
212 // if determinant is near zero, ray lies in plane of triangle
213 const float det
= DOT(edge1
, pvec
);
219 // calculate distance from vert0 to ray origin
220 SUB(tvec
, origin
, vert0
);
222 // calculate U parameter and test bounds
224 if ((u
< 0.0f
) || (u
> det
)) {
225 // Hit the plane outside the triangle
229 // prepare to test V parameter
230 CROSS(qvec
, tvec
, edge1
);
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
240 // Case where we don't need correct (u, v):
241 const float t
= DOT(edge2
, qvec
);
244 // Note that det must be positive
247 // We had to travel backwards in time to intersect
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
,
266 // Barycenteric coords
269 float tvec
[3], pvec
[3], qvec
[3];
271 // begin calculating determinant - also used to calculate U parameter
272 CROSS(pvec
, direction
, edge2
);
274 // if determinant is near zero, ray lies in plane of triangle
275 const float det
= DOT(edge1
, pvec
);
281 // calculate distance from vert0 to ray origin
282 SUB(tvec
, origin
, vert0
);
284 // calculate U parameter and test bounds
286 if ((u
< 0.0f
) || (u
> det
)) {
287 // Hit the plane outside the triangle
291 // prepare to test V parameter
292 CROSS(qvec
, tvec
, edge1
);
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
301 float t
= DOT(edge2
, qvec
);
304 const float inv_det
= 1.0f
/ det
;
315 // We had to travel backwards in time to intersect