11 float t = (point - a).Dot(ab);
12 float denom = ab.
Dot(ab);
13 if (denom < 1e-8f)
return a;
14 t = std::clamp(t / denom, 0.0f, 1.0f);
31 if (a < 1e-8f && e < 1e-8f) {
39 t = std::clamp(f / e, 0.0f, 1.0f);
44 s = std::clamp(-c / a, 0.0f, 1.0f);
47 float denom = a * e - b * b;
49 if (std::abs(denom) > 1e-8f) {
50 s = std::clamp((b * f - c * e) / denom, 0.0f, 1.0f);
59 s = std::clamp(-c / a, 0.0f, 1.0f);
60 }
else if (t > 1.0f) {
62 s = std::clamp((b - c) / a, 0.0f, 1.0f);
67 closestA = a1 + d1 * s;
68 closestB = b1 + d2 * t;
93 float minOverlap = overlapX1;
96 if (overlapX2 < minOverlap) { minOverlap = overlapX2; normal =
Vector3D(-1, 0, 0); }
97 if (overlapY1 < minOverlap) { minOverlap = overlapY1; normal =
Vector3D(0, 1, 0); }
98 if (overlapY2 < minOverlap) { minOverlap = overlapY2; normal =
Vector3D(0, -1, 0); }
99 if (overlapZ1 < minOverlap) { minOverlap = overlapZ1; normal =
Vector3D(0, 0, 1); }
100 if (overlapZ2 < minOverlap) { minOverlap = overlapZ2; normal =
Vector3D(0, 0, -1); }
116 if (dist >= sumR)
return result;
134 float distSq = diff.
Dot(diff);
138 float dist = std::sqrt(distSq);
193 if (nLen < 1e-8f)
return result;
194 n = n * (1.0f / nLen);
196 float dist = (sphere.
center - v0).Dot(n);
197 if (std::abs(dist) > sphere.
radius)
return result;
204 float d00 = edge0.
Dot(edge0);
205 float d01 = edge0.
Dot(edge1);
206 float d11 = edge1.
Dot(edge1);
207 float d20 = v0p.
Dot(edge0);
208 float d21 = v0p.
Dot(edge1);
209 float denom = d00 * d11 - d01 * d01;
211 if (std::abs(denom) < 1e-8f)
return result;
213 float bv = (d11 * d20 - d01 * d21) / denom;
214 float bw = (d00 * d21 - d01 * d20) / denom;
215 float bu = 1.0f - bv - bw;
218 if (bu >= 0 && bv >= 0 && bw >= 0) {
226 float d0 = (sphere.
center - c0).Dot(sphere.
center - c0);
227 float d1 = (sphere.
center - c1).Dot(sphere.
center - c1);
228 float d2 = (sphere.
center - c2).Dot(sphere.
center - c2);
232 if (d1 < minD) { minD = d1; closestPoint = c1; }
233 if (d2 < minD) { closestPoint = c2; }
237 float distSq = diff.
Dot(diff);
238 if (distSq >= sphere.
radius * sphere.
radius)
return result;
240 float d = std::sqrt(distSq);
255 for (
size_t i = 0; i + 2 < b.
indices.size(); i += 3) {
281 std::min(sMin.
GetZ(), sMax.
GetZ())),
289 float maxScale = std::max({std::abs(scale.
GetX()), std::abs(scale.
GetY()), std::abs(scale.
GetZ())});
294 float maxScale = std::max({std::abs(scale.
GetX()), std::abs(scale.
GetY()), std::abs(scale.
GetZ())});
295 float axisScale = 1.0f;
296 if (c.
axis == 0) axisScale = std::abs(scale.
GetX());
297 else if (c.
axis == 1) axisScale = std::abs(scale.
GetY());
298 else axisScale = std::abs(scale.
GetZ());
307 for (
size_t i = 0; i < m.
vertices.size(); ++i) {
317 using A = std::decay_t<
decltype(a)>;
318 using B = std::decay_t<
decltype(b)>;
320 if constexpr (std::is_same_v<A, AABB> && std::is_same_v<B, AABB>) {
323 else if constexpr (std::is_same_v<A, BoundingSphere> && std::is_same_v<B, BoundingSphere>) {
326 else if constexpr (std::is_same_v<A, AABB> && std::is_same_v<B, BoundingSphere>) {
329 else if constexpr (std::is_same_v<A, BoundingSphere> && std::is_same_v<B, AABB>) {
331 m.contact.normal = m.contact.normal * -1.0f;
334 else if constexpr (std::is_same_v<A, BoundingSphere> && std::is_same_v<B, BoundingCapsule>) {
337 else if constexpr (std::is_same_v<A, BoundingCapsule> && std::is_same_v<B, BoundingSphere>) {
339 m.contact.normal = m.contact.normal * -1.0f;
342 else if constexpr (std::is_same_v<A, AABB> && std::is_same_v<B, BoundingCapsule>) {
345 else if constexpr (std::is_same_v<A, BoundingCapsule> && std::is_same_v<B, AABB>) {
347 m.contact.normal = m.contact.normal * -1.0f;
350 else if constexpr (std::is_same_v<A, BoundingCapsule> && std::is_same_v<B, BoundingCapsule>) {
353 else if constexpr (std::is_same_v<A, BoundingSphere> && std::is_same_v<B, TriangleMesh>) {
356 else if constexpr (std::is_same_v<A, TriangleMesh> && std::is_same_v<B, BoundingSphere>) {
358 m.contact.normal = m.contact.normal * -1.0f;
361 else if constexpr (std::is_same_v<A, AABB> && std::is_same_v<B, TriangleMesh>) {
364 else if constexpr (std::is_same_v<A, TriangleMesh> && std::is_same_v<B, AABB>) {
366 m.contact.normal = m.contact.normal * -1.0f;
float Dot(const Vector3D &other) const
Vector3D Cross(const Vector3D &other) const
Collision shapes, the broadphase tree, and the world that steps them.
void ClosestPointsSegmentSegment(const Vector3D &a1, const Vector3D &a2, const Vector3D &b1, const Vector3D &b2, Vector3D &closestA, Vector3D &closestB)
Nearest points between two line segments, used for capsule-vs-capsule tests.
CollisionManifold TestSphereVsTriangle(const BoundingSphere &sphere, const Vector3D &v0, const Vector3D &v1, const Vector3D &v2)
static BoundingSphere TransformSphere(const BoundingSphere &s, const Vector3D &pos, const Vector3D &scale)
std::variant< AABB, BoundingSphere, BoundingCapsule, TriangleMesh > ColliderShape
Tagged union of the shapes a ColliderComponent can hold.
CollisionManifold TestCapsuleVsCapsule(const BoundingCapsule &a, const BoundingCapsule &b)
Vector3D ClosestPointOnSegment(const Vector3D &point, const Vector3D &a, const Vector3D &b)
Nearest point on segment [a, b] to the given point.
CollisionManifold TestAABBvsCapsule(const AABB &a, const BoundingCapsule &b)
CollisionManifold TestSphereVsMesh(const BoundingSphere &a, const TriangleMesh &b)
CollisionManifold TestAABBvsAABB(const AABB &a, const AABB &b)
Narrow-phase collision tests; the resulting normal always points from A to B.
static Vector3D ClosestPointOnAABB(const AABB &aabb, const Vector3D &point)
Clamps point into the box, giving the nearest surface or interior point.
CollisionManifold TestAABBvsSphere(const AABB &a, const BoundingSphere &b)
CollisionManifold TestSphereVsCapsule(const BoundingSphere &a, const BoundingCapsule &b)
CollisionManifold TestSphereVsSphere(const BoundingSphere &a, const BoundingSphere &b)
static TriangleMesh TransformMesh(const TriangleMesh &m, const Vector3D &pos, const Vector3D &scale)
static BoundingCapsule TransformCapsule(const BoundingCapsule &c, const Vector3D &pos, const Vector3D &scale)
CollisionManifold TestCollision(const ColliderShape &shapeA, const Vector3D &posA, const Vector3D &scaleA, const ColliderShape &shapeB, const Vector3D &posB, const Vector3D &scaleB)
Dispatches to the right narrow-phase test based on the runtime shape held by each variant.
CollisionManifold TestAABBvsMesh(const AABB &a, const TriangleMesh &b)
static AABB TransformAABB(const AABB &aabb, const Vector3D &pos, const Vector3D &scale)
Root namespace for everything the engine exposes.
Vector3D GetCenter() const
bool Overlaps(const AABB &other) const
Vector3D GetPointA() const
World position of the capsule's positive-axis cap center.
Vector3D GetPointB() const
World position of the capsule's negative-axis cap center.
static BoundingSphere FromAABB(const AABB &aabb)
Builds the sphere circumscribing the given AABB.
std::vector< Vector3D > vertices
std::vector< uint32_t > indices