noise/noise_fns/generators/fractals/
billow.rs

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