aboutsummaryrefslogtreecommitdiff
path: root/dep/include/g3dlite/G3D/Ray.h
diff options
context:
space:
mode:
authormaximius <none@none>2009-10-17 15:51:44 -0700
committermaximius <none@none>2009-10-17 15:51:44 -0700
commite585187b248f48b3c6e9247b49fa07c6565d65e5 (patch)
tree637c5b7ddacf41040bef4ea4f75a97da64c6a9bc /dep/include/g3dlite/G3D/Ray.h
parent26b5e033ffde3d161382fc9addbfa99738379641 (diff)
*Backed out changeset 3be01fb200a5
--HG-- branch : trunk
Diffstat (limited to 'dep/include/g3dlite/G3D/Ray.h')
-rw-r--r--dep/include/g3dlite/G3D/Ray.h67
1 files changed, 67 insertions, 0 deletions
diff --git a/dep/include/g3dlite/G3D/Ray.h b/dep/include/g3dlite/G3D/Ray.h
index b44796420f0..3929cf1e6ac 100644
--- a/dep/include/g3dlite/G3D/Ray.h
+++ b/dep/include/g3dlite/G3D/Ray.h
@@ -1,16 +1,23 @@
/**
@file Ray.h
+
Ray class
+
@maintainer Morgan McGuire, matrix@graphics3d.com
+
@created 2002-07-12
@edited 2006-02-21
*/
+
#ifndef G3D_RAY_H
#define G3D_RAY_H
+
#include "G3D/platform.h"
#include "G3D/Vector3.h"
#include "G3D/Triangle.h"
+
namespace G3D {
+
/**
A 3D Ray.
*/
@@ -20,23 +27,30 @@ private:
this->origin = origin;
this->direction = direction;
}
+
public:
Vector3 origin;
+
/**
Not unit length
*/
Vector3 direction;
+
Ray() : origin(Vector3::zero()), direction(Vector3::zero()) {}
+
virtual ~Ray() {}
+
/**
Creates a Ray from a origin and a (nonzero) direction.
*/
static Ray fromOriginAndDirection(const Vector3& point, const Vector3& direction) {
return Ray(point, direction);
}
+
Ray unit() const {
return Ray(origin, direction.unit());
}
+
/**
Returns the closest point on the Ray to point.
*/
@@ -48,33 +62,43 @@ public:
return this->origin + direction * t;
}
}
+
/**
Returns the closest distance between point and the Ray
*/
float distance(const Vector3& point) const {
return (closestPoint(point) - point).magnitude();
}
+
/**
Returns the point where the Ray and plane intersect. If there
is no intersection, returns a point at infinity.
+
Planes are considered one-sided, so the ray will not intersect
a plane where the normal faces in the traveling direction.
*/
Vector3 intersection(const class Plane& plane) const;
+
/**
Returns the distance until intersection with the (solid) sphere.
Will be 0 if inside the sphere, inf if there is no intersection.
+
The ray direction is <B>not</B> normalized. If the ray direction
has unit length, the distance from the origin to intersection
is equal to the time. If the direction does not have unit length,
the distance = time * direction.length().
+
See also the G3D::CollisionDetection "movingPoint" methods,
which give more information about the intersection.
*/
float intersectionTime(const class Sphere& sphere) const;
+
float intersectionTime(const class Plane& plane) const;
+
float intersectionTime(const class Box& box) const;
+
float intersectionTime(const class AABox& box) const;
+
/**
The three extra arguments are the weights of vertices 0, 1, and 2
at the intersection point; they are useful for texture mapping
@@ -84,6 +108,7 @@ public:
const Vector3& v0, const Vector3& v1, const Vector3& v2,
const Vector3& edge01, const Vector3& edge02,
double& w0, double& w1, double& w2) const;
+
/**
Ray-triangle intersection for a 1-sided triangle. Fastest version.
@cite http://www.acm.org/jgt/papers/MollerTrumbore97/
@@ -96,13 +121,16 @@ public:
const Vector3& edge01,
const Vector3& edge02) const;
+
inline float intersectionTime(
const Vector3& vert0,
const Vector3& vert1,
const Vector3& vert2) const {
+
return intersectionTime(vert0, vert1, vert2, vert1 - vert0, vert2 - vert0);
}
+
inline float intersectionTime(
const Vector3& vert0,
const Vector3& vert1,
@@ -110,8 +138,10 @@ public:
double& w0,
double& w1,
double& w2) const {
+
return intersectionTime(vert0, vert1, vert2, vert1 - vert0, vert2 - vert0, w0, w1, w2);
}
+
/* One-sided triangle
*/
inline float intersectionTime(const Triangle& triangle) const {
@@ -119,6 +149,7 @@ public:
triangle.vertex(0), triangle.vertex(1), triangle.vertex(2),
triangle.edge01, triangle.edge02);
}
+
inline float intersectionTime(
const Triangle& triangle,
double& w0,
@@ -127,6 +158,7 @@ public:
return intersectionTime(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2),
triangle.edge01, triangle.edge02, w0, w1, w2);
}
+
/** Refracts about the normal
using G3D::Vector3::refractionDirection
and bumps the ray slightly from the newOrigin. */
@@ -135,6 +167,7 @@ public:
const Vector3& normal,
float iInside,
float iOutside) const;
+
/** Reflects about the normal
using G3D::Vector3::reflectionDirection
and bumps the ray slightly from
@@ -144,44 +177,58 @@ public:
const Vector3& normal) const;
};
+
#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];
+
inline float Ray::intersectionTime(
const Vector3& vert0,
const Vector3& vert1,
const Vector3& vert2,
const Vector3& edge1,
const Vector3& edge2) const {
+
(void)vert1;
(void)vert2;
+
// Barycenteric coords
float u, v;
+
float tvec[3], pvec[3], qvec[3];
+
// begin calculating determinant - also used to calculate U parameter
CROSS(pvec, direction, edge2);
+
// if determinant is near zero, ray lies in plane of triangle
const float det = DOT(edge1, pvec);
+
if (det < EPSILON) {
return (float)inf();
}
+
// calculate distance from vert0 to ray origin
SUB(tvec, origin, vert0);
+
// calculate U parameter and test bounds
u = DOT(tvec, pvec);
if ((u < 0.0f) || (u > det)) {
// Hit the plane outside the triangle
return (float)inf();
}
+
// prepare to test V parameter
CROSS(qvec, tvec, edge1);
+
// calculate V parameter and test bounds
v = DOT(direction, qvec);
if ((v < 0.0f) || (u + v > det)) {
@@ -189,8 +236,10 @@ inline float Ray::intersectionTime(
return (float)inf();
}
+
// Case where we don't need correct (u, v):
const float t = DOT(edge2, qvec);
+
if (t >= 0.0f) {
// Note that det must be positive
return t / det;
@@ -200,6 +249,7 @@ inline float Ray::intersectionTime(
}
}
+
inline float Ray::intersectionTime(
const Vector3& vert0,
const Vector3& vert1,
@@ -209,53 +259,70 @@ inline float Ray::intersectionTime(
double& w0,
double& w1,
double& w2) const {
+
(void)vert1;
(void)vert2;
+
// Barycenteric coords
float u, v;
+
float tvec[3], pvec[3], qvec[3];
+
// begin calculating determinant - also used to calculate U parameter
CROSS(pvec, direction, edge2);
+
// if determinant is near zero, ray lies in plane of triangle
const float det = DOT(edge1, pvec);
+
if (det < EPSILON) {
return (float)inf();
}
+
// calculate distance from vert0 to ray origin
SUB(tvec, origin, vert0);
+
// calculate U parameter and test bounds
u = DOT(tvec, pvec);
if ((u < 0.0f) || (u > det)) {
// Hit the plane outside the triangle
return (float)inf();
}
+
// prepare to test V parameter
CROSS(qvec, tvec, edge1);
+
// calculate V parameter and test bounds
v = DOT(direction, qvec);
if ((v < 0.0f) || (u + v > det)) {
// Hit the plane outside the triangle
return (float)inf();
}
+
float t = DOT(edge2, qvec);
+
if (t >= 0) {
const float inv_det = 1.0f / det;
t *= inv_det;
u *= inv_det;
v *= inv_det;
+
w0 = (1.0f - u - v);
w1 = u;
w2 = v;
+
return t;
} else {
// We had to travel backwards in time to intersect
return (float)inf();
}
}
+
#undef EPSILON
#undef CROSS
#undef DOT
#undef SUB
+
}// namespace
+
#endif