Daniele Bartolini 11 роки тому
батько
коміт
ad49276c78
2 змінених файлів з 133 додано та 268 видалено
  1. 8 8
      engine/core/math/frustum.h
  2. 125 260
      engine/core/math/intersection.h

+ 8 - 8
engine/core/math/frustum.h

@@ -97,14 +97,14 @@ namespace frustum
 
 		switch (index)
 		{
-			case 0: return Intersection::test_plane_3(side[4], side[0], side[2], ip);
-			case 1: return Intersection::test_plane_3(side[4], side[1], side[2], ip);
-			case 2: return Intersection::test_plane_3(side[4], side[1], side[3], ip);
-			case 3: return Intersection::test_plane_3(side[4], side[0], side[3], ip);
-			case 4: return Intersection::test_plane_3(side[5], side[0], side[2], ip);
-			case 5: return Intersection::test_plane_3(side[5], side[1], side[2], ip);
-			case 6: return Intersection::test_plane_3(side[5], side[1], side[3], ip);
-			case 7: return Intersection::test_plane_3(side[5], side[0], side[3], ip);
+			case 0: return plane_3_intersection(side[4], side[0], side[2], ip);
+			case 1: return plane_3_intersection(side[4], side[1], side[2], ip);
+			case 2: return plane_3_intersection(side[4], side[1], side[3], ip);
+			case 3: return plane_3_intersection(side[4], side[0], side[3], ip);
+			case 4: return plane_3_intersection(side[5], side[0], side[2], ip);
+			case 5: return plane_3_intersection(side[5], side[1], side[2], ip);
+			case 6: return plane_3_intersection(side[5], side[1], side[3], ip);
+			case 7: return plane_3_intersection(side[5], side[0], side[3], ip);
 			default: break;
 		}
 

+ 125 - 260
engine/core/math/intersection.h

