isosurface/
source.rs

1// Copyright 2018 Tristam MacDonald
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use math::Vec3;
16
17/// A source capable of sampling a signed distance field at discrete coordinates.
18pub trait Source {
19    /// Samples the distance field at the given (x, y, z) coordinates.
20    ///
21    /// Must return the signed distance (i.e. negative for coodinates inside the surface),
22    /// as our Marching Cubes implementation will evaluate the surface at the zero-crossing.
23    fn sample(&self, x: f32, y: f32, z: f32) -> f32;
24}
25
26/// A source capable of evaluating the normal vector to a signed distance field at discrete coordinates.
27pub trait HermiteSource: Source {
28    /// Samples the distance field at the given (x, y, z) coordinates.
29    ///
30    /// Must return a normal vector to the surface.
31    fn sample_normal(&self, x: f32, y: f32, z: f32) -> Vec3;
32}
33
34/// Adapts a Source to a HermiteSource by deriving normals from the surface via central differencing
35pub struct CentralDifference {
36    source: Box<Source>,
37    epsilon: f32,
38}
39
40impl CentralDifference {
41    /// Create an adaptor from a [Source](trait.Source.html)
42    pub fn new(source: Box<Source>) -> CentralDifference {
43        CentralDifference {
44            source,
45            epsilon: 0.0001,
46        }
47    }
48
49    /// Create an adaptor from a [Source](trait.Source.html) and an epsilon value
50    pub fn new_with_epsilon(source: Box<Source>, epsilon: f32) -> CentralDifference {
51        CentralDifference { source, epsilon }
52    }
53}
54
55impl Source for CentralDifference {
56    fn sample(&self, x: f32, y: f32, z: f32) -> f32 {
57        self.source.sample(x, y, z)
58    }
59}
60
61impl HermiteSource for CentralDifference {
62    fn sample_normal(&self, x: f32, y: f32, z: f32) -> Vec3 {
63        let v = self.sample(x, y, z);
64        let vx = self.sample(x + self.epsilon, y, z);
65        let vy = self.sample(x, y + self.epsilon, z);
66        let vz = self.sample(x, y, z + self.epsilon);
67
68        Vec3::new(vx - v, vy - v, vz - v)
69    }
70}