Skip to main content

alice_physics/
static_collider.rs

1//! Immovable collision surfaces for a [`PhysicsWorld`](crate::solver::PhysicsWorld).
2//!
3//! A [`StaticCollider`] is a plane, a height field or a triangle mesh that bodies
4//! rest on. It is the counterpart of the SDF colliders for explicit geometry: the
5//! world resolves each non-static, non-sensor body's collision sphere against
6//! every collider after the substep's collision detection, pushing the body out
7// LIMITATION(COV-RIGID-065): world resolves each non-static, non-sensor body's collision sphere against every collider after the substep's collision detection
8//! along the contact normal by the penetration depth — the correction the
9//! position-based solver turns into a velocity.
10//!
11//! # Which sphere
12//!
13//! A body's collision radius (`add_body_with_radius`, `set_body_collision_radius`)
14//! is the sphere tested. A body with none uses the world's default
15//! (`set_sdf_collision_radius`), exactly as it does against an SDF collider.
16//!
17//! # Sides
18//!
19//! A [`PlaneCollider`] is **two-sided**, as the primitive documents: a sphere
20//! whose centre is behind the plane is held on that side. A [`HeightField`] and a
21//! [`TriMesh`] have no inside; a sphere is pushed away from the surface point
22//! nearest it.
23//!
24//! Author: Moroya Sakamoto
25
26use crate::collider::Contact;
27use crate::heightfield::HeightField;
28use crate::math::{Fix128, Vec3Fix};
29use crate::plane_collider::PlaneCollider;
30use crate::trimesh::TriMesh;
31
32/// A surface that does not move.
33pub enum StaticCollider {
34    /// An infinite plane.
35    Plane(PlaneCollider),
36    /// A grid of heights over the `XZ` plane.
37    HeightField(HeightField),
38    /// A triangle soup with a BVH.
39    TriMesh(TriMesh),
40}
41
42impl StaticCollider {
43    /// The contact of a sphere with this surface: the penetration depth and the
44    /// normal pointing from the surface toward the sphere's centre, or `None` when
45    /// the sphere is clear of it.
46    #[must_use]
47    pub fn collide_sphere(&self, center: Vec3Fix, radius: Fix128) -> Option<Contact> {
48        match self {
49            Self::Plane(plane) => {
50                let hit = plane.intersect_sphere(center, radius);
51                hit.colliding.then_some(Contact {
52                    depth: hit.depth,
53                    normal: hit.normal,
54                    point_a: hit.point_a,
55                    point_b: hit.point_b,
56                })
57            }
58            Self::HeightField(field) => field.collide_sphere(center, radius),
59            Self::TriMesh(mesh) => mesh.collide_sphere(center, radius),
60        }
61    }
62}