anput_physics/density_fields/
mod.rs

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