pfx_physics/rigid/
gravity.rs1use super::Pose;
2use super::convert::{Vec3, iso, vec};
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub enum Falloff {
6 Constant,
7 Inverse,
8 InverseSquare,
9}
10
11#[derive(Clone, Copy, Debug, PartialEq)]
12pub enum Region {
13 Sphere { center: [f32; 3], radius: f32 },
14 Box { pose: Pose, half: [f32; 3] },
15}
16
17impl Region {
18 pub fn contains(&self, point: [f32; 3]) -> bool {
19 match *self {
20 Self::Sphere { center, radius } => {
21 vec(point).distance_squared(vec(center)) <= radius * radius
22 }
23 Self::Box { pose, half } => {
24 let local = iso(pose).inverse_transform_point(vec(point));
25 local.x.abs() <= half[0] && local.y.abs() <= half[1] && local.z.abs() <= half[2]
26 }
27 }
28 }
29}
30
31#[derive(Clone, Copy, Debug, PartialEq)]
32pub enum Source {
33 Point {
34 center: [f32; 3],
35 strength: f32,
36 falloff: Falloff,
37 range: f32,
38 softening: f32,
39 },
40 Zone {
41 region: Region,
42 gravity: [f32; 3],
43 replace: bool,
44 },
45}
46
47impl Source {
48 pub fn attractor(center: [f32; 3], strength: f32) -> Self {
49 Self::Point {
50 center,
51 strength,
52 falloff: Falloff::InverseSquare,
53 range: f32::INFINITY,
54 softening: 0.01,
55 }
56 }
57}
58
59#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
60pub struct SourceId(pub(crate) u32);
61
62pub(crate) fn acceleration(sources: &[(SourceId, Source)], world: Vec3, point: Vec3) -> Vec3 {
63 let mut base = world;
64 let mut extra = Vec3::ZERO;
65 for (_, source) in sources {
66 match *source {
67 Source::Point {
68 center,
69 strength,
70 falloff,
71 range,
72 softening,
73 } => {
74 let towards = vec(center) - point;
75 let distance = towards.length();
76 if distance > range || distance <= f32::EPSILON {
77 continue;
78 }
79 let d = distance.max(softening);
80 let scale = match falloff {
81 Falloff::Constant => 1.0,
82 Falloff::Inverse => 1.0 / d,
83 Falloff::InverseSquare => 1.0 / (d * d),
84 };
85 extra += towards / distance * (strength * scale);
86 }
87 Source::Zone {
88 region,
89 gravity,
90 replace,
91 } => {
92 if !region.contains(point.to_array()) {
93 continue;
94 }
95 if replace {
96 base = vec(gravity);
97 } else {
98 extra += vec(gravity);
99 }
100 }
101 }
102 }
103 base - world + extra
104}