#include "CmRay.h" #include "CmPlane.h" #include "CmSphere.h" #include "CmAABox.h" namespace CamelotFramework { std::pair Ray::intersects(const Plane& p) const { return p.intersects(*this); } std::pair Ray::intersects(const Sphere& s) const { return s.intersects(*this); } std::pair Ray::intersects(const AABox& box) const { return box.intersects(*this); } std::pair Ray::intersects(const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& normal, bool positiveSide, bool negativeSide) const { // // Calculate intersection with plane. // float t; { float denom = normal.dot(getDirection()); // Check intersect side if (denom > + std::numeric_limits::epsilon()) { if (!negativeSide) return std::pair(false, 0.0f); } else if (denom < - std::numeric_limits::epsilon()) { if (!positiveSide) return std::pair(false, 0.0f); } else { // Parallel or triangle area is close to zero when // the plane normal not normalised. return std::pair(false, 0.0f); } t = normal.dot(a - getOrigin()) / denom; if (t < 0) { // Intersection is behind origin return std::pair(false, 0.0f); } } // // Calculate the largest area projection plane in X, Y or Z. // size_t i0, i1; { float n0 = Math::abs(normal[0]); float n1 = Math::abs(normal[1]); float n2 = Math::abs(normal[2]); i0 = 1; i1 = 2; if (n1 > n2) { if (n1 > n0) i0 = 0; } else { if (n2 > n0) i1 = 0; } } // // Check the intersection point is inside the triangle. // { float u1 = b[i0] - a[i0]; float v1 = b[i1] - a[i1]; float u2 = c[i0] - a[i0]; float v2 = c[i1] - a[i1]; float u0 = t * getDirection()[i0] + getOrigin()[i0] - a[i0]; float v0 = t * getDirection()[i1] + getOrigin()[i1] - a[i1]; float alpha = u0 * v2 - u2 * v0; float beta = u1 * v0 - u0 * v1; float area = u1 * v2 - u2 * v1; // epsilon to avoid float precision error const float EPSILON = 1e-6f; float tolerance = - EPSILON * area; if (area > 0) { if (alpha < tolerance || beta < tolerance || alpha+beta > area-tolerance) return std::pair(false, 0.0f); } else { if (alpha > tolerance || beta > tolerance || alpha+beta < area-tolerance) return std::pair(false, 0.0f); } } return std::pair(true, t); } }