noise/noise_fns/generators/fractals/
basicmulti.rs

1use crate::{
2    math::vectors::*,
3    noise_fns::{MultiFractal, NoiseFn, Seedable},
4};
5use alloc::vec::Vec;
6
7#[cfg(not(feature = "std"))]
8use num_traits::float::FloatCore;
9
10/// Noise function that outputs heterogenous Multifractal noise.
11///
12/// This is a multifractal method, meaning that it has a fractal dimension
13/// that varies with location.
14///
15/// The result of this multifractal method is that in areas near zero, higher
16/// frequencies will be heavily damped, resulting in the terrain remaining
17/// smooth. As the value moves further away from zero, higher frequencies will
18/// not be as damped and thus will grow more jagged as iteration progresses.
19///
20#[derive(Clone, Debug)]
21pub struct BasicMulti<T> {
22    /// Total number of frequency octaves to generate the noise with.
23    ///
24    /// The number of octaves control the _amount of detail_ in the noise
25    /// function. Adding more octaves increases the detail, with the drawback
26    /// of increasing the calculation time.
27    pub octaves: usize,
28
29    /// The number of cycles per unit length that the noise function outputs.
30    pub frequency: f64,
31
32    /// A multiplier that determines how quickly the frequency increases for
33    /// each successive octave in the noise function.
34    ///
35    /// The frequency of each successive octave is equal to the product of the
36    /// previous octave's frequency and the lacunarity value.
37    ///
38    /// A lacunarity of 2.0 results in the frequency doubling every octave. For
39    /// almost all cases, 2.0 is a good value to use.
40    pub lacunarity: f64,
41
42    /// A multiplier that determines how quickly the amplitudes diminish for
43    /// each successive octave in the noise function.
44    ///
45    /// The amplitude of each successive octave is equal to the product of the
46    /// previous octave's amplitude and the persistence value. Increasing the
47    /// persistence produces "rougher" noise.
48    pub persistence: f64,
49
50    seed: u32,
51    sources: Vec<T>,
52    scale_factor: f64,
53}
54
55impl<T> BasicMulti<T>
56where
57    T: Default + Seedable,
58{
59    pub const DEFAULT_SEED: u32 = 0;
60    pub const DEFAULT_OCTAVES: usize = 6;
61    pub const DEFAULT_FREQUENCY: f64 = 2.0;
62    pub const DEFAULT_LACUNARITY: f64 = core::f64::consts::PI * 2.0 / 3.0;
63    pub const DEFAULT_PERSISTENCE: f64 = 0.5;
64    pub const MAX_OCTAVES: usize = 32;
65
66    pub fn new(seed: u32) -> Self {
67        Self {
68            seed,
69            octaves: Self::DEFAULT_OCTAVES,
70            frequency: Self::DEFAULT_FREQUENCY,
71            lacunarity: Self::DEFAULT_LACUNARITY,
72            persistence: Self::DEFAULT_PERSISTENCE,
73            sources: super::build_sources(seed, Self::DEFAULT_OCTAVES),
74            scale_factor: Self::calc_scale_factor(Self::DEFAULT_PERSISTENCE, Self::DEFAULT_OCTAVES),
75        }
76    }
77
78    pub fn set_sources(self, sources: Vec<T>) -> Self {
79        Self { sources, ..self }
80    }
81
82    fn calc_scale_factor(persistence: f64, octaves: usize) -> f64 {
83        let denom = if octaves == 1 {
84            1.0
85        } else {
86            (1..=octaves).fold(1.0, |acc, x| acc + (acc * persistence.powi(x as i32)))
87        };
88
89        1.0 / denom
90    }
91}
92
93impl<T> Default for BasicMulti<T>
94where
95    T: Default + Seedable,
96{
97    fn default() -> Self {
98        Self::new(Self::DEFAULT_SEED)
99    }
100}
101
102impl<T> MultiFractal for BasicMulti<T>
103where
104    T: Default + Seedable,
105{
106    fn set_octaves(self, mut octaves: usize) -> Self {
107        if self.octaves == octaves {
108            return self;
109        }
110
111        octaves = octaves.clamp(1, Self::MAX_OCTAVES);
112        Self {
113            octaves,
114            sources: super::build_sources(self.seed, octaves),
115            scale_factor: Self::calc_scale_factor(self.persistence, octaves),
116            ..self
117        }
118    }
119
120    fn set_frequency(self, frequency: f64) -> Self {
121        Self { frequency, ..self }
122    }
123
124    fn set_lacunarity(self, lacunarity: f64) -> Self {
125        Self { lacunarity, ..self }
126    }
127
128    fn set_persistence(self, persistence: f64) -> Self {
129        Self {
130            persistence,
131            scale_factor: Self::calc_scale_factor(persistence, self.octaves),
132            ..self
133        }
134    }
135}
136
137impl<T> Seedable for BasicMulti<T>
138where
139    T: Default + Seedable,
140{
141    fn set_seed(self, seed: u32) -> Self {
142        if self.seed == seed {
143            return self;
144        }
145
146        Self {
147            seed,
148            sources: super::build_sources(seed, self.octaves),
149            ..self
150        }
151    }
152
153    fn seed(&self) -> u32 {
154        self.seed
155    }
156}
157
158/// 2-dimensional `BasicMulti` noise
159impl<T> NoiseFn<f64, 2> for BasicMulti<T>
160where
161    T: NoiseFn<f64, 2>,
162{
163    fn get(&self, point: [f64; 2]) -> f64 {
164        let mut point = Vector2::from(point);
165
166        // First unscaled octave of function; later octaves are scaled.
167        point *= self.frequency;
168        let mut result = self.sources[0].get(point.into_array());
169
170        // if only 1 octave of noise, then return result unchanged, otherwise process another octave
171        if self.octaves > 1 {
172            let mut attenuation = self.persistence;
173            // Spectral construction inner loop, where the fractal is built.
174            for x in 1..self.octaves {
175                // Raise the spatial frequency.
176                point *= self.lacunarity;
177
178                // Get noise value.
179                let mut signal = self.sources[x].get(point.into_array());
180
181                // Scale the amplitude appropriately for this frequency.
182                signal *= attenuation;
183
184                // Increase the attenuation for the next octave, to be equal to persistence ^ (x + 1)
185                attenuation *= self.persistence;
186
187                // Scale the signal by the current 'altitude' of the function.
188                signal *= result;
189
190                // Add signal to result.
191                result += signal;
192            }
193        }
194
195        // Scale the result to the [-1,1] range.
196        result * self.scale_factor
197    }
198}
199
200/// 3-dimensional `BasicMulti` noise
201impl<T> NoiseFn<f64, 3> for BasicMulti<T>
202where
203    T: NoiseFn<f64, 3>,
204{
205    fn get(&self, point: [f64; 3]) -> f64 {
206        let mut point = Vector3::from(point);
207
208        // First unscaled octave of function; later octaves are scaled.
209        point *= self.frequency;
210        let mut result = self.sources[0].get(point.into_array());
211
212        // if only 1 octave of noise, then return result unchanged, otherwise process another octave
213        if self.octaves > 1 {
214            let mut attenuation = self.persistence;
215            // Spectral construction inner loop, where the fractal is built.
216            for x in 1..self.octaves {
217                // Raise the spatial frequency.
218                point *= self.lacunarity;
219
220                // Get noise value.
221                let mut signal = self.sources[x].get(point.into_array());
222
223                // Scale the amplitude appropriately for this frequency.
224                signal *= attenuation;
225
226                // Increase the attenuation for the next octave, to be equal to persistence ^ (x + 1)
227                attenuation *= self.persistence;
228
229                // Scale the signal by the current 'altitude' of the function.
230                signal *= result;
231
232                // Add signal to result.
233                result += signal;
234            }
235        }
236
237        // Scale the result to the [-1,1] range.
238        result * self.scale_factor
239    }
240}
241
242/// 4-dimensional `BasicMulti` noise
243impl<T> NoiseFn<f64, 4> for BasicMulti<T>
244where
245    T: NoiseFn<f64, 4>,
246{
247    fn get(&self, point: [f64; 4]) -> f64 {
248        let mut point = Vector4::from(point);
249
250        // First unscaled octave of function; later octaves are scaled.
251        point *= self.frequency;
252        let mut result = self.sources[0].get(point.into_array());
253
254        // if only 1 octave of noise, then return result unchanged, otherwise process another octave
255        if self.octaves > 1 {
256            let mut attenuation = self.persistence;
257            // Spectral construction inner loop, where the fractal is built.
258            for x in 1..self.octaves {
259                // Raise the spatial frequency.
260                point *= self.lacunarity;
261
262                // Get noise value.
263                let mut signal = self.sources[x].get(point.into_array());
264
265                // Scale the amplitude appropriately for this frequency.
266                signal *= attenuation;
267
268                // Increase the attenuation for the next octave, to be equal to persistence ^ (x + 1)
269                attenuation *= self.persistence;
270
271                // Scale the signal by the current 'altitude' of the function.
272                signal *= result;
273
274                // Add signal to result.
275                result += signal;
276            }
277        }
278
279        // Scale the result to the [-1,1] range.
280        result * self.scale_factor
281    }
282}