anput_physics/density_fields/
mod.rs

1pub mod aabb;
2pub mod addition;
3pub mod multiplication;
4pub mod sphere;
5pub mod subtraction;
6
7use crate::{Scalar, components::BodyAccessInfo};
8use std::{
9    any::Any,
10    ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
11};
12use vek::{Aabb, Vec3};
13
14pub struct DensityFieldBox(Box<dyn DensityField>);
15
16impl DensityFieldBox {
17    pub fn new(field: impl DensityField + 'static) -> Self {
18        Self(Box::new(field))
19    }
20
21    pub fn as_any(&self) -> &dyn Any {
22        &*self.0
23    }
24
25    pub fn as_any_mut(&mut self) -> &mut dyn Any {
26        &mut *self.0
27    }
28}
29
30impl Deref for DensityFieldBox {
31    type Target = dyn DensityField;
32
33    fn deref(&self) -> &Self::Target {
34        &*self.0
35    }
36}
37
38impl DerefMut for DensityFieldBox {
39    fn deref_mut(&mut self) -> &mut Self::Target {
40        &mut *self.0
41    }
42}
43
44pub trait DensityField: Send + Sync + Any {
45    /// Returns the AABB that contains the density field.
46    #[allow(unused_variables)]
47    fn aabb(&self, info: &BodyAccessInfo) -> Aabb<Scalar>;
48
49    /// Returns the precise density at the given point.
50    /// Reported densities are useful for narrow area queries.
51    ///
52    /// Value 0.0 means no shape occupancy, 1.0 means full occupancy and values
53    /// in between are considered density gradient.
54    /// Shape might report scaled densities, e.g. reporting 0.5 on entire shape.
55    ///
56    /// Scaled densities are useful to represent soft shapes like fluid or fog.
57    /// This allows for collision queries to achieve partial penetration based
58    /// on density threshold, so if we have an object that has hard body core
59    /// and soft outline, another object might partially penetrate that object
60    /// outline and still not report collision.
61    fn density_at_point(&self, point: Vec3<Scalar>, info: &BodyAccessInfo) -> Scalar;
62
63    /// Returns the approximate minimum and maximum density at the given region.
64    /// Reported densities are useful for broad area queries.
65    ///
66    /// This is useful for queries that require density at a larger region,
67    /// for example if some collision queries do quad/oct tree subdivision
68    /// use min-max to tell if region should be subdivided further or not.
69    ///
70    /// The default implementation divides the region into chunks and samples
71    /// densities at the center of each chunk using `density_at_point` and then
72    /// reduces the results to find the minimum and maximum density.
73    /// You should implement this method if you want to provide a more
74    /// efficient way to compute the density range at a specific region.
75    fn density_at_region(&self, region: Aabb<Scalar>, info: &BodyAccessInfo) -> DensityRange {
76        let center = region.center();
77        let size = region.size().into_array().map(|size| size * 0.5);
78        std::iter::once(center)
79            .chain(
80                size.into_iter()
81                    .enumerate()
82                    .filter(|(_, size)| *size > Scalar::EPSILON)
83                    .flat_map(|(index, size)| {
84                        let mut offset = Vec3::zero();
85                        offset[index] = size;
86                        [center - offset, center + offset]
87                    }),
88            )
89            .map(|point| DensityRange::converged(self.density_at_point(point, info)))
90            .reduce(|accum, range| accum.min_max(&range))
91            .unwrap()
92    }
93
94    /// Returns normalized "surface" normal at the given point.
95    ///
96    /// It represents the direction of the density change gradient from more
97    /// dense to less dense change at that point.
98    /// Resolution parameter is used in case when only way to calculate normal
99    /// is by multisampling, so resolution can be used for sampling offsets
100    /// around queried point.
101    ///
102    /// The default implementation returns zero meaning no particular direction.
103    #[allow(unused_variables)]
104    fn normal_at_point(
105        &self,
106        point: Vec3<Scalar>,
107        resolution: Vec3<Scalar>,
108        info: &BodyAccessInfo,
109    ) -> Vec3<Scalar> {
110        Default::default()
111    }
112}
113
114#[derive(Debug, Default, Clone, Copy, PartialEq)]
115pub struct DensityRange {
116    pub min: Scalar,
117    pub max: Scalar,
118}
119
120impl DensityRange {
121    pub fn converged(density: Scalar) -> Self {
122        Self {
123            min: density,
124            max: density,
125        }
126    }
127
128    pub fn separation(&self) -> Scalar {
129        (self.max - self.min).abs()
130    }
131
132    pub fn has_converged(&self) -> bool {
133        self.separation() < Scalar::EPSILON
134    }
135
136    pub fn has_separation(&self) -> bool {
137        !self.has_converged()
138    }
139
140    pub fn average(&self) -> Scalar {
141        (self.min + self.max) * 0.5
142    }
143
144    pub fn min_max(&self, other: &Self) -> Self {
145        Self {
146            min: self.min.min(other.min),
147            max: self.max.max(other.max),
148        }
149    }
150
151    pub fn clamp(&self) -> Self {
152        Self {
153            min: self.min.clamp(0.0, 1.0),
154            max: self.max.clamp(0.0, 1.0),
155        }
156    }
157}
158
159impl Add for DensityRange {
160    type Output = Self;
161
162    fn add(self, other: Self) -> Self::Output {
163        Self {
164            min: self.min + other.min,
165            max: self.max + other.max,
166        }
167    }
168}
169
170impl AddAssign for DensityRange {
171    fn add_assign(&mut self, other: Self) {
172        self.min += other.min;
173        self.max += other.max;
174    }
175}
176
177impl Sub for DensityRange {
178    type Output = Self;
179
180    fn sub(self, other: Self) -> Self::Output {
181        Self {
182            min: self.min - other.min,
183            max: self.max - other.max,
184        }
185    }
186}
187
188impl SubAssign for DensityRange {
189    fn sub_assign(&mut self, other: Self) {
190        self.min -= other.min;
191        self.max -= other.max;
192    }
193}
194
195impl Mul for DensityRange {
196    type Output = Self;
197
198    fn mul(self, other: Self) -> Self::Output {
199        Self {
200            min: self.min * other.min,
201            max: self.max * other.max,
202        }
203    }
204}
205
206impl MulAssign for DensityRange {
207    fn mul_assign(&mut self, other: Self) {
208        self.min *= other.min;
209        self.max *= other.max;
210    }
211}
212
213impl Mul<Scalar> for DensityRange {
214    type Output = Self;
215
216    fn mul(self, scalar: Scalar) -> Self::Output {
217        Self {
218            min: self.min * scalar,
219            max: self.max * scalar,
220        }
221    }
222}
223
224impl MulAssign<Scalar> for DensityRange {
225    fn mul_assign(&mut self, scalar: Scalar) {
226        self.min *= scalar;
227        self.max *= scalar;
228    }
229}
230
231impl Div for DensityRange {
232    type Output = Self;
233
234    fn div(self, other: Self) -> Self::Output {
235        Self {
236            min: self.min / other.min,
237            max: self.max / other.max,
238        }
239    }
240}
241
242impl DivAssign for DensityRange {
243    fn div_assign(&mut self, other: Self) {
244        self.min /= other.min;
245        self.max /= other.max;
246    }
247}
248
249impl Div<Scalar> for DensityRange {
250    type Output = Self;
251
252    fn div(self, scalar: Scalar) -> Self::Output {
253        Self {
254            min: self.min / scalar,
255            max: self.max / scalar,
256        }
257    }
258}
259
260impl DivAssign<Scalar> for DensityRange {
261    fn div_assign(&mut self, scalar: Scalar) {
262        self.min /= scalar;
263        self.max /= scalar;
264    }
265}