@@ -35,290 +35,155 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 namespace crown
 {
-namespace Intersection
-{
-	/// Returns the distance along ray (from, dir) to intersection point with plane @a p.
-	/// -1.0f if no collision.
-	inline float ray_plane_intersection(const Vector3& from, const Vector3& dir, const Plane& p)
-	{
-		float nd = vector3::dot(dir, p.n);
-		float orpn = vector3::dot(from, p.n);
-		float dist = -1.0f;
 
-		if (nd < 0.0f)
-			dist = (-p.d - orpn) / nd;
-
-		return dist > 0.0f ? dist : -1.0f;
-	}
-	
-	//-----------------------------------------------------------------------------
-	inline bool test_ray_sphere(const Vector3& from, const Vector3& dir, const Sphere& s, float& distance, Vector3& intersectionPoint)
-	{
-		Vector3 v = s.center() - from;
-		float b = vector3::dot(v, dir);
-		float det = (s.radius() * s.radius()) - vector3::dot(v, v) + (b * b);
+/// Returns the distance along ray (from, dir) to intersection point with plane @a p.
+/// -1.0f if no collision.
+inline float ray_plane_intersection(const Vector3& from, const Vector3& dir, const Plane& p)
+{
+	float nd = vector3::dot(dir, p.n);
+	float orpn = vector3::dot(from, p.n);
+	float dist = -1.0f;
 
-		if (det < 0.0 || b < s.radius())
-		{
-			return false;
-		}
+	if (nd < 0.0f)
+		dist = (-p.d - orpn) / nd;
 
-		distance = b - math::sqrt(det);
-		intersectionPoint = from + dir * distance;
+	return dist > 0.0f ? dist : -1.0f;
+}
 
-		return true;
-	}
+/// Returns the distance along ray (from, dir) to intersection point with sphere @a s.
+/// -1.0f if no collision.
+inline float ray_sphere_intersection(const Vector3& from, const Vector3& dir, const Sphere& s)
+{
+	Vector3 v = s.center() - from;
+	float b = vector3::dot(v, dir);
+	float det = (s.radius() * s.radius()) - vector3::dot(v, v) + (b * b);
 
-	//-----------------------------------------------------------------------------
-	inline bool test_plane_3(const Plane& p1, const Plane& p2, const Plane& p3, Vector3& ip)
+	if (det < 0.0 || b < s.radius())
 	{
-		const Vector3& n1 = p1.n;
-		const Vector3& n2 = p2.n;
-		const Vector3& n3 = p3.n;
-
-		float den = -vector3::dot(vector3::cross(n1, n2), n3);
-
-		if (math::equals(den, (float)0.0))
-		{
-			return false;
-		}
-
-		Vector3 res = p1.d * vector3::cross(n2, n3) + p2.d * vector3::cross(n3, n1) + p3.d * vector3::cross(n1, n2);
-		ip = res / den;
-
-		return true;
+		return -1.0f;
 	}
 
-	//-----------------------------------------------------------------------------
-	inline bool test_static_sphere_plane(const Sphere& s, const Plane& p)
-	{
-		if (math::abs(plane::distance_to_point(p, s.center())) < s.radius())
-		{
-			return true;
-		}
+	return b - math::sqrt(det);
+}
 
-		return false;
-	}
+//-----------------------------------------------------------------------------
+inline bool plane_3_intersection(const Plane& p1, const Plane& p2, const Plane& p3, Vector3& ip)
+{
+	const Vector3& n1 = p1.n;
+	const Vector3& n2 = p2.n;
+	const Vector3& n3 = p3.n;
 
-	//-----------------------------------------------------------------------------
-	inline bool test_static_sphere_sphere(const Sphere& a, const Sphere& b)
-	{
-		float dist = vector3::squared_length(b.center() - a.center());
-		return (dist < (b.radius() + a.radius()) * (b.radius() + a.radius()));
-	}
+	float den = -vector3::dot(vector3::cross(n1, n2), n3);
 
-	//-----------------------------------------------------------------------------
-	inline bool test_dynamic_sphere_plane(const Sphere& s, const Vector3& d, const Plane& p, float& it, Vector3& intersectionPoint)
+	if (math::equals(den, (float)0.0))
 	{
-		const Vector3& sphereCenter = s.center();
-		const float sphereRadius = s.radius();
-
-		float t0;	// Time at which the sphere int32_tersects the plane remaining at the front side of the plane
-		float t1;	// Time at which the sphere int32_tersects the plane remaining at the back side of the plane
-
-		float sphereToPlaneDistance = plane::distance_to_point(p, sphereCenter);
-		float planeNormalDotVelocity = vector3::dot(p.n, d);
-
-		if (planeNormalDotVelocity > 0.0)
-		{
-			return false;
-		}
-
-		// If the sphere is travelling parallel to the plane
-		if (planeNormalDotVelocity == 0.0)
-		{
-			// If the sphere is embedded in the plane
-			if (math::abs(sphereToPlaneDistance) < sphereRadius)
-			{
-				t0 = 0.0;
-				t1 = 1.0;
-
-				it = t0;
-				intersectionPoint = s.center() - p.n * s.radius();
-				return true;
-			}
-
-			return false;
-		}
-
-		t0 = (sphereRadius - sphereToPlaneDistance) / planeNormalDotVelocity;
-		t1 = (-sphereRadius - sphereToPlaneDistance) / planeNormalDotVelocity;
-
-		// If _both_ t0 and t1 are outside [0,1] then collision can never happen
-		if (t0 >= 0.0 && t0 <= 1.0)
-		{
-			it = math::min(t0, t1);
-			intersectionPoint = s.center() - p.n * s.radius() + (d * it);
-			return true;
-		}
-
 		return false;
 	}
 
-	//-----------------------------------------------------------------------------
-	inline bool test_dynamic_sphere_sphere(const Sphere& s1, const Vector3& d1, const Sphere& s2, const Vector3& d2, float& it, Vector3& /*intersectionPoint*/)
-	{
-		// s1 == static sphere
-		// s2 == moving sphere
-		Vector3 d = d2 - d1;
-		vector3::normalize(d);
+	Vector3 res = p1.d * vector3::cross(n2, n3) + p2.d * vector3::cross(n3, n1) + p3.d * vector3::cross(n1, n2);
+	ip = res / den;
 
-		const Vector3& cs = s1.center();
-		const Vector3& cm = s2.center();
+	return true;
+}
 
-		Vector3 e = cs - cm;
-		float r = s1.radius() + s2.radius();
-
-		// If ||e|| < r, int32_tersection occurs at t = 0
-		if (vector3::length(e) < r)
-		{
-			it = 0.0;
-			return true;
-		}
-
-		// it == Intersection Time
-		float ed = vector3::dot(e, d);
-		float squared = (ed * ed) + (r * r) - vector3::dot(e, e);
-
-		// If the value inside the square root is neg, then no int32_tersection
-		if (squared < 0.0)
-		{
-			return false;
-		}
-
-		float t = ed - math::sqrt(squared);
-		float l = vector3::length(d2 - d1);
-
-		// If t < 0 || t > l, then non int32_tersection in the considered period of time
-		if (t < 0.0 || t > l)
-		{
-			return false;
-		}
-
-		it = t / l;
-		return true;
-	}
-
-	//-----------------------------------------------------------------------------
-	inline bool test_static_box_box(const AABB& b1, const AABB& b2)
+//-----------------------------------------------------------------------------
+inline bool frustum_sphere_intersection(const Frustum& f, const Sphere& s)
+{
+	if (plane::distance_to_point(f.left, s.center()) < -s.radius() ||
+		plane::distance_to_point(f.right, s.center()) < -s.radius())
 	{
-		if (b1.min.x > b2.max.x || b1.max.x < b2.min.x)
-		{
-			return false;
-		}
-
-		if (b1.min.y > b2.max.y || b1.max.y < b2.min.y)
-		{
-			return false;
-		}
-
-		if (b1.min.z > b2.max.z || b1.max.z < b2.min.z)
-		{
-			return false;
-		}
-
-		return true;
+		return false;
 	}
 
-	//-----------------------------------------------------------------------------
-	inline bool test_frustum_sphere(const Frustum& f, const Sphere& s)
+	if (plane::distance_to_point(f.bottom, s.center()) < -s.radius() ||
+		plane::distance_to_point(f.top, s.center()) < -s.radius())
 	{
-		if (plane::distance_to_point(f.left, s.center()) < -s.radius() ||
-			plane::distance_to_point(f.right, s.center()) < -s.radius())
-		{
-			return false;
-		}
-
-		if (plane::distance_to_point(f.bottom, s.center()) < -s.radius() ||
-			plane::distance_to_point(f.top, s.center()) < -s.radius())
-		{
-			return false;
-		}
-
-		if (plane::distance_to_point(f.near, s.center()) < -s.radius() ||
-			plane::distance_to_point(f.far, s.center()) < -s.radius())
-		{
-			return false;
-		}
-
-		return true;
+		return false;
 	}
 
-	//-----------------------------------------------------------------------------
-	inline bool test_frustum_box(const Frustum& f, const AABB& b)
+	if (plane::distance_to_point(f.near, s.center()) < -s.radius() ||
+		plane::distance_to_point(f.far, s.center()) < -s.radius())
 	{
-		uint8_t out;
-
-		out = 0;
-		if (plane::distance_to_point(f.left, aabb::vertex(b, 0)) < 0.0) out++;
-		if (plane::distance_to_point(f.left, aabb::vertex(b, 1)) < 0.0) out++;
-		if (plane::distance_to_point(f.left, aabb::vertex(b, 2)) < 0.0) out++;
-		if (plane::distance_to_point(f.left, aabb::vertex(b, 3)) < 0.0) out++;
-		if (plane::distance_to_point(f.left, aabb::vertex(b, 4)) < 0.0) out++;
-		if (plane::distance_to_point(f.left, aabb::vertex(b, 5)) < 0.0) out++;
-		if (plane::distance_to_point(f.left, aabb::vertex(b, 6)) < 0.0) out++;
-		if (plane::distance_to_point(f.left, aabb::vertex(b, 7)) < 0.0) out++;
-
-		// If all vertices are outside one face, then the box doesn't intersect the frustum
-		if (out == 8) return false;
-
-		out = 0;
-		if (plane::distance_to_point(f.right, aabb::vertex(b, 0)) < 0.0) out++;
-		if (plane::distance_to_point(f.right, aabb::vertex(b, 1)) < 0.0) out++;
-		if (plane::distance_to_point(f.right, aabb::vertex(b, 2)) < 0.0) out++;
-		if (plane::distance_to_point(f.right, aabb::vertex(b, 3)) < 0.0) out++;
-		if (plane::distance_to_point(f.right, aabb::vertex(b, 4)) < 0.0) out++;
-		if (plane::distance_to_point(f.right, aabb::vertex(b, 5)) < 0.0) out++;
-		if (plane::distance_to_point(f.right, aabb::vertex(b, 6)) < 0.0) out++;
-		if (plane::distance_to_point(f.right, aabb::vertex(b, 7)) < 0.0) out++;
-		if (out == 8) return false;
-
-		out = 0;
-		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 0)) < 0.0) out++;
-		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 1)) < 0.0) out++;
-		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 2)) < 0.0) out++;
-		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 3)) < 0.0) out++;
-		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 4)) < 0.0) out++;
-		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 5)) < 0.0) out++;
-		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 6)) < 0.0) out++;
-		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 7)) < 0.0) out++;
-		if (out == 8) return false;
-
-		out = 0;
-		if (plane::distance_to_point(f.top, aabb::vertex(b, 0)) < 0.0) out++;
-		if (plane::distance_to_point(f.top, aabb::vertex(b, 1)) < 0.0) out++;
-		if (plane::distance_to_point(f.top, aabb::vertex(b, 2)) < 0.0) out++;
-		if (plane::distance_to_point(f.top, aabb::vertex(b, 3)) < 0.0) out++;
-		if (plane::distance_to_point(f.top, aabb::vertex(b, 4)) < 0.0) out++;
-		if (plane::distance_to_point(f.top, aabb::vertex(b, 5)) < 0.0) out++;
-		if (plane::distance_to_point(f.top, aabb::vertex(b, 6)) < 0.0) out++;
-		if (plane::distance_to_point(f.top, aabb::vertex(b, 7)) < 0.0) out++;
-		if (out == 8) return false;
-
-		out = 0;
-		if (plane::distance_to_point(f.near, aabb::vertex(b, 0)) < 0.0) out++;
-		if (plane::distance_to_point(f.near, aabb::vertex(b, 1)) < 0.0) out++;
-		if (plane::distance_to_point(f.near, aabb::vertex(b, 2)) < 0.0) out++;
-		if (plane::distance_to_point(f.near, aabb::vertex(b, 3)) < 0.0) out++;
-		if (plane::distance_to_point(f.near, aabb::vertex(b, 4)) < 0.0) out++;
-		if (plane::distance_to_point(f.near, aabb::vertex(b, 5)) < 0.0) out++;
-		if (plane::distance_to_point(f.near, aabb::vertex(b, 6)) < 0.0) out++;
-		if (plane::distance_to_point(f.near, aabb::vertex(b, 7)) < 0.0) out++;
-		if (out == 8) return false;
+		return false;
+	}
 
