Przeglądaj źródła

math: extract the gradient generator from simplex noise so that we

can reuse it for other noise implementations.
undefined
Sam Hocevar 10 lat temu
rodzic
commit
5d9488182f
10 zmienionych plików z 141 dodań i 99 usunięć
  1. +11
    -11
      demos/test/simplex.cpp
  2. +2
    -1
      src/Makefile.am
  3. +3
    -1
      src/lol/math/all.h
  4. +95
    -0
      src/lol/math/noise/gradient.h
  5. +16
    -76
      src/lol/math/noise/simplex.h
  6. +2
    -1
      src/lolcore.vcxproj
  7. +9
    -3
      src/lolcore.vcxproj.filters
  8. +1
    -2
      src/t/Makefile.am
  9. +1
    -3
      src/t/math/noise/simplex.cpp
  10. +1
    -1
      src/t/test-math.vcxproj

+ 11
- 11
demos/test/simplex.cpp Wyświetl plik

@@ -33,17 +33,17 @@ int main(int argc, char **argv)
array2d<vec4> &data = img.Lock2D<PixelFormat::RGBA_F32>();

/* 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 */
for (int j = 0; j < size.y; ++j)


+ 2
- 1
src/Makefile.am Wyświetl plik

@@ -44,7 +44,8 @@ liblolcore_headers = \
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/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/sort.h lol/algorithm/portal.h lol/algorithm/aabb_tree.h \


+ 3
- 1
src/lol/math/all.h Wyświetl plik

@@ -23,4 +23,6 @@
#include <lol/math/interp.h>
#include <lol/math/rand.h>
#include <lol/math/polynomial.h>
#include <lol/math/simplex_interpolator.h>

#include <lol/math/noise/gradient.h>
#include <lol/math/noise/simplex.h>

+ 95
- 0
src/lol/math/noise/gradient.h Wyświetl plik

@@ -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;
};

}


src/lol/math/simplex_interpolator.h → src/lol/math/noise/simplex.h Wyświetl plik

@@ -12,7 +12,7 @@

#pragma once

#include <functional>
#include <lol/math/noise/gradient.h>

namespace lol
{
@@ -39,17 +39,22 @@ namespace lol
*/

template<int N>
class simplex_interpolator
class simplex_noise : public gradient_provider<N>
{
public:
simplex_interpolator(int seed = 0)
: m_seed(seed)
simplex_noise()
: gradient_provider<N>()
{
#if 0
debugprint();
#endif
}

simplex_noise(int seed)
: gradient_provider<N>(seed)
{
}

/* Evaluate noise at a given point */
inline float eval(vec_t<float, N> position) const
{
@@ -145,16 +150,15 @@ protected:
//d = (3.f - 2.f * 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);
sum += d;
}

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;
}
}
@@ -185,65 +189,6 @@ protected:
: /* 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)
{
/* 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, and multiply it by the
* matrix inverse. */
#if 0
#if 1
int i0 = (i == 0) ? 1 : 0;
mat_t<float, N, N> m;
for (int j = 0; j < N; ++j)
@@ -374,9 +319,8 @@ private:
for (int k = 0; k < N; ++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.
* Just use the projection theorem in N dimensions. */
@@ -402,8 +346,7 @@ private:
array<vec_t<float, N>> deltas;
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;
}
for (int run = 0; run < 1000; ++run)
@@ -449,9 +392,6 @@ private:

printf("\n");
}

/* A user-provided random seed. Defaults to zero. */
int m_seed;
};

}

+ 2
- 1
src/lolcore.vcxproj Wyświetl plik

@@ -332,12 +332,13 @@
<ClInclude Include="lol\math\half.h" />
<ClInclude Include="lol\math\interp.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\polynomial.h" />
<ClInclude Include="lol\math\rand.h" />
<ClInclude Include="lol\math\real.h" />
<ClInclude Include="lol\math\remez.h" />
<ClInclude Include="lol\math\simplex_interpolator.h" />
<ClInclude Include="lol\math\transform.h" />
<ClInclude Include="lol\math\vector.h" />
<ClInclude Include="lol\public.h" />


+ 9
- 3
src/lolcore.vcxproj.filters Wyświetl plik

@@ -40,6 +40,9 @@
<Filter Include="lol\math">
<UniqueIdentifier>{1e0b7a4c-425f-4d4f-945e-ba2ac9386ce0}</UniqueIdentifier>
</Filter>
<Filter Include="lol\math\noise">
<UniqueIdentifier>{97d023b5-9715-4f30-bacb-846d89025f5b}</UniqueIdentifier>
</Filter>
<Filter Include="math">
<UniqueIdentifier>{2caadbda-b9f1-446d-bbd2-55c959db342c}</UniqueIdentifier>
</Filter>
@@ -450,6 +453,12 @@
<ClInclude Include="lol\math\matrix.h">
<Filter>lol\math</Filter>
</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">
<Filter>lol\math</Filter>
</ClInclude>
@@ -465,9 +474,6 @@
<ClInclude Include="lol\math\remez.h">
<Filter>lol\math</Filter>
</ClInclude>
<ClInclude Include="lol\math\simplex_interpolator.h">
<Filter>lol\math</Filter>
</ClInclude>
<ClInclude Include="lol\math\transform.h">
<Filter>lol\math</Filter>
</ClInclude>


+ 1
- 2
src/t/Makefile.am Wyświetl plik

@@ -20,8 +20,7 @@ test_math_SOURCES = test-common.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/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_DEPENDENCIES = @LOL_DEPS@



src/t/math/simplex_interpolator.cpp → src/t/math/noise/simplex.cpp Wyświetl plik

@@ -12,14 +12,12 @@

#include <lol/engine-internal.h>

#include <lol/math/simplex_interpolator.h>

#include <lolunit.h>

namespace lol
{

lolunit_declare_fixture(SimplexevalolatorTest)
lolunit_declare_fixture(SimplexNoise)
{
void SetUp() {}


+ 1
- 1
src/t/test-math.vcxproj Wyświetl plik

@@ -52,12 +52,12 @@
<ClCompile Include="math\half.cpp" />
<ClCompile Include="math\interp.cpp" />
<ClCompile Include="math\matrix.cpp" />
<ClCompile Include="math\noise\simplex.cpp" />
<ClCompile Include="math\polynomial.cpp" />
<ClCompile Include="math\quat.cpp" />
<ClCompile Include="math\rand.cpp" />
<ClCompile Include="math\real.cpp" />
<ClCompile Include="math\rotation.cpp" />
<ClCompile Include="math\simplex_interpolation.cpp" />
<ClCompile Include="math\trig.cpp" />
<ClCompile Include="math\vector.cpp" />
</ItemGroup>


Ładowanie…
Anuluj
Zapisz