(hopefully) finished Box::Clip()
[MicroTrace.git] / Box.cxx
diff --git a/Box.cxx b/Box.cxx
index 9f1ca77..70ab618 100644 (file)
--- a/Box.cxx
+++ b/Box.cxx
@@ -67,41 +67,52 @@ Box::Clip(const Ray& ray, float& tnear, float& tfar) const
   Vec3f diff_min = m_min - ray.origin(); // o-a
   Vec3f diff_max = m_max - ray.origin();
 
-  float cos_theta;
-  float tx_near, tx_far;
+  float cos_theta, temp;
+  float tx_near = -Infinity, tx_far = Infinity,
+    ty_near = -Infinity, ty_far = Infinity,
+    tz_near = -Infinity, tz_far = Infinity;
 
   // clip along x axis
-  if(cos_theta = ray.direction().dot(Vec3f(1,0,0)) != 0) // if not parallel...
+  if((cos_theta = ray.direction().dot(Vec3f(1,0,0))) != 0) // if not parallel...
     tx_near = diff_min.dot(Vec3f(1,0,0)) / cos_theta;
-  if(cos_theta = ray.direction().dot(Vec3f(1,0,0)) != 0)
+  if((cos_theta = ray.direction().dot(Vec3f(1,0,0))) != 0)
     tx_far = diff_max.dot(Vec3f(1,0,0)) / cos_theta;
 
-  // clip along y axis
-  if(cos_theta = ray.direction().dot(Vec3f(0,1,0)) != 0)
+  // we don't know which is nearer, m_min or m_max, so swap them if neccessary
+  if(tx_near > tx_far) {
+    temp = tx_near;
+    tx_near = tx_far;
+    tx_far = temp;
+  }
+
+  // do the same for y axis
+  if((cos_theta = ray.direction().dot(Vec3f(0,1,0))) != 0)
     ty_near = diff_min.dot(Vec3f(0,1,0)) / cos_theta;
-  if(cos_theta = ray.direction().dot(Vec3f(0,0,1)) != 0)
+  if((cos_theta = ray.direction().dot(Vec3f(0,1,0))) != 0)
     ty_far = diff_max.dot(Vec3f(0,1,0)) / cos_theta;
-
-  // ray intersects box iff it intersects projection on xy plane
-  // in this case: tx_near <= ty_near <= tx_far  <= ty_far
-  //           or: tx_far  <= ty_near <= tx_near <= ty_far
-  //           or: tx_far  <= ty_far  <= tx_near <= ty_near
-  //           or: tx_near <= ty_far  <= tx_far  <= ty_near
-  if(tx_near <= ty_near && tx_far <= ty_near &&
-    tx_near <= ty_far && tx_far <= ty_far) {
-
-    // clip along z axis
-    if (cos_theta = ray.direction().dot(Vec3f(0, 1, 0)) != 0)
-      tz_near = diff_min.dot(Vec3f(0, 1, 0)) / cos_theta;
-    if (cos_theta = ray.direction().dot(Vec3f(0, 0, 1)) != 0)
-      tz_far = diff_max.dot(Vec3f(0, 1, 0)) / cos_theta;
-
-  } else {
-
+  if(ty_near > ty_far) {
+    temp = ty_near;
+    ty_near = ty_far;
+    ty_far = temp;
   }
 
-  //////////////////////////
+  // ...and for z axis
+  if((cos_theta = ray.direction().dot(Vec3f(0,0,1))) != 0)
+    tz_near = diff_min.dot(Vec3f(0,0,1)) / cos_theta;
+  if((cos_theta = ray.direction().dot(Vec3f(0,0,1))) != 0)
+    tz_far = diff_max.dot(Vec3f(0,0,1)) / cos_theta;
+  if(tz_near > tz_far) {
+    temp = tz_near;
+    tz_near = tz_far;
+    tz_far = temp;
+  }
 
+  // now the maximum of "near"s is the entry point of the ray, the minimum
+  // of "far"s is the ray's exit point. Visually speaking: the ray must cross
+  // all three "near" planes before it can be inside the box.
+  // Note: If t_near_max > t_far_min, the ray does not intersect the box
+  tnear = fmax(fmax(tx_near, ty_near), tz_near);
+  tfar = fmin(fmin(tx_far, ty_far), tz_far);
 }
 
 const Vec3f&
This page took 0.032199 seconds and 4 git commands to generate.