return out << "Sphere(" << s.origin << ", " << s.radius << ')';
}
+bool Intersection(
+ const Sphere &a,
+ const Sphere &b,
+ float &dist,
+ glm::vec3 &norm
+) noexcept {
+ glm::vec3 diff(b.origin - a.origin);
+ float dist2 = glm::length2(diff);
+ if (dist2 < std::numeric_limits<float>::epsilon()) {
+ // origins coincide, use smaller of the diameters for
+ // depth and pick arbitrary normal
+ dist = 2.0f * std::min(a.radius, b.radius);
+ norm = glm::vec3(1.0f, 0.0f, 0.0f);
+ return true;
+ }
+ if (dist2 < (a.radius + b.radius) * (a.radius + b.radius)) {
+ dist = std::sqrt(dist2);
+ norm = diff / dist;
+ dist = a.radius - (dist - b.radius);
+ return true;
+ } else {
+ return false;
+ }
+}
+
bool Intersection(
const Sphere &sphere,
const Plane &plane,
return glm::length(high);
}
+ void Position(const glm::vec3 ¢er) noexcept {
+ const glm::vec3 halfsize((max - min) * 0.5f);
+ min = center - halfsize;
+ max = center + halfsize;
+ }
void Move(const glm::vec3 &delta) noexcept {
min += delta;
max += delta;
bool CullTest(const AABB &box, const Frustum &) noexcept;
struct Sphere {
+
glm::vec3 origin;
float radius;
+
+ void Position(const glm::vec3 ¢er) noexcept {
+ origin = center;
+ }
+ void Move(const glm::vec3 &delta) noexcept {
+ origin += delta;
+ }
+
};
std::ostream &operator <<(std::ostream &, const Sphere &);
+/// Two spheres intersection test.
+bool Intersection(
+ const Sphere &,
+ const Sphere &,
+ float &dist,
+ glm::vec3 &norm) noexcept;
+
/// Test for intersection of sphere with double sided infinite plane.
/// If true, dist will hold the smaller interpenetration depth and norm
/// the respective contact normal.
);
}
+void IntersectionTest::testSphereSphere() {
+ const float delta = std::numeric_limits<float>::epsilon();
+
+ Sphere a{{ 0.0f, 0.0f, 0.0f }, 1.0f};
+ Sphere b{{ 0.0f, 0.0f, 0.0f }, 1.0f};
+ float depth;
+ glm::vec3 normal;
+
+ CPPUNIT_ASSERT_MESSAGE(
+ "coincidental spheres should intersect",
+ Intersection(a, b, depth, normal)
+ );
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ "bad intersection distance",
+ 2.0f, depth, delta
+ );
+ // normal can be just about anything
+
+ b.Move({ 1, 0, 0 });
+ CPPUNIT_ASSERT_MESSAGE(
+ "spheres should intersect",
+ Intersection(a, b, depth, normal)
+ );
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ "bad intersection distance",
+ 1.0f, depth, delta
+ );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "bad intersection normal",
+ glm::vec3(1, 0, 0), normal
+ );
+
+ b.Position({ -1.5, 0, 0 });
+ CPPUNIT_ASSERT_MESSAGE(
+ "spheres should intersect",
+ Intersection(a, b, depth, normal)
+ );
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+ "bad intersection distance",
+ 0.5f, depth, delta
+ );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "bad intersection normal",
+ glm::vec3(-1, 0, 0), normal
+ );
+
+ b.Move({ -1, 0, 0 });
+ CPPUNIT_ASSERT_MESSAGE(
+ "spheres should not intersect",
+ !Intersection(a, b, depth, normal)
+ );
+}
+
void IntersectionTest::testSpherePlane() {
const float delta = std::numeric_limits<float>::epsilon();