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}