diff --git a/src/SConscript b/src/SConscript index 7dc7283..f4d1987 100644 --- a/src/SConscript +++ b/src/SConscript @@ -22,6 +22,7 @@ files = [ 'light.cc', 'material.cc', 'object.cc', + 'objectBox.cc', 'object_sphere.cc', #'object_plane.cc', 'reader_yaml.cc', diff --git a/src/objectBox.cc b/src/objectBox.cc new file mode 100644 index 0000000..cacec91 --- /dev/null +++ b/src/objectBox.cc @@ -0,0 +1,152 @@ +/* objectBox.cc + * vim: set tw=80: + * Eryn Wells + */ + +#include + +#include "objectBox.hh" + + +namespace charles { + +Box::Box() + /* A unit box centered on the origin. */ + : Box(Vector3(-0.5, -0.5, -0.5), Vector3(0.5, 0.5, 0.5)) +{ } + + +Box::Box(const Vector3& near, const Vector3& far) + : Object(), + mNear(near), + mFar(far) +{ } + + +bool +Box::DoesIntersect(const Ray& ray, + TVector& t) + const +{ + /* + * XXX: For now, I'm assuming that all boxes are parallel to the coordinate + * axes. This is the Kay-Kajiya box intersection algorithm. + */ + + Double t0, t1; + Double tNear = -std::numeric_limits::infinity(); + Double tFar = std::numeric_limits::infinity(); + + /* + * From the Ray Tracing book: + * + * For a more efficient algorithm, unwrap the loop, expand the swap of t0 + * and t1 into two branches, and change the calculations to multiply by + * the inverse of the ray's direction to avoid divisions. Unwrapping the + * loop allows elimination of comparing t0 adn t1 to tNear and tFar [for + * the X planes], as tNear will always be set to the smaller and tFar the + * larger of t0 and t1. + * + * Initially there was a for loop iterating over each parallel pair of + * planes (X, Y, and Z planes). + */ + + /* Unrolling the loop, so we start with the X planes... */ + + if (ray.direction.x == 0.0) { + /* The ray is parallel to the X axis. */ + if (ray.origin.x < mNear.x || ray.origin.x > mFar.x) { + /* The ray's origin is not between the slabs, so no intersection. */ + return false; + } + } else { + Double invX = 1.0 / ray.direction.x; + t0 = (mNear.x - ray.origin.x) * invX; + t1 = (mFar.x - ray.origin.x) * invX; + if (t0 > t1) { + tNear = t1; + tFar = t0; + } else { + tNear = t0; + tFar = t1; + } + + if (tNear > tFar) { + /* Box is missed. */ + return false; + } + if (tFar < 0.0) { + /* Box is behind the ray. */ + return false; + } + } + + /* Now the Y planes. */ + + if (ray.direction.y == 0.0) { + /* The ray is parallel to the Y axis. */ + if (ray.origin.y < mNear.y || ray.origin.y > mFar.y) { + /* The ray's origin is not between the slabs, so no intersection. */ + return false; + } + } else { + /* The ray isn't parallel, so calculate the intersection points. */ + Double invY = 1.0 / ray.direction.y; + t0 = (mNear.y - ray.origin.y) * invY; + t1 = (mFar.y - ray.origin.y) * invY; + if (t0 > t1) { + tNear = t1; + tFar = t0; + } else { + tNear = t0; + tFar = t1; + } + + if (tNear > tFar) { + /* Box is missed. */ + return false; + } + if (tFar < 0.0) { + /* Box is behind the ray. */ + return false; + } + } + + /* Finally, the Z planes. */ + + if (ray.direction.z == 0.0) { + /* The ray is parallel to the Z axis. */ + if (ray.origin.z < mNear.z || ray.origin.z > mFar.z) { + /* The ray's origin is not between the slabs, so no intersection. */ + return false; + } + } else { + Double invZ = 1.0 / ray.direction.z; + t0 = (mNear.z - ray.origin.z) * invZ; + t1 = (mFar.z - ray.origin.z) * invZ; + if (t0 > t1) { + tNear = t1; + tFar = t0; + } else { + tNear = t0; + tFar = t1; + } + + if (tNear > tFar) { + /* Box is missed. */ + return false; + } + if (tFar < 0.0) { + /* Box is behind the ray. */ + return false; + } + } + + /* We have an intersection! */ + t.push_back(t0); + t.push_back(t1); + return true; +} + +} /* namespace charles */ + diff --git a/src/objectBox.hh b/src/objectBox.hh new file mode 100644 index 0000000..c02d743 --- /dev/null +++ b/src/objectBox.hh @@ -0,0 +1,31 @@ +/* objectBox.hh + * vim: set tw=80: + * Eryn Wells + */ + +#include "basics.h" +#include "object.h" +#include "types.hh" + + +namespace charles { + +struct Box + : public Object +{ + Box(); + Box(const Vector3& near, const Vector3& far); + + bool DoesIntersect(const Ray& ray, TVector& t) const; + bool point_is_on_surface(const Vector3 &p) const; + Vector3 compute_normal(const Vector3 &p) const; + +private: + /** The near, lower left corner. */ + Vector3 mNear; + + /** The far, upper right corner. */ + Vector3 mFar; +}; + +} /* namespace charles */