// =================================================================== // $Id: sbbox.cpp $ // // ssbbox.cpp // Simply bounding box for ray tracing only, 24 Bytes in size. // REPLACEMENT_STRING // // Copyright by Vlastimil Havran, 2007 - email to "vhavran AT seznam.cz" // Initial coding by Vlasta Havran, December 2005 // GOLEM headers #include "sbbox.h" #undef INLINE #define INLINE //#define INLINE INLINE namespace GtpVisibilityPreprocessor { void Describe(const SBBox &b, ostream &app, int ind) { indent(app, ind); app << "SBBox: min at(" << b.Min() << "), max at(" << b.Max() << ")\n"; } // Function describing the box void DescribeXYZ(const SBBox &b, ostream &app, int ind) { indent(app, ind); app << " box = ( " << b.Min().x << " , " << b.Max().x << " )( " << b.Min().y << " , " << b.Max().y << " )( " << b.Min().z << " , " << b.Max().z << " )\n"; } bool SBBox::Includes(const SBBox &b) const { if (b.pp[0].x >= pp[0].x && b.pp[0].y >= pp[0].y && b.pp[0].z >= pp[0].z && b.pp[1].x <= pp[1].x && b.pp[1].y <= pp[1].y && b.pp[1].z <= pp[1].z) return true; return false; } bool SBBox::Includes(const SBBox &b, float eps) const { if (b.pp[0].x >= pp[0].x - eps && b.pp[0].y >= pp[0].y - eps && b.pp[0].z >= pp[0].z - eps && b.pp[1].x <= pp[1].x + eps && b.pp[1].y <= pp[1].y + eps && b.pp[1].z <= pp[1].z + eps) return true; return false; } #if 0 // The implementation I, the first version implemented by Vlastimil // Havran, without looking into the literature INLINE bool SBBox::RayIntersect(const CRay &ray, float &tmin, float &tmax) const { float interval_min = tmin; float interval_max = tmax; const CVector3D &rayLoc = ray.GetLoc(); const CVector3D &rayinvDir = ray.GetInvertedDir(); float t0, t1; if (rayinvDir.x > 0) { t0 = (pp[0].x - rayLoc.x) * rayinvDir.x; t1 = (pp[1].x - rayLoc.x) * rayinvDir.x; } else { t0 = (pp[1].x - rayLoc.x) * rayinvDir.x; t1 = (pp[0].x - rayLoc.x) * rayinvDir.x; } assert(t0 <= t1); if (t0 > interval_min) interval_min = t0; if (t1 < interval_max) interval_max = t1; if (interval_min > interval_max) return false; if (rayinvDir.y > 0) { t0 = (pp[0].y - rayLoc.y) * rayinvDir.y; t1 = (pp[1].y - rayLoc.y) * rayinvDir.y; } else { t0 = (pp[1].y - rayLoc.y) * rayinvDir.y; t1 = (pp[0].y - rayLoc.y) * rayinvDir.y; } assert(t0 <= t1); if (t0 > interval_min) interval_min = t0; if (t1 < interval_max) interval_max = t1; if (interval_min > interval_max) return false; if (rayinvDir.z > 0) { t0 = (pp[0].z - rayLoc.z) * rayinvDir.z; t1 = (pp[1].z - rayLoc.z) * rayinvDir.z; } else { t0 = (pp[1].z - rayLoc.z) * rayinvDir.z; t1 = (pp[0].z - rayLoc.z) * rayinvDir.z; } assert(t0 <= t1); if (t0 > interval_min) interval_min = t0; if (t1 < interval_max) interval_max = t1; // return true if the box is intersected // return false if not intersected by ray if ( (interval_max > 0.0f) && (interval_min <= interval_max) ) { // yes, intersected, update tmin and tmax for current node tmin = interval_min; tmax = interval_max; return true; } return false; // not intersected } #endif // ------------------------------------------------------------- #if 0 // The implementation II // The code follows the article by Mueller/Geimer 2003 paper INLINE float minf(const float a, const float b) { return (a < b) ? a : b;} INLINE float maxf(const float a, const float b) { return (a > b) ? a : b;} INLINE bool SBBox::RayIntersect(const CRay &ray, float &tmin, float &tmax) const { //assert(tmin <= tmax); const CVector3D &rayLoc = ray.GetLoc(); const CVector3D &rayinvDir = ray.GetInvertedDir(); register float t0, t1; // coordinate x t0 = (pp[0].x - rayLoc.x) * rayinvDir.x; t1 = (pp[1].x - rayLoc.x) * rayinvDir.x; register float ttmin = maxf(minf(t0, t1), tmin); register float ttmax = minf(maxf(t0, t1), tmax); // coordinate y t0 = (pp[0].y - rayLoc.y) * rayinvDir.y; t1 = (pp[1].y - rayLoc.y) * rayinvDir.y; ttmin = maxf(minf(t0, t1), ttmin); ttmax = minf(maxf(t0, t1), ttmax); // coordinate z t0 = (pp[0].z - rayLoc.z) * rayinvDir.z; t1 = (pp[1].z - rayLoc.z) * rayinvDir.z; ttmin = maxf(minf(t0, t1), ttmin); ttmax = minf(maxf(t0, t1), ttmax); // return true if the box is intersected // return false if not intersected by ray if ( (ttmax > 0.f) && (ttmin <= ttmax)) { // yes, intersected, update tmin and tmax for current node tmin = ttmin; tmax = ttmax; return true; } return false; // not intersected } #endif // ------------------------------------------------------------- #if 0 // The implementation III // The code follows the article by Mueller/Geimer 2003 paper // - improved possibly by earlier termination. INLINE float minf(const float a, const float b) { return (a < b) ? a : b;} INLINE float maxf(const float a, const float b) { return (a > b) ? a : b;} INLINE bool SBBox::RayIntersect(const CRay &ray, float &tmin, float &tmax) const { //assert(tmin <= tmax); const CVector3D &rayLoc = ray.GetLoc(); const CVector3D &rayinvDir = ray.GetInvertedDir(); register float t0, t1; // coordinate x t0 = (pp[0].x - rayLoc.x) * rayinvDir.x; t1 = (pp[1].x - rayLoc.x) * rayinvDir.x; register float ttmin = maxf(minf(t0, t1), tmin); register float ttmax = minf(maxf(t0, t1), tmax); if (ttmin > ttmax) return false; // coordinate y t0 = (pp[0].y - rayLoc.y) * rayinvDir.y; t1 = (pp[1].y - rayLoc.y) * rayinvDir.y; ttmin = maxf(minf(t0, t1), ttmin); ttmax = minf(maxf(t0, t1), ttmax); if (ttmin > ttmax) return false; // coordinate z t0 = (pp[0].z - rayLoc.z) * rayinvDir.z; t1 = (pp[1].z - rayLoc.z) * rayinvDir.z; ttmin = maxf(minf(t0, t1), ttmin); ttmax = minf(maxf(t0, t1), ttmax); // return true if the box is intersected // return false if not intersected by ray if ( (ttmax > 0.f) && (ttmin <= ttmax)) { // yes, intersected, update tmin and tmax for current node tmin = ttmin; tmax = ttmax; return true; } return false; // not intersected } #endif #if 0 // The implementation IV // - improved implementation I - it does not work for shadow rays ? INLINE float minf(const float a, const float b) { return (a < b) ? a : b;} INLINE float maxf(const float a, const float b) { return (a > b) ? a : b;} INLINE bool SBBox::RayIntersect(const CRay &ray, float &tmin, float &tmax) const { register float interval_min = tmin; register float interval_max = tmax; const CVector3D &rayLoc = ray.GetLoc(); const CVector3D &rayinvDir = ray.GetInvertedDir(); register float t0, t1; if (rayinvDir.x > 0) { t0 = (pp[0].x - rayLoc.x) * rayinvDir.x; t1 = (pp[1].x - rayLoc.x) * rayinvDir.x; } else { t0 = (pp[1].x - rayLoc.x) * rayinvDir.x; t1 = (pp[0].x - rayLoc.x) * rayinvDir.x; } assert(t0 <= t1); interval_min = maxf(t0, interval_min); interval_max = minf(t1, interval_min); if (interval_min > interval_max) return false; if (rayinvDir.y > 0) { t0 = (pp[0].y - rayLoc.y) * rayinvDir.y; t1 = (pp[1].y - rayLoc.y) * rayinvDir.y; } else { t0 = (pp[1].y - rayLoc.y) * rayinvDir.y; t1 = (pp[0].y - rayLoc.y) * rayinvDir.y; } assert(t0 <= t1); interval_min = maxf(t0, interval_min); interval_max = minf(t1, interval_min); if (interval_min > interval_max) return false; if (rayinvDir.z > 0) { t0 = (pp[0].z - rayLoc.z) * rayinvDir.z; t1 = (pp[1].z - rayLoc.z) * rayinvDir.z; } else { t0 = (pp[1].z - rayLoc.z) * rayinvDir.z; t1 = (pp[0].z - rayLoc.z) * rayinvDir.z; } assert(t0 <= t1); interval_min = maxf(t0, interval_min); interval_max = minf(t1, interval_min); // return true if the box is intersected // return false if not intersected by ray if ( (interval_max > 0.f) && (interval_min <= interval_max)) { // yes, intersected, update tmin and tmax for current node tmin = interval_min; tmax = interval_max; return true; } return false; // not intersected } #endif // ------------------------------------------------------------- #if 0 // The implementation V // The code follows the article by Mueller/Geimer 2003 paper // - changed. - it does not work for shadow rays ? INLINE bool SBBox::RayIntersect(const CRay &ray, float &tmin, float &tmax) const { //assert(tmin <= tmax); const CVector3D &rayLoc = ray.GetLoc(); const CVector3D &rayinvDir = ray.GetInvertedDir(); register float tt_min = tmin; register float tt_max = tmax; register float t0, t1; // coordinate x t0 = (pp[0].x - rayLoc.x) * rayinvDir.x; t1 = (pp[1].x - rayLoc.x) * rayinvDir.x; register float rmin, rmax; if (t1 < t0) { rmin = t1; // min rmax = t0; // max } else { rmin = t0; // min rmax = t1; // max } assert(rmin <= rmax); if (tt_min < rmin) tt_min = rmin; // take maximum if (tt_max > rmax) tt_max = rmax; // take minimum if (tt_min > tt_max) return false; // coordinate y t0 = (pp[0].y - rayLoc.y) * rayinvDir.y; t1 = (pp[1].y - rayLoc.y) * rayinvDir.y; if (t1 < t0) { rmin = t1; // min rmax = t0; // max } else { rmin = t0; // min rmax = t1; // max } assert(rmin <= rmax); if (tt_min < rmin) tt_min = rmin; // take maximum if (tt_max > rmax) tt_max = rmax; // take minimum if (tt_min > tt_max) return false; // coordinate z t0 = (pp[0].z - rayLoc.z) * rayinvDir.z; t1 = (pp[1].z - rayLoc.z) * rayinvDir.z; if (t1 < t0) { rmin = t1; // min rmax = t0; // max } else { rmin = t0; // min rmax = t1; // max } assert(rmin <= rmax); if (tt_min < rmin) tt_min = rmin; // take maximum if (tt_max > rmax) tt_max = rmax; // take minimum if ((tt_min > tt_max) || (tt_max < 0.f) ) return false; // not intersected // yes, intersected, update tmin and tmax for current node tmin = tt_min; tmax = tt_max; return true; } #endif // ------------------------------------------------------------- #if 0 // The implementation VI // The code follows the article in SIGGRAPH 2005 course notes, // page 59, likely by Peter Shirley and Boulos Solomon. INLINE float minf(const float a, const float b) { return (a < b) ? a : b;} INLINE float maxf(const float a, const float b) { return (a > b) ? a : b;} INLINE bool SBBox::RayIntersect(const CRay &ray, float &t0, float &t1) const { //assert(tmin <= tmax); const CVector3D &rayLoc = ray.GetLoc(); const CVector3D &rayinvDir = ray.GetInvertedDir(); // coordinate x float tmin = (pp[ray.GetSign(0)].x - rayLoc.x) * rayinvDir.x; float tmax = (pp[1-ray.GetSign(0)].x - rayLoc.x) * rayinvDir.x; float tymin = (pp[ray.GetSign(1)].y - rayLoc.y) * rayinvDir.y; float tymax = (pp[1-ray.GetSign(1)].y - rayLoc.y) * rayinvDir.y; if ( (tmin > tymax) || (tymin > tmax) ) return false; if (tymin > tmin) tmin = tymin; if (tymax < tmax) tmax = tymax; float tzmin = (pp[ray.GetSign(2)].z - rayLoc.z) * rayinvDir.z; float tzmax = (pp[1-ray.GetSign(2)].z - rayLoc.y) * rayinvDir.z; if ( (tmin > tzmax) || (tzmin > tmax) ) return false; if (tzmin > tmin) tmin = tzmin; if (tzmax < tmax) tmax = tzmax; return ( (tmin < t1) && (tmax >= 0.f) ); } #endif // End of ray-box intersections // ---------------------------------------------------------- } // namespace