layers/roughness.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief `RoughnessLayer`, fine self-affine roughness from octaves of Perlin noise. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/layers/fade.h" | ||
| 6 | #include "terraingen/layers/layer.h" | ||
| 7 | #include "terraingen/util/surface.h" | ||
| 8 | |||
| 9 | #include <array> | ||
| 10 | #include <cstdint> | ||
| 11 | #include <vector> | ||
| 12 | |||
| 13 | namespace terraingen { | ||
| 14 | |||
| 15 | /// The roughness a `RoughnessLayer` adds: RMS slope over a baseline and Hurst exponent, as | ||
| 16 | /// Shepard et al. (2001) give it. | ||
| 17 | struct RoughnessOptions { | ||
| 18 | 4 | double rmsSlope = 0.15; ///< RMS slope (rise over run) over `baseline`. | |
| 19 | 4 | double baseline = 0.25; ///< Baseline the RMS slope is given over (m). | |
| 20 | 4 | double hurst = 0.8; ///< Hurst exponent, in (0, 1]. | |
| 21 | 4 | double maxWavelength = 4.0; ///< Longest octave (m). | |
| 22 | 4 | double minWavelength = 0.01; ///< Shortest octave (m); octaves halve down to it. | |
| 23 | 4 | std::uint32_t seed = 1; ///< Varies the octaves' offsets and rotations. | |
| 24 | /// How octaves too fine to resolve fade out, by samples per wavelength. | ||
| 25 | 4 | ResolutionFade fade{}; | |
| 26 | |||
| 27 | 4 | bool operator==(const RoughnessOptions&) const = default; | |
| 28 | }; | ||
| 29 | |||
| 30 | /// Checks roughness options. | ||
| 31 | /// @throws std::invalid_argument for a non-positive `rmsSlope` or `baseline`, a `hurst` outside | ||
| 32 | /// (0, 1], wavelengths that do not satisfy 0 < `minWavelength` <= `maxWavelength` or that span more | ||
| 33 | /// than 40 octaves, or an invalid `fade`. | ||
| 34 | void ValidateRoughnessOptions(const RoughnessOptions& options); | ||
| 35 | |||
| 36 | /// The structure function of `PerlinNoise2`: mean squared difference of values a lag `r` apart | ||
| 37 | /// (lattice units), over positions, directions and seeds; 0 for `r` <= 0. | ||
| 38 | double PerlinStructureFunction(double r); | ||
| 39 | |||
| 40 | /// The structure function of `PerlinNoise3` at a lag `r` (lattice units) in a random 3D | ||
| 41 | /// direction; 0 for `r` <= 0. | ||
| 42 | double Perlin3StructureFunction(double r); | ||
| 43 | |||
| 44 | /// Fine roughness: octaves of Perlin noise halving in wavelength from `maxWavelength` to | ||
| 45 | /// `minWavelength`, amplitudes growing as wavelength^H. | ||
| 46 | /// | ||
| 47 | /// Amplitudes are scaled so the RMS slope over `baseline` is `rmsSlope` with every octave | ||
| 48 | /// resolved. Octaves are rotated and offset so their lattices do not line up, and fade out at | ||
| 49 | /// spacings too coarse to resolve them. | ||
| 50 | class RoughnessLayer final : public FormulaLayer { | ||
| 51 | public: | ||
| 52 | /// On a sphere each octave is 3D Perlin noise at the 3D point, its lattice turned by a uniform | ||
| 53 | /// random rotation. | ||
| 54 | /// @throws std::invalid_argument as `ValidateRoughnessOptions`. | ||
| 55 | explicit RoughnessLayer(RoughnessOptions options, Surface surface = {}); | ||
| 56 | |||
| 57 | /// The RMS slope (rise over run) over `baseline` metres with every octave resolved. | ||
| 58 | double RmsSlope(double baseline) const; | ||
| 59 | |||
| 60 | /// The octaves' wavelengths in metres, longest first. | ||
| 61 | std::vector<double> Wavelengths() const; | ||
| 62 | |||
| 63 | /// The options the layer was made with. | ||
| 64 | const RoughnessOptions& Options() const { | ||
| 65 | return options_; | ||
| 66 | } | ||
| 67 | |||
| 68 | protected: | ||
| 69 | float HeightAt(float height, double x, double y, double spacing, | ||
| 70 | const Ground* ground) const override; | ||
| 71 | |||
| 72 | private: | ||
| 73 | struct Octave { | ||
| 74 | double wavelength; | ||
| 75 | double amplitude; | ||
| 76 | double cos; | ||
| 77 | double sin; | ||
| 78 | double offsetX; | ||
| 79 | double offsetY; | ||
| 80 | std::uint32_t seed; | ||
| 81 | std::array<double, 9> rotation{}; | ||
| 82 | double offsetZ = 0.0; | ||
| 83 | }; | ||
| 84 | |||
| 85 | /// Octave `i` of `wavelength`, before its amplitude is scaled to the RMS slope. | ||
| 86 | Octave MakeOctave(std::uint32_t i, double wavelength) const; | ||
| 87 | /// The noise of one octave at (`x`, `y`), in [-1, 1]. | ||
| 88 | double OctaveNoise(const Octave& octave, double x, double y) const; | ||
| 89 | |||
| 90 | RoughnessOptions options_; | ||
| 91 | std::vector<Octave> octaves_; | ||
| 92 | }; | ||
| 93 | |||
| 94 | } // namespace terraingen | ||
| 95 |