-		out = 0;
-		if (plane::distance_to_point(f.far, aabb::vertex(b, 0)) < 0.0) out++;
-		if (plane::distance_to_point(f.far, aabb::vertex(b, 1)) < 0.0) out++;
-		if (plane::distance_to_point(f.far, aabb::vertex(b, 2)) < 0.0) out++;
-		if (plane::distance_to_point(f.far, aabb::vertex(b, 3)) < 0.0) out++;
-		if (plane::distance_to_point(f.far, aabb::vertex(b, 4)) < 0.0) out++;
-		if (plane::distance_to_point(f.far, aabb::vertex(b, 5)) < 0.0) out++;
-		if (plane::distance_to_point(f.far, aabb::vertex(b, 6)) < 0.0) out++;
-		if (plane::distance_to_point(f.far, aabb::vertex(b, 7)) < 0.0) out++;
-		if (out == 8) return false;
+	return true;
+}
 
-		// If we are here, it is because either the box intersects or it is contained in the frustum
-		return true;
-	}
-} // namespace Intersection
+//-----------------------------------------------------------------------------
+inline bool frustum_box_intersection(const Frustum& f, const AABB& b)
+{
+	uint8_t out;
+
+	out = 0;
+	if (plane::distance_to_point(f.left, aabb::vertex(b, 0)) < 0.0) out++;
+	if (plane::distance_to_point(f.left, aabb::vertex(b, 1)) < 0.0) out++;
+	if (plane::distance_to_point(f.left, aabb::vertex(b, 2)) < 0.0) out++;
+	if (plane::distance_to_point(f.left, aabb::vertex(b, 3)) < 0.0) out++;
+	if (plane::distance_to_point(f.left, aabb::vertex(b, 4)) < 0.0) out++;
+	if (plane::distance_to_point(f.left, aabb::vertex(b, 5)) < 0.0) out++;
+	if (plane::distance_to_point(f.left, aabb::vertex(b, 6)) < 0.0) out++;
+	if (plane::distance_to_point(f.left, aabb::vertex(b, 7)) < 0.0) out++;
+
+	// If all vertices are outside one face, then the box doesn't intersect the frustum
+	if (out == 8) return false;
+
+	out = 0;
+	if (plane::distance_to_point(f.right, aabb::vertex(b, 0)) < 0.0) out++;
+	if (plane::distance_to_point(f.right, aabb::vertex(b, 1)) < 0.0) out++;
+	if (plane::distance_to_point(f.right, aabb::vertex(b, 2)) < 0.0) out++;
+	if (plane::distance_to_point(f.right, aabb::vertex(b, 3)) < 0.0) out++;
+	if (plane::distance_to_point(f.right, aabb::vertex(b, 4)) < 0.0) out++;
+	if (plane::distance_to_point(f.right, aabb::vertex(b, 5)) < 0.0) out++;
+	if (plane::distance_to_point(f.right, aabb::vertex(b, 6)) < 0.0) out++;
+	if (plane::distance_to_point(f.right, aabb::vertex(b, 7)) < 0.0) out++;
+	if (out == 8) return false;
+
+	out = 0;
+	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 0)) < 0.0) out++;
+	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 1)) < 0.0) out++;
+	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 2)) < 0.0) out++;
+	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 3)) < 0.0) out++;
+	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 4)) < 0.0) out++;
+	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 5)) < 0.0) out++;
+	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 6)) < 0.0) out++;
+	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 7)) < 0.0) out++;
+	if (out == 8) return false;
+
+	out = 0;
+	if (plane::distance_to_point(f.top, aabb::vertex(b, 0)) < 0.0) out++;
+	if (plane::distance_to_point(f.top, aabb::vertex(b, 1)) < 0.0) out++;
+	if (plane::distance_to_point(f.top, aabb::vertex(b, 2)) < 0.0) out++;
+	if (plane::distance_to_point(f.top, aabb::vertex(b, 3)) < 0.0) out++;
+	if (plane::distance_to_point(f.top, aabb::vertex(b, 4)) < 0.0) out++;
+	if (plane::distance_to_point(f.top, aabb::vertex(b, 5)) < 0.0) out++;
+	if (plane::distance_to_point(f.top, aabb::vertex(b, 6)) < 0.0) out++;
+	if (plane::distance_to_point(f.top, aabb::vertex(b, 7)) < 0.0) out++;
+	if (out == 8) return false;
+
+	out = 0;
+	if (plane::distance_to_point(f.near, aabb::vertex(b, 0)) < 0.0) out++;
+	if (plane::distance_to_point(f.near, aabb::vertex(b, 1)) < 0.0) out++;
+	if (plane::distance_to_point(f.near, aabb::vertex(b, 2)) < 0.0) out++;
+	if (plane::distance_to_point(f.near, aabb::vertex(b, 3)) < 0.0) out++;
+	if (plane::distance_to_point(f.near, aabb::vertex(b, 4)) < 0.0) out++;
+	if (plane::distance_to_point(f.near, aabb::vertex(b, 5)) < 0.0) out++;
+	if (plane::distance_to_point(f.near, aabb::vertex(b, 6)) < 0.0) out++;
+	if (plane::distance_to_point(f.near, aabb::vertex(b, 7)) < 0.0) out++;
+	if (out == 8) return false;
+
+	out = 0;
+	if (plane::distance_to_point(f.far, aabb::vertex(b, 0)) < 0.0) out++;
+	if (plane::distance_to_point(f.far, aabb::vertex(b, 1)) < 0.0) out++;
+	if (plane::distance_to_point(f.far, aabb::vertex(b, 2)) < 0.0) out++;
+	if (plane::distance_to_point(f.far, aabb::vertex(b, 3)) < 0.0) out++;
+	if (plane::distance_to_point(f.far, aabb::vertex(b, 4)) < 0.0) out++;
+	if (plane::distance_to_point(f.far, aabb::vertex(b, 5)) < 0.0) out++;
+	if (plane::distance_to_point(f.far, aabb::vertex(b, 6)) < 0.0) out++;
+	if (plane::distance_to_point(f.far, aabb::vertex(b, 7)) < 0.0) out++;
+	if (out == 8) return false;
+
+	// If we are here, it is because either the box intersects or it is contained in the frustum
+	return true;
+}
 } // namespace crown