--- @section Intersection --- To use this module, you need to use require to bring it to scope: --- ```lua --- local intersection = require "intersection" --- ``` local intersection = {} --- Tests a sphere against a sphere. function intersection.test_sphere_sphere(center1, radius1, center2, radius2) return distance_squared3(center1, center2) <= (radius1 + radius2) ^ 2.0 end --- Tests a sphere against a point. function intersection.test_sphere_point(center, radius, point) return distance_squared3(center, point) <= radius ^ 2.0 end --- Tests an axis aligned bounding box (AABB) against an AABB. function intersection.test_aabb_aabb(center1, half_size1, center2, half_size2) return math.abs(center1.x - center2.x) <= half_size1.x + half_size2.x and math.abs(center1.y - center2.y) <= half_size1.y + half_size2.y and math.abs(center1.z - center2.z) <= half_size1.z + half_size2.z end --- Tests an axis aligned bounding box against a point. function intersection.test_aabb_point(center, half_size, point) local min_x = center.x - half_size.x local min_y = center.y - half_size.y local min_z = center.z - half_size.z local max_x = center.x + half_size.x local max_y = center.y + half_size.y local max_z = center.z + half_size.z return point.x >= min_x and point.y >= min_y and point.z >= min_z and point.x <= max_x and point.y <= max_y and point.z <= max_z end --- Computes the radius of the base of a cone. Cone angle is the opening angle at the apex. function intersection.cone_radius(cone_angle, cone_length) return cone_length * math.tan(cone_angle * 0.5) end --- Tests a sphere against a cone. The parametrization of the cone is a bit unusual; instead of defining --- the cone with two end points and radius, it's defined with the following parameters: --- cone_apex: the position of the cone apex, --- cone_dir: the direction vector from cone apex towards the base, --- cone_angle: the opening angle at the apex, --- cone_length: the distance from apex to base along cone axis. --- The assumption here is that the cone is used for testing many spheres, so this parametrization --- avoids computing the same value repeatedly in the inner loop (test_sphere_cone routine). function intersection.test_sphere_cone(sphere_pos, sphere_radius, cone_apex, cone_dir, cone_angle, cone_length) -- references: -- https://bartwronski.com/2017/04/13/cull-that-cone/ -- https://www.cbloom.com/3d/techdocs/culling.txt local v = sphere_pos - cone_apex local a = dot3(v, cone_dir) -- projected distance along cone axis (0.0 = apex) if a < -sphere_radius or a > cone_length + sphere_radius then return false end local distance_closest_point = math.cos(cone_angle * 0.5) * math.sqrt(dot3(v, v) - a * a) - a * math.sin(cone_angle * 0.5) return distance_closest_point <= sphere_radius end return intersection