can reuse it for other noise implementations.undefined
| @@ -33,17 +33,17 @@ int main(int argc, char **argv) | |||||
| array2d<vec4> &data = img.Lock2D<PixelFormat::RGBA_F32>(); | array2d<vec4> &data = img.Lock2D<PixelFormat::RGBA_F32>(); | ||||
| /* Declare plenty of allocators */ | /* Declare plenty of allocators */ | ||||
| simplex_interpolator<2> s2; | |||||
| simplex_interpolator<3> s3; | |||||
| simplex_interpolator<4> s4; | |||||
| simplex_interpolator<5> s5; | |||||
| simplex_interpolator<6> s6; | |||||
| simplex_interpolator<7> s7; | |||||
| simplex_interpolator<8> s8; | |||||
| simplex_interpolator<9> s9; | |||||
| simplex_interpolator<10> s10; | |||||
| simplex_interpolator<11> s11; | |||||
| simplex_interpolator<12> s12; | |||||
| simplex_noise<2> s2; | |||||
| simplex_noise<3> s3; | |||||
| simplex_noise<4> s4; | |||||
| simplex_noise<5> s5; | |||||
| simplex_noise<6> s6; | |||||
| simplex_noise<7> s7; | |||||
| simplex_noise<8> s8; | |||||
| simplex_noise<9> s9; | |||||
| simplex_noise<10> s10; | |||||
| simplex_noise<11> s11; | |||||
| simplex_noise<12> s12; | |||||
| /* Fill image with simplex noise */ | /* Fill image with simplex noise */ | ||||
| for (int j = 0; j < size.y; ++j) | for (int j = 0; j < size.y; ++j) | ||||
| @@ -44,7 +44,8 @@ liblolcore_headers = \ | |||||
| lol/math/functions.h lol/math/vector.h lol/math/half.h lol/math/real.h \ | lol/math/functions.h lol/math/vector.h lol/math/half.h lol/math/real.h \ | ||||
| lol/math/geometry.h lol/math/interp.h lol/math/rand.h lol/math/array2d.h \ | lol/math/geometry.h lol/math/interp.h lol/math/rand.h lol/math/array2d.h \ | ||||
| lol/math/array3d.h lol/math/constants.h lol/math/matrix.h lol/math/ops.h \ | lol/math/array3d.h lol/math/constants.h lol/math/matrix.h lol/math/ops.h \ | ||||
| lol/math/transform.h lol/math/polynomial.h lol/math/simplex_interpolator.h \ | |||||
| lol/math/transform.h lol/math/polynomial.h \ | |||||
| lol/math/noise/gradient.h lol/math/noise/simplex.h \ | |||||
| \ | \ | ||||
| lol/algorithm/all.h \ | lol/algorithm/all.h \ | ||||
| lol/algorithm/sort.h lol/algorithm/portal.h lol/algorithm/aabb_tree.h \ | lol/algorithm/sort.h lol/algorithm/portal.h lol/algorithm/aabb_tree.h \ | ||||
| @@ -23,4 +23,6 @@ | |||||
| #include <lol/math/interp.h> | #include <lol/math/interp.h> | ||||
| #include <lol/math/rand.h> | #include <lol/math/rand.h> | ||||
| #include <lol/math/polynomial.h> | #include <lol/math/polynomial.h> | ||||
| #include <lol/math/simplex_interpolator.h> | |||||
| #include <lol/math/noise/gradient.h> | |||||
| #include <lol/math/noise/simplex.h> | |||||
| @@ -0,0 +1,95 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net> | |||||
| // (c) 2013-2014 Benjamin "Touky" Huet <huet.benjamin@gmail.com> | |||||
| // (c) 2013-2014 Guillaume Bittoun <guillaume.bittoun@gmail.com> | |||||
| // This program is free software; you can redistribute it and/or | |||||
| // modify it under the terms of the Do What The Fuck You Want To | |||||
| // Public License, Version 2, as published by Sam Hocevar. See | |||||
| // http://www.wtfpl.net/ for more details. | |||||
| // | |||||
| #pragma once | |||||
| #include <functional> | |||||
| namespace lol | |||||
| { | |||||
| template<int N> | |||||
| class gradient_provider | |||||
| { | |||||
| public: | |||||
| gradient_provider(int seed = 0) | |||||
| : m_seed(seed) | |||||
| { | |||||
| } | |||||
| protected: | |||||
| vec_t<float, N> get_gradient(vec_t<int, N> origin) const | |||||
| { | |||||
| /* Quick shuffle table: | |||||
| * strings /dev/urandom | grep . -nm256 | sort -k2 -t: | sed 's|:.*|,|' | |||||
| * Then just replace “256” with “0”. */ | |||||
| static int const shuffle[256] = | |||||
| { | |||||
| 111, 14, 180, 186, 221, 114, 219, 79, 66, 46, 152, 81, 246, 200, | |||||
| 141, 172, 85, 244, 112, 92, 34, 106, 218, 205, 236, 7, 121, 115, | |||||
| 109, 131, 10, 96, 188, 148, 17, 107, 94, 182, 235, 163, 143, 63, | |||||
| 248, 202, 52, 154, 37, 241, 53, 129, 25, 159, 242, 38, 171, 213, | |||||
| 6, 203, 255, 193, 42, 209, 28, 176, 210, 60, 54, 144, 3, 71, 89, | |||||
| 116, 12, 237, 67, 216, 252, 178, 174, 164, 98, 234, 32, 26, 175, | |||||
| 24, 130, 128, 113, 99, 212, 62, 11, 75, 185, 73, 93, 31, 30, 44, | |||||
| 122, 173, 139, 91, 136, 162, 194, 41, 56, 101, 68, 69, 211, 151, | |||||
| 97, 55, 83, 33, 50, 119, 156, 149, 208, 157, 253, 247, 161, 133, | |||||
| 230, 166, 225, 204, 224, 13, 110, 123, 142, 64, 65, 155, 215, 9, | |||||
| 197, 140, 58, 77, 214, 126, 195, 179, 220, 232, 125, 147, 8, 39, | |||||
| 187, 27, 217, 100, 134, 199, 88, 206, 231, 250, 74, 2, 135, 120, | |||||
| 21, 245, 118, 243, 82, 183, 238, 150, 158, 61, 4, 177, 146, 153, | |||||
| 117, 249, 254, 233, 90, 222, 207, 48, 15, 18, 20, 16, 47, 0, 51, | |||||
| 165, 138, 127, 169, 72, 1, 201, 145, 191, 192, 239, 49, 19, 160, | |||||
| 226, 228, 84, 181, 251, 36, 87, 22, 43, 70, 45, 105, 5, 189, 95, | |||||
| 40, 196, 59, 57, 190, 80, 104, 167, 78, 124, 103, 240, 184, 170, | |||||
| 137, 29, 23, 223, 108, 102, 86, 198, 227, 35, 229, 76, 168, 132, | |||||
| }; | |||||
| /* Generate 2^(N+2) random vectors, but at least 2^5 (32) and not | |||||
| * more than 2^20 (~ 1 million). */ | |||||
| int const gradient_count = 1 << min(max(N + 2, 5), 20); | |||||
| static auto build_gradients = [&]() | |||||
| { | |||||
| array<vec_t<float, N>> ret; | |||||
| for (int k = 0; k < gradient_count; ++k) | |||||
| { | |||||
| vec_t<float, N> v; | |||||
| for (int i = 0; i < N; ++i) | |||||
| v[i] = rand(-1.f, 1.f); | |||||
| ret << normalize(v); | |||||
| } | |||||
| return ret; | |||||
| }; | |||||
| static array<vec_t<float, N>> const gradients = build_gradients(); | |||||
| int idx = m_seed; | |||||
| for (int i = 0; i < N; ++i) | |||||
| idx ^= shuffle[(idx + origin[i]) & 255]; | |||||
| idx &= (gradient_count - 1); | |||||
| #if 0 | |||||
| // DEBUG: only output a few gradients | |||||
| if (idx > 2) | |||||
| return vec_t<float, N>(0); | |||||
| #endif | |||||
| return gradients[idx]; | |||||
| } | |||||
| private: | |||||
| /* A user-provided random seed. Defaults to zero. */ | |||||
| int m_seed; | |||||
| }; | |||||
| } | |||||
| @@ -12,7 +12,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <functional> | |||||
| #include <lol/math/noise/gradient.h> | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| @@ -39,17 +39,22 @@ namespace lol | |||||
| */ | */ | ||||
| template<int N> | template<int N> | ||||
| class simplex_interpolator | |||||
| class simplex_noise : public gradient_provider<N> | |||||
| { | { | ||||
| public: | public: | ||||
| simplex_interpolator(int seed = 0) | |||||
| : m_seed(seed) | |||||
| simplex_noise() | |||||
| : gradient_provider<N>() | |||||
| { | { | ||||
| #if 0 | #if 0 | ||||
| debugprint(); | debugprint(); | ||||
| #endif | #endif | ||||
| } | } | ||||
| simplex_noise(int seed) | |||||
| : gradient_provider<N>(seed) | |||||
| { | |||||
| } | |||||
| /* Evaluate noise at a given point */ | /* Evaluate noise at a given point */ | ||||
| inline float eval(vec_t<float, N> position) const | inline float eval(vec_t<float, N> position) const | ||||
| { | { | ||||
| @@ -145,16 +150,15 @@ protected: | |||||
| //d = (3.f - 2.f * d) * d * d; | //d = (3.f - 2.f * d) * d * d; | ||||
| //d = ((6 * d - 15) * d + 10) * d * d * d; | //d = ((6 * d - 15) * d + 10) * d * d * d; | ||||
| result += d * dot(get_gradient(origin), | |||||
| result += d * dot(this->get_gradient(origin), | |||||
| world_pos - world_corner); | world_pos - world_corner); | ||||
| sum += d; | sum += d; | ||||
| } | } | ||||
| if (i < N) | if (i < N) | ||||
| { | { | ||||
| vec_t<float, N> v(0.f); | |||||
| v[traversal_order[i]] = 1.f; | |||||
| world_corner += unskew(v); | |||||
| auto axis = vec_t<float, N>::axis(traversal_order[i]); | |||||
| world_corner += unskew(axis); | |||||
| origin[traversal_order[i]] += 1; | origin[traversal_order[i]] += 1; | ||||
| } | } | ||||
| } | } | ||||
| @@ -185,65 +189,6 @@ protected: | |||||
| : /* 7+ */ 6.7958f; | : /* 7+ */ 6.7958f; | ||||
| } | } | ||||
| inline vec_t<float, N> get_gradient(vec_t<int, N> origin) const | |||||
| { | |||||
| /* Quick shuffle table: | |||||
| * strings /dev/urandom | grep . -nm256 | sort -k2 -t: | sed 's|:.*|,|' | |||||
| * Then just replace “256” with “0”. */ | |||||
| static int const shuffle[256] = | |||||
| { | |||||
| 111, 14, 180, 186, 221, 114, 219, 79, 66, 46, 152, 81, 246, 200, | |||||
| 141, 172, 85, 244, 112, 92, 34, 106, 218, 205, 236, 7, 121, 115, | |||||
| 109, 131, 10, 96, 188, 148, 17, 107, 94, 182, 235, 163, 143, 63, | |||||
| 248, 202, 52, 154, 37, 241, 53, 129, 25, 159, 242, 38, 171, 213, | |||||
| 6, 203, 255, 193, 42, 209, 28, 176, 210, 60, 54, 144, 3, 71, 89, | |||||
| 116, 12, 237, 67, 216, 252, 178, 174, 164, 98, 234, 32, 26, 175, | |||||
| 24, 130, 128, 113, 99, 212, 62, 11, 75, 185, 73, 93, 31, 30, 44, | |||||
| 122, 173, 139, 91, 136, 162, 194, 41, 56, 101, 68, 69, 211, 151, | |||||
| 97, 55, 83, 33, 50, 119, 156, 149, 208, 157, 253, 247, 161, 133, | |||||
| 230, 166, 225, 204, 224, 13, 110, 123, 142, 64, 65, 155, 215, 9, | |||||
| 197, 140, 58, 77, 214, 126, 195, 179, 220, 232, 125, 147, 8, 39, | |||||
| 187, 27, 217, 100, 134, 199, 88, 206, 231, 250, 74, 2, 135, 120, | |||||
| 21, 245, 118, 243, 82, 183, 238, 150, 158, 61, 4, 177, 146, 153, | |||||
| 117, 249, 254, 233, 90, 222, 207, 48, 15, 18, 20, 16, 47, 0, 51, | |||||
| 165, 138, 127, 169, 72, 1, 201, 145, 191, 192, 239, 49, 19, 160, | |||||
| 226, 228, 84, 181, 251, 36, 87, 22, 43, 70, 45, 105, 5, 189, 95, | |||||
| 40, 196, 59, 57, 190, 80, 104, 167, 78, 124, 103, 240, 184, 170, | |||||
| 137, 29, 23, 223, 108, 102, 86, 198, 227, 35, 229, 76, 168, 132, | |||||
| }; | |||||
| /* Generate 2^(N+2) random vectors, but at least 2^5 (32) and not | |||||
| * more than 2^20 (~ 1 million). */ | |||||
| int const gradient_count = 1 << min(max(N + 2, 5), 20); | |||||
| static auto build_gradients = [&]() | |||||
| { | |||||
| array<vec_t<float, N>> ret; | |||||
| for (int k = 0; k < gradient_count; ++k) | |||||
| { | |||||
| vec_t<float, N> v; | |||||
| for (int i = 0; i < N; ++i) | |||||
| v[i] = rand(-1.f, 1.f); | |||||
| ret << normalize(v); | |||||
| } | |||||
| return ret; | |||||
| }; | |||||
| static array<vec_t<float, N>> const gradients = build_gradients(); | |||||
| int idx = m_seed; | |||||
| for (int i = 0; i < N; ++i) | |||||
| idx ^= shuffle[(idx + origin[i]) & 255]; | |||||
| idx &= (gradient_count - 1); | |||||
| #if 0 | |||||
| // DEBUG: only output a few gradients | |||||
| if (idx > 2) | |||||
| return vec_t<float, N>(0); | |||||
| #endif | |||||
| return gradients[idx]; | |||||
| } | |||||
| static inline vec_t<float, N> skew(vec_t<float, N> const &v) | static inline vec_t<float, N> skew(vec_t<float, N> const &v) | ||||
| { | { | ||||
| /* Quoting Perlin in “Hardware Noise” (2-18): | /* Quoting Perlin in “Hardware Noise” (2-18): | ||||
| @@ -365,7 +310,7 @@ private: | |||||
| * full of zeroes except at position i. So we build a vector | * full of zeroes except at position i. So we build a vector | ||||
| * full of zeroes except at position i, and multiply it by the | * full of zeroes except at position i, and multiply it by the | ||||
| * matrix inverse. */ | * matrix inverse. */ | ||||
| #if 0 | |||||
| #if 1 | |||||
| int i0 = (i == 0) ? 1 : 0; | int i0 = (i == 0) ? 1 : 0; | ||||
| mat_t<float, N, N> m; | mat_t<float, N, N> m; | ||||
| for (int j = 0; j < N; ++j) | for (int j = 0; j < N; ++j) | ||||
| @@ -374,9 +319,8 @@ private: | |||||
| for (int k = 0; k < N; ++k) | for (int k = 0; k < N; ++k) | ||||
| m[k][j] = v[k]; | m[k][j] = v[k]; | ||||
| } | } | ||||
| vec_t<float, N> p(0.f); | |||||
| p[i < i0 ? i : i - 1] = 1.f; | |||||
| auto normal = normalize(inverse(m) * p); | |||||
| auto axis = vec_t<float, N>::axis(i < i0 ? i : i - 1); | |||||
| auto normal = normalize(inverse(m) * axis); | |||||
| /* Find distance from current vertex to the opposite hyperplane. | /* Find distance from current vertex to the opposite hyperplane. | ||||
| * Just use the projection theorem in N dimensions. */ | * Just use the projection theorem in N dimensions. */ | ||||
| @@ -402,8 +346,7 @@ private: | |||||
| array<vec_t<float, N>> deltas; | array<vec_t<float, N>> deltas; | ||||
| for (int i = 0; i < N; ++i) | for (int i = 0; i < N; ++i) | ||||
| { | { | ||||
| vec_t<float, N> v(0.f); | |||||
| v[i] = 1.f; | |||||
| auto v = vec_t<float, N>::axis(i); | |||||
| deltas << v << -v; | deltas << v << -v; | ||||
| } | } | ||||
| for (int run = 0; run < 1000; ++run) | for (int run = 0; run < 1000; ++run) | ||||
| @@ -449,9 +392,6 @@ private: | |||||
| printf("\n"); | printf("\n"); | ||||
| } | } | ||||
| /* A user-provided random seed. Defaults to zero. */ | |||||
| int m_seed; | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -332,12 +332,13 @@ | |||||
| <ClInclude Include="lol\math\half.h" /> | <ClInclude Include="lol\math\half.h" /> | ||||
| <ClInclude Include="lol\math\interp.h" /> | <ClInclude Include="lol\math\interp.h" /> | ||||
| <ClInclude Include="lol\math\matrix.h" /> | <ClInclude Include="lol\math\matrix.h" /> | ||||
| <ClInclude Include="lol\math\noise\gradient.h" /> | |||||
| <ClInclude Include="lol\math\noise\simplex.h" /> | |||||
| <ClInclude Include="lol\math\ops.h" /> | <ClInclude Include="lol\math\ops.h" /> | ||||
| <ClInclude Include="lol\math\polynomial.h" /> | <ClInclude Include="lol\math\polynomial.h" /> | ||||
| <ClInclude Include="lol\math\rand.h" /> | <ClInclude Include="lol\math\rand.h" /> | ||||
| <ClInclude Include="lol\math\real.h" /> | <ClInclude Include="lol\math\real.h" /> | ||||
| <ClInclude Include="lol\math\remez.h" /> | <ClInclude Include="lol\math\remez.h" /> | ||||
| <ClInclude Include="lol\math\simplex_interpolator.h" /> | |||||
| <ClInclude Include="lol\math\transform.h" /> | <ClInclude Include="lol\math\transform.h" /> | ||||
| <ClInclude Include="lol\math\vector.h" /> | <ClInclude Include="lol\math\vector.h" /> | ||||
| <ClInclude Include="lol\public.h" /> | <ClInclude Include="lol\public.h" /> | ||||
| @@ -40,6 +40,9 @@ | |||||
| <Filter Include="lol\math"> | <Filter Include="lol\math"> | ||||
| <UniqueIdentifier>{1e0b7a4c-425f-4d4f-945e-ba2ac9386ce0}</UniqueIdentifier> | <UniqueIdentifier>{1e0b7a4c-425f-4d4f-945e-ba2ac9386ce0}</UniqueIdentifier> | ||||
| </Filter> | </Filter> | ||||
| <Filter Include="lol\math\noise"> | |||||
| <UniqueIdentifier>{97d023b5-9715-4f30-bacb-846d89025f5b}</UniqueIdentifier> | |||||
| </Filter> | |||||
| <Filter Include="math"> | <Filter Include="math"> | ||||
| <UniqueIdentifier>{2caadbda-b9f1-446d-bbd2-55c959db342c}</UniqueIdentifier> | <UniqueIdentifier>{2caadbda-b9f1-446d-bbd2-55c959db342c}</UniqueIdentifier> | ||||
| </Filter> | </Filter> | ||||
| @@ -450,6 +453,12 @@ | |||||
| <ClInclude Include="lol\math\matrix.h"> | <ClInclude Include="lol\math\matrix.h"> | ||||
| <Filter>lol\math</Filter> | <Filter>lol\math</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| <ClInclude Include="lol\math\noise\gradient.h"> | |||||
| <Filter>lol\math\noise</Filter> | |||||
| </ClInclude> | |||||
| <ClInclude Include="lol\math\noise\simplex.h"> | |||||
| <Filter>lol\math\noise</Filter> | |||||
| </ClInclude> | |||||
| <ClInclude Include="lol\math\ops.h"> | <ClInclude Include="lol\math\ops.h"> | ||||
| <Filter>lol\math</Filter> | <Filter>lol\math</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| @@ -465,9 +474,6 @@ | |||||
| <ClInclude Include="lol\math\remez.h"> | <ClInclude Include="lol\math\remez.h"> | ||||
| <Filter>lol\math</Filter> | <Filter>lol\math</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| <ClInclude Include="lol\math\simplex_interpolator.h"> | |||||
| <Filter>lol\math</Filter> | |||||
| </ClInclude> | |||||
| <ClInclude Include="lol\math\transform.h"> | <ClInclude Include="lol\math\transform.h"> | ||||
| <Filter>lol\math</Filter> | <Filter>lol\math</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| @@ -20,8 +20,7 @@ test_math_SOURCES = test-common.cpp \ | |||||
| math/array2d.cpp math/array3d.cpp math/arraynd.cpp math/box.cpp \ | math/array2d.cpp math/array3d.cpp math/arraynd.cpp math/box.cpp \ | ||||
| math/cmplx.cpp math/half.cpp math/interp.cpp math/matrix.cpp \ | math/cmplx.cpp math/half.cpp math/interp.cpp math/matrix.cpp \ | ||||
| math/quat.cpp math/rand.cpp math/real.cpp math/rotation.cpp \ | math/quat.cpp math/rand.cpp math/real.cpp math/rotation.cpp \ | ||||
| math/trig.cpp math/vector.cpp math/simplex_interpolator.cpp \ | |||||
| math/polynomial.cpp | |||||
| math/trig.cpp math/vector.cpp math/polynomial.cpp math/noise/simplex.cpp | |||||
| test_math_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tools/lolunit | test_math_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tools/lolunit | ||||
| test_math_DEPENDENCIES = @LOL_DEPS@ | test_math_DEPENDENCIES = @LOL_DEPS@ | ||||
| @@ -12,14 +12,12 @@ | |||||
| #include <lol/engine-internal.h> | #include <lol/engine-internal.h> | ||||
| #include <lol/math/simplex_interpolator.h> | |||||
| #include <lolunit.h> | #include <lolunit.h> | ||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| lolunit_declare_fixture(SimplexevalolatorTest) | |||||
| lolunit_declare_fixture(SimplexNoise) | |||||
| { | { | ||||
| void SetUp() {} | void SetUp() {} | ||||
| @@ -52,12 +52,12 @@ | |||||
| <ClCompile Include="math\half.cpp" /> | <ClCompile Include="math\half.cpp" /> | ||||
| <ClCompile Include="math\interp.cpp" /> | <ClCompile Include="math\interp.cpp" /> | ||||
| <ClCompile Include="math\matrix.cpp" /> | <ClCompile Include="math\matrix.cpp" /> | ||||
| <ClCompile Include="math\noise\simplex.cpp" /> | |||||
| <ClCompile Include="math\polynomial.cpp" /> | <ClCompile Include="math\polynomial.cpp" /> | ||||
| <ClCompile Include="math\quat.cpp" /> | <ClCompile Include="math\quat.cpp" /> | ||||
| <ClCompile Include="math\rand.cpp" /> | <ClCompile Include="math\rand.cpp" /> | ||||
| <ClCompile Include="math\real.cpp" /> | <ClCompile Include="math\real.cpp" /> | ||||
| <ClCompile Include="math\rotation.cpp" /> | <ClCompile Include="math\rotation.cpp" /> | ||||
| <ClCompile Include="math\simplex_interpolation.cpp" /> | |||||
| <ClCompile Include="math\trig.cpp" /> | <ClCompile Include="math\trig.cpp" /> | ||||
| <ClCompile Include="math\vector.cpp" /> | <ClCompile Include="math\vector.cpp" /> | ||||
| </ItemGroup> | </ItemGroup> | ||||