Box objects, parallel to the coordinate axes
This change implements Kay-Kajiya intersection (with slabs) too!
This commit is contained in:
parent
d69d708b31
commit
15db0c42d4
3 changed files with 184 additions and 0 deletions
|
@ -22,6 +22,7 @@ files = [
|
|||
'light.cc',
|
||||
'material.cc',
|
||||
'object.cc',
|
||||
'objectBox.cc',
|
||||
'object_sphere.cc',
|
||||
#'object_plane.cc',
|
||||
'reader_yaml.cc',
|
||||
|
|
152
src/objectBox.cc
Normal file
152
src/objectBox.cc
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* objectBox.cc
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
|
||||
#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<Double>::infinity();
|
||||
Double tFar = std::numeric_limits<Double>::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 */
|
||||
|
31
src/objectBox.hh
Normal file
31
src/objectBox.hh
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* objectBox.hh
|
||||
* vim: set tw=80:
|
||||
* Eryn Wells <eryn@erynwells.me>
|
||||
*/
|
||||
|
||||
#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 */
|
Loading…
Add table
Add a link
Reference in a new issue