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}