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}