├── .github └── FUNDING.yml ├── images ├── top.png ├── f8o3_23456.png ├── f8o8_12345.png └── f8o8_23456.png ├── Makefile ├── LICENSE ├── README.md ├── example.cpp └── PerlinNoise.hpp /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: Reputeless 2 | -------------------------------------------------------------------------------- /images/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reputeless/PerlinNoise/HEAD/images/top.png -------------------------------------------------------------------------------- /images/f8o3_23456.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reputeless/PerlinNoise/HEAD/images/f8o3_23456.png -------------------------------------------------------------------------------- /images/f8o8_12345.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reputeless/PerlinNoise/HEAD/images/f8o8_12345.png -------------------------------------------------------------------------------- /images/f8o8_23456.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reputeless/PerlinNoise/HEAD/images/f8o8_23456.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=clang 2 | 3 | .PHONY: clean 4 | 5 | example: example.cpp 6 | $(CC) -std=c++17 $^ -o $@ -lm -lstdc++ 7 | 8 | clean: 9 | rm -rf example 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-2020 Ryo Suzuki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # siv::PerlinNoise 2 | ![noise](images/top.png) 3 | 4 | **siv::PerlinNoise** is a header-only Perlin noise library for modern C++ (C++17/20). 5 | The implementation is based on Ken Perlin's [Improved Noise](https://cs.nyu.edu/~perlin/noise/). 6 | 7 | ## Features 8 | * 1D / 2D / 3D noise 9 | * octave noise 10 | * initial seed 11 | * *(✨ new in v3.0)* produce the same output on any platform (except for floating point errors) 12 | 13 | ## License 14 | siv::PerlinNoise is distributed under the **MIT license**. 15 | 16 | ## Usage 17 | 18 | ```cpp 19 | # include 20 | # include "PerlinNoise.hpp" 21 | 22 | int main() 23 | { 24 | const siv::PerlinNoise::seed_type seed = 123456u; 25 | 26 | const siv::PerlinNoise perlin{ seed }; 27 | 28 | for (int y = 0; y < 5; ++y) 29 | { 30 | for (int x = 0; x < 5; ++x) 31 | { 32 | const double noise = perlin.octave2D_01((x * 0.01), (y * 0.01), 4); 33 | 34 | std::cout << noise << '\t'; 35 | } 36 | 37 | std::cout << '\n'; 38 | } 39 | } 40 | ``` 41 | 42 | ## API 43 | 44 | ### `template class BasicPerlinNoise` 45 | 46 | - Typedefs 47 | - `using PerlinNoise = BasicPerlinNoise;` 48 | - `using state_type = std::array;` 49 | - `using value_type = Float;` 50 | - `using default_random_engine = std::mt19937;` 51 | - `using seed_type = typename default_random_engine::result_type;` 52 | - Constructors 53 | - `constexpr BasicPerlinNoise();` 54 | - `BasicPerlinNoise(seed_type seed);` 55 | - `BasicPerlinNoise(URBG&& urbg);` 56 | - Reseed 57 | - `void reseed(seed_type seed);` 58 | - `void reseed(URBG&& urbg);` 59 | - Serialization 60 | - `constexpr const state_type& serialize() const noexcept;` 61 | - `constexpr void deserialize(const state_type& state) noexcept;` 62 | - Noise (The result is **in the range [-1, 1]**) 63 | - `value_type noise1D(value_type x) const noexcept;` 64 | - `value_type noise2D(value_type x, value_type y) const noexcept;` 65 | - `value_type noise3D(value_type x, value_type y, value_type z) const noexcept;` 66 | - Noise (The result is **remapped to the range [0, 1]**) 67 | - `value_type noise1D_01(value_type x) const noexcept;` 68 | - `value_type noise2D_01(value_type x, value_type y) const noexcept;` 69 | - `value_type noise3D_01(value_type x, value_type y, value_type z) const noexcept;` 70 | - Octave noise (The result **can be out of the range [-1, 1]**) 71 | - `value_type octave1D(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 72 | - `value_type octave2D(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 73 | - `value_type octave3D(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 74 | - Octave noise (The result is **clamped to the range [-1, 1]**) 75 | - `value_type octave1D_11(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 76 | - `value_type octave2D_11(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 77 | - `value_type octave3D_11(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 78 | - Octave noise (The result is **clamped and remapped to the range [0, 1]**) 79 | - `value_type octave1D_01(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 80 | - `value_type octave2D_01(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 81 | - `value_type octave3D_01(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 82 | - Octave noise (The result is **normalized to the range [-1, 1]**) 83 | - `value_type normalizedOctave1D(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 84 | - `value_type normalizedOctave2D(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 85 | - `value_type normalizedOctave3D(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 86 | - Octave noise (The result is **normalized and remapped to the range [0, 1]**) 87 | - `value_type normalizedOctave1D_01(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 88 | - `value_type normalizedOctave2D_01(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 89 | - `value_type normalizedOctave3D_01(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;` 90 | 91 | ## Example 92 | Run example.cpp with the following parameters. 93 | 94 | ``` 95 | frequency = 8.0 96 | octaves = 8 97 | seed = 12345 98 | ``` 99 | 100 | ![noise](images/f8o8_12345.png) 101 | 102 | --- 103 | 104 | ``` 105 | frequency = 8.0 106 | octaves = 8 107 | seed = 23456 108 | ``` 109 | 110 | ![noise](images/f8o8_23456.png) 111 | 112 | --- 113 | 114 | ``` 115 | frequency = 8.0 116 | octaves = 3 117 | seed = 23456 118 | ``` 119 | 120 | ![noise](images/f8o3_23456.png) 121 | -------------------------------------------------------------------------------- /example.cpp: -------------------------------------------------------------------------------- 1 | # include 2 | # include 3 | # include 4 | # include 5 | # include "PerlinNoise.hpp" 6 | 7 | # pragma pack (push, 1) 8 | struct BMPHeader 9 | { 10 | std::uint16_t bfType; 11 | std::uint32_t bfSize; 12 | std::uint16_t bfReserved1; 13 | std::uint16_t bfReserved2; 14 | std::uint32_t bfOffBits; 15 | std::uint32_t biSize; 16 | std::int32_t biWidth; 17 | std::int32_t biHeight; 18 | std::uint16_t biPlanes; 19 | std::uint16_t biBitCount; 20 | std::uint32_t biCompression; 21 | std::uint32_t biSizeImage; 22 | std::int32_t biXPelsPerMeter; 23 | std::int32_t biYPelsPerMeter; 24 | std::uint32_t biClrUsed; 25 | std::uint32_t biClrImportant; 26 | }; 27 | static_assert(sizeof(BMPHeader) == 54); 28 | # pragma pack (pop) 29 | 30 | struct RGB 31 | { 32 | double r = 0.0; 33 | double g = 0.0; 34 | double b = 0.0; 35 | constexpr RGB() = default; 36 | explicit constexpr RGB(double _rgb) noexcept 37 | : r{ _rgb }, g{ _rgb }, b{ _rgb } {} 38 | constexpr RGB(double _r, double _g, double _b) noexcept 39 | : r{ _r }, g{ _g }, b{ _b } {} 40 | }; 41 | 42 | class Image 43 | { 44 | public: 45 | 46 | Image() = default; 47 | 48 | Image(std::size_t width, std::size_t height) 49 | : m_data(width* height) 50 | , m_width{ static_cast(width) } 51 | , m_height{ static_cast(height) } {} 52 | 53 | void set(std::int32_t x, std::int32_t y, const RGB& color) 54 | { 55 | if (not inBounds(y, x)) 56 | { 57 | return; 58 | } 59 | 60 | m_data[static_cast(y) * m_width + x] = color; 61 | } 62 | 63 | std::int32_t width() const noexcept { return m_width; } 64 | 65 | std::int32_t height() const noexcept { return m_height; } 66 | 67 | bool saveBMP(const std::string& path) 68 | { 69 | const std::int32_t rowSize = m_width * 3 + m_width % 4; 70 | const std::uint32_t bmpsize = rowSize * m_height; 71 | const BMPHeader header = 72 | { 73 | 0x4d42, 74 | static_cast(bmpsize + sizeof(BMPHeader)), 75 | 0, 0, sizeof(BMPHeader), 40, 76 | m_width, m_height, 1, 24, 77 | 0, bmpsize, 0, 0, 0, 0 78 | }; 79 | 80 | if (std::ofstream ofs{ path, std::ios_base::binary }) 81 | { 82 | ofs.write(reinterpret_cast(&header), sizeof(header)); 83 | 84 | std::vector line(rowSize); 85 | 86 | for (std::int32_t y = m_height - 1; -1 < y; --y) 87 | { 88 | size_t pos = 0; 89 | 90 | for (std::int32_t x = 0; x < m_width; ++x) 91 | { 92 | const RGB& col = m_data[static_cast(y) * m_width + x]; 93 | line[pos++] = ToUint8(col.b); 94 | line[pos++] = ToUint8(col.g); 95 | line[pos++] = ToUint8(col.r); 96 | } 97 | 98 | ofs.write(reinterpret_cast(line.data()), line.size()); 99 | } 100 | 101 | return true; 102 | } 103 | else 104 | { 105 | return false; 106 | } 107 | } 108 | 109 | private: 110 | 111 | std::vector m_data; 112 | 113 | std::int32_t m_width = 0, m_height = 0; 114 | 115 | bool inBounds(std::int32_t y, std::int32_t x) const noexcept 116 | { 117 | return (0 <= y) && (y < m_height) && (0 <= x) && (x < m_width); 118 | } 119 | 120 | static constexpr std::uint8_t ToUint8(double x) noexcept 121 | { 122 | return (x <= 0.0) ? 0 : (1.0 <= x) ? 255 : static_cast(x * 255.0 + 0.5); 123 | } 124 | }; 125 | 126 | void Test() 127 | { 128 | siv::PerlinNoise perlinA{ std::random_device{} }; 129 | siv::PerlinNoise perlinB; 130 | 131 | perlinB.deserialize(perlinA.serialize()); 132 | 133 | assert(perlinA.octave3D(0.1, 0.2, 0.3, 4) 134 | == perlinB.octave3D(0.1, 0.2, 0.3, 4)); 135 | 136 | perlinA.reseed(12345u); 137 | perlinB.reseed(12345u); 138 | 139 | assert(perlinA.octave3D(0.1, 0.2, 0.3, 4) 140 | == perlinB.octave3D(0.1, 0.2, 0.3, 4)); 141 | 142 | perlinA.reseed(std::mt19937{ 67890u }); 143 | perlinB.reseed(std::mt19937{ 67890u }); 144 | 145 | assert(perlinA.octave3D(0.1, 0.2, 0.3, 4) 146 | == perlinB.octave3D(0.1, 0.2, 0.3, 4)); 147 | 148 | for (std::int32_t y = 0; y < 20; ++y) 149 | { 150 | for (std::int32_t x = 0; x < 20; ++x) 151 | { 152 | const double noise = perlinA.octave2D_01(x * 0.1, y * 0.1, 6); 153 | std::cout << static_cast(std::floor(noise * 10) - 0.5); 154 | } 155 | std::cout << '\n'; 156 | } 157 | } 158 | 159 | int main() 160 | { 161 | Test(); 162 | 163 | Image image{ 512, 512 }; 164 | 165 | std::cout << "---------------------------------\n"; 166 | std::cout << "* frequency [0.1 .. 8.0 .. 64.0] \n"; 167 | std::cout << "* octaves [1 .. 8 .. 16] \n"; 168 | std::cout << "* seed [0 .. 2^32-1] \n"; 169 | std::cout << "---------------------------------\n"; 170 | 171 | for (;;) 172 | { 173 | double frequency; 174 | std::cout << "double frequency = "; 175 | std::cin >> frequency; 176 | frequency = std::clamp(frequency, 0.1, 64.0); 177 | 178 | std::int32_t octaves; 179 | std::cout << "int32 octaves = "; 180 | std::cin >> octaves; 181 | octaves = std::clamp(octaves, 1, 16); 182 | 183 | std::uint32_t seed; 184 | std::cout << "uint32 seed = "; 185 | std::cin >> seed; 186 | 187 | const siv::PerlinNoise perlin{ seed }; 188 | const double fx = (frequency / image.width()); 189 | const double fy = (frequency / image.height()); 190 | 191 | for (std::int32_t y = 0; y < image.height(); ++y) 192 | { 193 | for (std::int32_t x = 0; x < image.width(); ++x) 194 | { 195 | const RGB color(perlin.octave2D_01((x * fx), (y * fy), octaves)); 196 | image.set(x, y, color); 197 | } 198 | } 199 | 200 | std::stringstream ss; 201 | ss << 'f' << frequency << 'o' << octaves << '_' << seed << ".bmp"; 202 | 203 | if (image.saveBMP(ss.str())) 204 | { 205 | std::cout << "...saved \"" << ss.str() << "\"\n"; 206 | } 207 | else 208 | { 209 | std::cout << "...failed\n"; 210 | } 211 | 212 | char c; 213 | std::cout << "continue? [y/n] >"; 214 | std::cin >> c; 215 | if (c != 'y') break; 216 | std::cout << '\n'; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /PerlinNoise.hpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------------- 2 | // 3 | // siv::PerlinNoise 4 | // Perlin noise library for modern C++ 5 | // 6 | // Copyright (C) 2013-2021 Ryo Suzuki 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files(the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions : 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | //---------------------------------------------------------------------------------------- 27 | 28 | # pragma once 29 | # include 30 | # include 31 | # include 32 | # include 33 | # include 34 | # include 35 | # include 36 | 37 | # if __has_include() && defined(__cpp_concepts) 38 | # include 39 | # endif 40 | 41 | 42 | // Library major version 43 | # define SIVPERLIN_VERSION_MAJOR 3 44 | 45 | // Library minor version 46 | # define SIVPERLIN_VERSION_MINOR 0 47 | 48 | // Library revision version 49 | # define SIVPERLIN_VERSION_REVISION 0 50 | 51 | // Library version 52 | # define SIVPERLIN_VERSION ((SIVPERLIN_VERSION_MAJOR * 100 * 100) + (SIVPERLIN_VERSION_MINOR * 100) + (SIVPERLIN_VERSION_REVISION)) 53 | 54 | 55 | // [[nodiscard]] for constructors 56 | # if (201907L <= __has_cpp_attribute(nodiscard)) 57 | # define SIVPERLIN_NODISCARD_CXX20 [[nodiscard]] 58 | # else 59 | # define SIVPERLIN_NODISCARD_CXX20 60 | # endif 61 | 62 | 63 | // std::uniform_random_bit_generator concept 64 | # if __cpp_lib_concepts 65 | # define SIVPERLIN_CONCEPT_URBG template 66 | # define SIVPERLIN_CONCEPT_URBG_ template 67 | # else 68 | # define SIVPERLIN_CONCEPT_URBG template , std::is_unsigned>>>* = nullptr> 69 | # define SIVPERLIN_CONCEPT_URBG_ template , std::is_unsigned>>>*> 70 | # endif 71 | 72 | 73 | // arbitrary value for increasing entropy 74 | # ifndef SIVPERLIN_DEFAULT_Y 75 | # define SIVPERLIN_DEFAULT_Y (0.12345) 76 | # endif 77 | 78 | // arbitrary value for increasing entropy 79 | # ifndef SIVPERLIN_DEFAULT_Z 80 | # define SIVPERLIN_DEFAULT_Z (0.34567) 81 | # endif 82 | 83 | 84 | namespace siv 85 | { 86 | template 87 | class BasicPerlinNoise 88 | { 89 | public: 90 | 91 | static_assert(std::is_floating_point_v); 92 | 93 | /////////////////////////////////////// 94 | // 95 | // Typedefs 96 | // 97 | 98 | using state_type = std::array; 99 | 100 | using value_type = Float; 101 | 102 | using default_random_engine = std::mt19937; 103 | 104 | using seed_type = typename default_random_engine::result_type; 105 | 106 | /////////////////////////////////////// 107 | // 108 | // Constructors 109 | // 110 | 111 | SIVPERLIN_NODISCARD_CXX20 112 | constexpr BasicPerlinNoise() noexcept; 113 | 114 | SIVPERLIN_NODISCARD_CXX20 115 | explicit BasicPerlinNoise(seed_type seed); 116 | 117 | SIVPERLIN_CONCEPT_URBG 118 | SIVPERLIN_NODISCARD_CXX20 119 | explicit BasicPerlinNoise(URBG&& urbg); 120 | 121 | /////////////////////////////////////// 122 | // 123 | // Reseed 124 | // 125 | 126 | void reseed(seed_type seed); 127 | 128 | SIVPERLIN_CONCEPT_URBG 129 | void reseed(URBG&& urbg); 130 | 131 | /////////////////////////////////////// 132 | // 133 | // Serialization 134 | // 135 | 136 | [[nodiscard]] 137 | constexpr const state_type& serialize() const noexcept; 138 | 139 | constexpr void deserialize(const state_type& state) noexcept; 140 | 141 | /////////////////////////////////////// 142 | // 143 | // Noise (The result is in the range [-1, 1]) 144 | // 145 | 146 | [[nodiscard]] 147 | value_type noise1D(value_type x) const noexcept; 148 | 149 | [[nodiscard]] 150 | value_type noise2D(value_type x, value_type y) const noexcept; 151 | 152 | [[nodiscard]] 153 | value_type noise3D(value_type x, value_type y, value_type z) const noexcept; 154 | 155 | /////////////////////////////////////// 156 | // 157 | // Noise (The result is remapped to the range [0, 1]) 158 | // 159 | 160 | [[nodiscard]] 161 | value_type noise1D_01(value_type x) const noexcept; 162 | 163 | [[nodiscard]] 164 | value_type noise2D_01(value_type x, value_type y) const noexcept; 165 | 166 | [[nodiscard]] 167 | value_type noise3D_01(value_type x, value_type y, value_type z) const noexcept; 168 | 169 | /////////////////////////////////////// 170 | // 171 | // Octave noise (The result can be out of the range [-1, 1]) 172 | // 173 | 174 | [[nodiscard]] 175 | value_type octave1D(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 176 | 177 | [[nodiscard]] 178 | value_type octave2D(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 179 | 180 | [[nodiscard]] 181 | value_type octave3D(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 182 | 183 | /////////////////////////////////////// 184 | // 185 | // Octave noise (The result is clamped to the range [-1, 1]) 186 | // 187 | 188 | [[nodiscard]] 189 | value_type octave1D_11(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 190 | 191 | [[nodiscard]] 192 | value_type octave2D_11(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 193 | 194 | [[nodiscard]] 195 | value_type octave3D_11(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 196 | 197 | /////////////////////////////////////// 198 | // 199 | // Octave noise (The result is clamped and remapped to the range [0, 1]) 200 | // 201 | 202 | [[nodiscard]] 203 | value_type octave1D_01(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 204 | 205 | [[nodiscard]] 206 | value_type octave2D_01(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 207 | 208 | [[nodiscard]] 209 | value_type octave3D_01(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 210 | 211 | /////////////////////////////////////// 212 | // 213 | // Octave noise (The result is normalized to the range [-1, 1]) 214 | // 215 | 216 | [[nodiscard]] 217 | value_type normalizedOctave1D(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 218 | 219 | [[nodiscard]] 220 | value_type normalizedOctave2D(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 221 | 222 | [[nodiscard]] 223 | value_type normalizedOctave3D(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 224 | 225 | /////////////////////////////////////// 226 | // 227 | // Octave noise (The result is normalized and remapped to the range [0, 1]) 228 | // 229 | 230 | [[nodiscard]] 231 | value_type normalizedOctave1D_01(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 232 | 233 | [[nodiscard]] 234 | value_type normalizedOctave2D_01(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 235 | 236 | [[nodiscard]] 237 | value_type normalizedOctave3D_01(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept; 238 | 239 | private: 240 | 241 | state_type m_permutation; 242 | }; 243 | 244 | using PerlinNoise = BasicPerlinNoise; 245 | 246 | namespace perlin_detail 247 | { 248 | //////////////////////////////////////////////// 249 | // 250 | // These functions are provided for consistency. 251 | // You may get different results from std::shuffle() with different standard library implementations. 252 | // 253 | SIVPERLIN_CONCEPT_URBG 254 | [[nodiscard]] 255 | inline std::uint64_t Random(const std::uint64_t max, URBG&& urbg) 256 | { 257 | return (urbg() % (max + 1)); 258 | } 259 | 260 | template 261 | inline void Shuffle(RandomIt first, RandomIt last, URBG&& urbg) 262 | { 263 | if (first == last) 264 | { 265 | return; 266 | } 267 | 268 | using difference_type = typename std::iterator_traits::difference_type; 269 | 270 | for (RandomIt it = first + 1; it < last; ++it) 271 | { 272 | const std::uint64_t n = static_cast(it - first); 273 | std::iter_swap(it, first + static_cast(Random(n, std::forward(urbg)))); 274 | } 275 | } 276 | // 277 | //////////////////////////////////////////////// 278 | 279 | template 280 | [[nodiscard]] 281 | inline constexpr Float Fade(const Float t) noexcept 282 | { 283 | return t * t * t * (t * (t * 6 - 15) + 10); 284 | } 285 | 286 | template 287 | [[nodiscard]] 288 | inline constexpr Float Lerp(const Float a, const Float b, const Float t) noexcept 289 | { 290 | return (a + (b - a) * t); 291 | } 292 | 293 | template 294 | [[nodiscard]] 295 | inline constexpr Float Grad(const std::uint8_t hash, const Float x, const Float y, const Float z) noexcept 296 | { 297 | const std::uint8_t h = hash & 15; 298 | const Float u = h < 8 ? x : y; 299 | const Float v = h < 4 ? y : h == 12 || h == 14 ? x : z; 300 | return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); 301 | } 302 | 303 | template 304 | [[nodiscard]] 305 | inline constexpr Float Remap_01(const Float x) noexcept 306 | { 307 | return (x * Float(0.5) + Float(0.5)); 308 | } 309 | 310 | template 311 | [[nodiscard]] 312 | inline constexpr Float Clamp_11(const Float x) noexcept 313 | { 314 | return std::clamp(x, Float(-1.0), Float(1.0)); 315 | } 316 | 317 | template 318 | [[nodiscard]] 319 | inline constexpr Float RemapClamp_01(const Float x) noexcept 320 | { 321 | if (x <= Float(-1.0)) 322 | { 323 | return Float(0.0); 324 | } 325 | else if (Float(1.0) <= x) 326 | { 327 | return Float(1.0); 328 | } 329 | 330 | return (x * Float(0.5) + Float(0.5)); 331 | } 332 | 333 | template 334 | [[nodiscard]] 335 | inline auto Octave1D(const Noise& noise, Float x, const std::int32_t octaves, const Float persistence) noexcept 336 | { 337 | using value_type = Float; 338 | value_type result = 0; 339 | value_type amplitude = 1; 340 | 341 | for (std::int32_t i = 0; i < octaves; ++i) 342 | { 343 | result += (noise.noise1D(x) * amplitude); 344 | x *= 2; 345 | amplitude *= persistence; 346 | } 347 | 348 | return result; 349 | } 350 | 351 | template 352 | [[nodiscard]] 353 | inline auto Octave2D(const Noise& noise, Float x, Float y, const std::int32_t octaves, const Float persistence) noexcept 354 | { 355 | using value_type = Float; 356 | value_type result = 0; 357 | value_type amplitude = 1; 358 | 359 | for (std::int32_t i = 0; i < octaves; ++i) 360 | { 361 | result += (noise.noise2D(x, y) * amplitude); 362 | x *= 2; 363 | y *= 2; 364 | amplitude *= persistence; 365 | } 366 | 367 | return result; 368 | } 369 | 370 | template 371 | [[nodiscard]] 372 | inline auto Octave3D(const Noise& noise, Float x, Float y, Float z, const std::int32_t octaves, const Float persistence) noexcept 373 | { 374 | using value_type = Float; 375 | value_type result = 0; 376 | value_type amplitude = 1; 377 | 378 | for (std::int32_t i = 0; i < octaves; ++i) 379 | { 380 | result += (noise.noise3D(x, y, z) * amplitude); 381 | x *= 2; 382 | y *= 2; 383 | z *= 2; 384 | amplitude *= persistence; 385 | } 386 | 387 | return result; 388 | } 389 | 390 | template 391 | [[nodiscard]] 392 | inline constexpr Float MaxAmplitude(const std::int32_t octaves, const Float persistence) noexcept 393 | { 394 | using value_type = Float; 395 | value_type result = 0; 396 | value_type amplitude = 1; 397 | 398 | for (std::int32_t i = 0; i < octaves; ++i) 399 | { 400 | result += amplitude; 401 | amplitude *= persistence; 402 | } 403 | 404 | return result; 405 | } 406 | } 407 | 408 | /////////////////////////////////////// 409 | 410 | template 411 | inline constexpr BasicPerlinNoise::BasicPerlinNoise() noexcept 412 | : m_permutation{ 151,160,137,91,90,15, 413 | 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 414 | 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 415 | 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 416 | 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 417 | 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 418 | 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 419 | 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 420 | 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 421 | 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 422 | 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 423 | 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 424 | 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 } {} 425 | 426 | template 427 | inline BasicPerlinNoise::BasicPerlinNoise(const seed_type seed) 428 | { 429 | reseed(seed); 430 | } 431 | 432 | template 433 | SIVPERLIN_CONCEPT_URBG_ 434 | inline BasicPerlinNoise::BasicPerlinNoise(URBG&& urbg) 435 | { 436 | reseed(std::forward(urbg)); 437 | } 438 | 439 | /////////////////////////////////////// 440 | 441 | template 442 | inline void BasicPerlinNoise::reseed(const seed_type seed) 443 | { 444 | reseed(default_random_engine{ seed }); 445 | } 446 | 447 | template 448 | SIVPERLIN_CONCEPT_URBG_ 449 | inline void BasicPerlinNoise::reseed(URBG&& urbg) 450 | { 451 | std::iota(m_permutation.begin(), m_permutation.end(), uint8_t{ 0 }); 452 | 453 | perlin_detail::Shuffle(m_permutation.begin(), m_permutation.end(), std::forward(urbg)); 454 | } 455 | 456 | /////////////////////////////////////// 457 | 458 | template 459 | inline constexpr const typename BasicPerlinNoise::state_type& BasicPerlinNoise::serialize() const noexcept 460 | { 461 | return m_permutation; 462 | } 463 | 464 | template 465 | inline constexpr void BasicPerlinNoise::deserialize(const state_type& state) noexcept 466 | { 467 | m_permutation = state; 468 | } 469 | 470 | /////////////////////////////////////// 471 | 472 | template 473 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::noise1D(const value_type x) const noexcept 474 | { 475 | return noise3D(x, 476 | static_cast(SIVPERLIN_DEFAULT_Y), 477 | static_cast(SIVPERLIN_DEFAULT_Z)); 478 | } 479 | 480 | template 481 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::noise2D(const value_type x, const value_type y) const noexcept 482 | { 483 | return noise3D(x, 484 | y, 485 | static_cast(SIVPERLIN_DEFAULT_Z)); 486 | } 487 | 488 | template 489 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::noise3D(const value_type x, const value_type y, const value_type z) const noexcept 490 | { 491 | const value_type _x = std::floor(x); 492 | const value_type _y = std::floor(y); 493 | const value_type _z = std::floor(z); 494 | 495 | const std::int32_t ix = static_cast(_x) & 255; 496 | const std::int32_t iy = static_cast(_y) & 255; 497 | const std::int32_t iz = static_cast(_z) & 255; 498 | 499 | const value_type fx = (x - _x); 500 | const value_type fy = (y - _y); 501 | const value_type fz = (z - _z); 502 | 503 | const value_type u = perlin_detail::Fade(fx); 504 | const value_type v = perlin_detail::Fade(fy); 505 | const value_type w = perlin_detail::Fade(fz); 506 | 507 | const std::uint8_t A = (m_permutation[ix & 255] + iy) & 255; 508 | const std::uint8_t B = (m_permutation[(ix + 1) & 255] + iy) & 255; 509 | 510 | const std::uint8_t AA = (m_permutation[A] + iz) & 255; 511 | const std::uint8_t AB = (m_permutation[(A + 1) & 255] + iz) & 255; 512 | 513 | const std::uint8_t BA = (m_permutation[B] + iz) & 255; 514 | const std::uint8_t BB = (m_permutation[(B + 1) & 255] + iz) & 255; 515 | 516 | const value_type p0 = perlin_detail::Grad(m_permutation[AA], fx, fy, fz); 517 | const value_type p1 = perlin_detail::Grad(m_permutation[BA], fx - 1, fy, fz); 518 | const value_type p2 = perlin_detail::Grad(m_permutation[AB], fx, fy - 1, fz); 519 | const value_type p3 = perlin_detail::Grad(m_permutation[BB], fx - 1, fy - 1, fz); 520 | const value_type p4 = perlin_detail::Grad(m_permutation[(AA + 1) & 255], fx, fy, fz - 1); 521 | const value_type p5 = perlin_detail::Grad(m_permutation[(BA + 1) & 255], fx - 1, fy, fz - 1); 522 | const value_type p6 = perlin_detail::Grad(m_permutation[(AB + 1) & 255], fx, fy - 1, fz - 1); 523 | const value_type p7 = perlin_detail::Grad(m_permutation[(BB + 1) & 255], fx - 1, fy - 1, fz - 1); 524 | 525 | const value_type q0 = perlin_detail::Lerp(p0, p1, u); 526 | const value_type q1 = perlin_detail::Lerp(p2, p3, u); 527 | const value_type q2 = perlin_detail::Lerp(p4, p5, u); 528 | const value_type q3 = perlin_detail::Lerp(p6, p7, u); 529 | 530 | const value_type r0 = perlin_detail::Lerp(q0, q1, v); 531 | const value_type r1 = perlin_detail::Lerp(q2, q3, v); 532 | 533 | return perlin_detail::Lerp(r0, r1, w); 534 | } 535 | 536 | /////////////////////////////////////// 537 | 538 | template 539 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::noise1D_01(const value_type x) const noexcept 540 | { 541 | return perlin_detail::Remap_01(noise1D(x)); 542 | } 543 | 544 | template 545 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::noise2D_01(const value_type x, const value_type y) const noexcept 546 | { 547 | return perlin_detail::Remap_01(noise2D(x, y)); 548 | } 549 | 550 | template 551 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::noise3D_01(const value_type x, const value_type y, const value_type z) const noexcept 552 | { 553 | return perlin_detail::Remap_01(noise3D(x, y, z)); 554 | } 555 | 556 | /////////////////////////////////////// 557 | 558 | template 559 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::octave1D(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept 560 | { 561 | return perlin_detail::Octave1D(*this, x, octaves, persistence); 562 | } 563 | 564 | template 565 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::octave2D(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept 566 | { 567 | return perlin_detail::Octave2D(*this, x, y, octaves, persistence); 568 | } 569 | 570 | template 571 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::octave3D(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept 572 | { 573 | return perlin_detail::Octave3D(*this, x, y, z, octaves, persistence); 574 | } 575 | 576 | /////////////////////////////////////// 577 | 578 | template 579 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::octave1D_11(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept 580 | { 581 | return perlin_detail::Clamp_11(octave1D(x, octaves, persistence)); 582 | } 583 | 584 | template 585 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::octave2D_11(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept 586 | { 587 | return perlin_detail::Clamp_11(octave2D(x, y, octaves, persistence)); 588 | } 589 | 590 | template 591 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::octave3D_11(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept 592 | { 593 | return perlin_detail::Clamp_11(octave3D(x, y, z, octaves, persistence)); 594 | } 595 | 596 | /////////////////////////////////////// 597 | 598 | template 599 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::octave1D_01(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept 600 | { 601 | return perlin_detail::RemapClamp_01(octave1D(x, octaves, persistence)); 602 | } 603 | 604 | template 605 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::octave2D_01(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept 606 | { 607 | return perlin_detail::RemapClamp_01(octave2D(x, y, octaves, persistence)); 608 | } 609 | 610 | template 611 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::octave3D_01(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept 612 | { 613 | return perlin_detail::RemapClamp_01(octave3D(x, y, z, octaves, persistence)); 614 | } 615 | 616 | /////////////////////////////////////// 617 | 618 | template 619 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::normalizedOctave1D(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept 620 | { 621 | return (octave1D(x, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence)); 622 | } 623 | 624 | template 625 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::normalizedOctave2D(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept 626 | { 627 | return (octave2D(x, y, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence)); 628 | } 629 | 630 | template 631 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::normalizedOctave3D(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept 632 | { 633 | return (octave3D(x, y, z, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence)); 634 | } 635 | 636 | /////////////////////////////////////// 637 | 638 | template 639 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::normalizedOctave1D_01(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept 640 | { 641 | return perlin_detail::Remap_01(normalizedOctave1D(x, octaves, persistence)); 642 | } 643 | 644 | template 645 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::normalizedOctave2D_01(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept 646 | { 647 | return perlin_detail::Remap_01(normalizedOctave2D(x, y, octaves, persistence)); 648 | } 649 | 650 | template 651 | inline typename BasicPerlinNoise::value_type BasicPerlinNoise::normalizedOctave3D_01(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept 652 | { 653 | return perlin_detail::Remap_01(normalizedOctave3D(x, y, z, octaves, persistence)); 654 | } 655 | } 656 | 657 | # undef SIVPERLIN_NODISCARD_CXX20 658 | # undef SIVPERLIN_CONCEPT_URBG 659 | # undef SIVPERLIN_CONCEPT_URBG_ 660 | --------------------------------------------------------------------------------