vox_geometry_rust/
custom_implicit_surface3.rs

1/*
2 * // Copyright (c) 2021 Feng Yang
3 * //
4 * // I am making my contributions/submissions to this project solely in my
5 * // personal capacity and am not conveying any rights to any intellectual
6 * // property of any third parties.
7 */
8
9use crate::transform3::Transform3;
10use crate::vector3::Vector3D;
11use crate::bounding_box3::BoundingBox3D;
12use crate::ray3::Ray3D;
13use crate::surface3::*;
14use crate::implicit_surface3::ImplicitSurface3;
15use std::sync::{RwLock, Arc};
16
17/// # Custom 3-D implicit surface using arbitrary function.
18pub struct CustomImplicitSurface3 {
19    _func: fn(&Vector3D) -> f64,
20    _domain: BoundingBox3D,
21    _resolution: f64,
22    _ray_marching_resolution: f64,
23    _max_num_of_iterations: usize,
24
25    /// data from surface3
26    pub surface_data: Surface3Data,
27}
28
29impl CustomImplicitSurface3 {
30    ///
31    /// Constructs an implicit surface using the given signed-distance function.
32    ///
33    /// - parameter: func Custom SDF function object.
34    /// - parameter: domain Bounding box of the SDF if exists.
35    /// - parameter: resolution Finite differencing resolution for derivatives.
36    /// - parameter: ray_marching_resolution Ray marching resolution for ray tests.
37    /// - parameter: maxNumOfIterations Number of iterations for closest point search.
38    /// - parameter: transform Local-to-world transform.
39    /// - parameter: is_normal_flipped True if normal is flipped.
40    ///
41    pub fn new(func: fn(&Vector3D) -> f64,
42               domain: Option<BoundingBox3D>,
43               resolution: Option<f64>,
44               ray_marching_resolution: Option<f64>,
45               number_of_iterations: Option<usize>,
46               transform: Option<Transform3>,
47               is_normal_flipped: Option<bool>) -> CustomImplicitSurface3 {
48        return CustomImplicitSurface3 {
49            _func: func,
50            _domain: domain.unwrap_or(BoundingBox3D::new_default()),
51            _resolution: resolution.unwrap_or(1.0e-3),
52            _ray_marching_resolution: ray_marching_resolution.unwrap_or(1.0e-6),
53            _max_num_of_iterations: number_of_iterations.unwrap_or(5),
54            surface_data: Surface3Data::new(transform, is_normal_flipped),
55        };
56    }
57
58    /// Returns builder fox CustomImplicitSurface3.
59    pub fn builder() -> Builder {
60        return Builder::new();
61    }
62
63    pub fn gradient_local(&self, x: &Vector3D) -> Vector3D {
64        let left = (self._func)(&(*x - Vector3D::new(0.5 * self._resolution, 0.0, 0.0)));
65        let right = (self._func)(&(*x + Vector3D::new(0.5 * self._resolution, 0.0, 0.0)));
66        let bottom = (self._func)(&(*x - Vector3D::new(0.0, 0.5 * self._resolution, 0.0)));
67        let top = (self._func)(&(*x + Vector3D::new(0.0, 0.5 * self._resolution, 0.0)));
68        let back = (self._func)(&(*x - Vector3D::new(0.0, 0.0, 0.5 * self._resolution)));
69        let front = (self._func)(&(*x + Vector3D::new(0.0, 0.0, 0.5 * self._resolution)));
70
71        return Vector3D::new((right - left) / self._resolution, (top - bottom) / self._resolution,
72                             (front - back) / self._resolution);
73    }
74}
75
76impl Surface3 for CustomImplicitSurface3 {
77    fn closest_point_local(&self, other_point: &Vector3D) -> Vector3D {
78        let mut pt = crate::vector3::clamp(other_point, &self._domain.lower_corner, &self._domain.upper_corner);
79        for _ in 0..self._max_num_of_iterations {
80            let sdf = self.signed_distance_local(&pt);
81            if f64::abs(sdf) < f64::EPSILON {
82                break;
83            }
84            let g = self.gradient_local(&pt);
85            pt = pt - g * sdf;
86        }
87        return pt;
88    }
89    fn bounding_box_local(&self) -> BoundingBox3D {
90        return self._domain.clone();
91    }
92
93    fn closest_intersection_local(&self, ray: &Ray3D) -> SurfaceRayIntersection3 {
94        let mut result = SurfaceRayIntersection3::new();
95
96        let intersection = self._domain.closest_intersection(ray);
97
98        if intersection.is_intersecting {
99            let t_start;
100            let t_end;
101            if intersection.t_far == f64::MAX {
102                t_start = 0.0;
103                t_end = intersection.t_near;
104            } else {
105                t_start = intersection.t_near;
106                t_end = intersection.t_far;
107            }
108
109            let mut t = t_start;
110            let mut t_prev = t;
111            let mut pt = ray.point_at(t);
112            let mut prev_phi = (self._func)(&pt);
113
114            while t <= t_end {
115                pt = ray.point_at(t);
116                let new_phi = (self._func)(&pt);
117                let new_phi_abs = f64::abs(new_phi);
118
119                if new_phi * prev_phi < 0.0 {
120                    let frac = prev_phi / (prev_phi - new_phi);
121                    let t_sub = t_prev + self._ray_marching_resolution * frac;
122
123                    result.is_intersecting = true;
124                    result.distance = t_sub;
125                    result.point = ray.point_at(t_sub);
126                    result.normal = self.gradient_local(&result.point);
127                    if result.normal.length() > 0.0 {
128                        result.normal.normalize();
129                    }
130
131                    return result;
132                }
133
134                t_prev = t;
135                t += f64::max(new_phi_abs, self._ray_marching_resolution);
136                prev_phi = new_phi;
137            }
138        }
139
140        return result;
141    }
142
143    fn closest_normal_local(&self, other_point: &Vector3D) -> Vector3D {
144        let pt = self.closest_point_local(other_point);
145        let g = self.gradient_local(&pt);
146        return if g.length_squared() > 0.0 {
147            g.normalized()
148        } else {
149            g
150        };
151    }
152
153    fn intersects_local(&self, ray: &Ray3D) -> bool {
154        let intersection = self._domain.closest_intersection(ray);
155
156        if intersection.is_intersecting {
157            let t_start;
158            let t_end;
159            if intersection.t_far == f64::MAX {
160                t_start = 0.0;
161                t_end = intersection.t_near;
162            } else {
163                t_start = intersection.t_near;
164                t_end = intersection.t_far;
165            }
166
167            let mut t = t_start;
168            let mut pt = ray.point_at(t);
169            let mut prev_phi = (self._func)(&pt);
170            while t <= t_end {
171                pt = ray.point_at(t);
172                let new_phi = (self._func)(&pt);
173                let new_phi_abs = f64::abs(new_phi);
174
175                if new_phi * prev_phi < 0.0 {
176                    return true;
177                }
178
179                t += f64::max(new_phi_abs, self._ray_marching_resolution);
180                prev_phi = new_phi;
181            }
182        }
183
184        return false;
185    }
186
187    fn view(&self) -> &Surface3Data {
188        return &self.surface_data;
189    }
190}
191
192impl ImplicitSurface3 for CustomImplicitSurface3 {
193    fn signed_distance_local(&self, other_point: &Vector3D) -> f64 {
194        return (self._func)(other_point);
195    }
196}
197
198/// Shared pointer type for the CustomImplicitSurface3.
199pub type CustomImplicitSurface3Ptr = Arc<RwLock<CustomImplicitSurface3>>;
200
201///
202/// # Front-end to create CustomImplicitSurface3 objects step by step.
203///
204pub struct Builder {
205    _func: Option<fn(&Vector3D) -> f64>,
206    _domain: BoundingBox3D,
207    _resolution: f64,
208    _ray_marching_resolution: f64,
209    _max_num_of_iterations: usize,
210
211    _surface_data: Surface3Data,
212}
213
214impl Builder {
215    /// Returns builder with custom signed-distance function
216    pub fn with_signed_distance_function(&mut self, func: fn(&Vector3D) -> f64) -> &mut Self {
217        self._func = Some(func);
218        return self;
219    }
220
221    /// Returns builder with domain.
222    pub fn with_domain(&mut self, domain: BoundingBox3D) -> &mut Self {
223        self._domain = domain;
224        return self;
225    }
226
227    /// Returns builder with finite differencing resolution.
228    pub fn with_resolution(&mut self, resolution: f64) -> &mut Self {
229        self._resolution = resolution;
230        return self;
231    }
232
233    /// Returns builder with ray marching resolution which determines the ray
234    /// intersection quality.
235    pub fn with_ray_marching_resolution(&mut self, ray_marching_resolution: f64) -> &mut Self {
236        self._ray_marching_resolution = ray_marching_resolution;
237        return self;
238    }
239
240    /// Returns builder with number of iterations for closest point/normal
241    /// searches.
242    pub fn with_max_number_of_iterations(&mut self, num_iter: usize) -> &mut Self {
243        self._max_num_of_iterations = num_iter;
244        return self;
245    }
246
247    /// Builds CustomImplicitSurface3.
248    pub fn build(&mut self) -> CustomImplicitSurface3 {
249        return CustomImplicitSurface3::new(self._func.unwrap(),
250                                           Some(self._domain.clone()),
251                                           Some(self._resolution),
252                                           Some(self._ray_marching_resolution),
253                                           Some(self._max_num_of_iterations),
254                                           Some(self._surface_data.transform.clone()),
255                                           Some(self._surface_data.is_normal_flipped));
256    }
257
258    /// Builds shared pointer of CustomImplicitSurface3 instance.
259    pub fn make_shared(&mut self) -> CustomImplicitSurface3Ptr {
260        return CustomImplicitSurface3Ptr::new(RwLock::new(self.build()));
261    }
262
263    /// constructor
264    pub fn new() -> Builder {
265        return Builder {
266            _func: None,
267            _domain: BoundingBox3D::new_default(),
268            _resolution: 1.0e-3,
269            _ray_marching_resolution: 1.0e-6,
270            _max_num_of_iterations: 5,
271            _surface_data: Surface3Data::new(None, None),
272        };
273    }
274}
275
276impl SurfaceBuilderBase3 for Builder {
277    fn view(&mut self) -> &mut Surface3Data {
278        return &mut self._surface_data;
279    }
280}