noise: use permutation random generator
much faster for common operations
This commit is contained in:
parent
e80e445645
commit
b464f089a5
@ -186,6 +186,10 @@ UTIL_FILES = \
|
||||
noise/midpoint.hpp \
|
||||
noise/rand.hpp \
|
||||
noise/rand.ipp \
|
||||
noise/rand/hash.hpp \
|
||||
noise/rand/hash.ipp \
|
||||
noise/rand/permute.cpp \
|
||||
noise/rand/permute.hpp \
|
||||
noise/turbulence.hpp \
|
||||
noise/turbulence.ipp \
|
||||
pascal.cpp \
|
||||
|
@ -38,7 +38,7 @@ namespace util { namespace noise { namespace basis {
|
||||
vector<S,T>
|
||||
expgrad<S,T,L>::generate (pointi<S> p) const
|
||||
{
|
||||
auto t = (noise::rand<float> (this->seed (), p) + 1) / 2;
|
||||
auto t = rand::scalar<float> (this->seed (), p);
|
||||
auto factor = std::pow (m_base, -t * m_exponent);
|
||||
return factor * gradient<S,T,L>::generate (p);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ namespace util { namespace noise { namespace basis {
|
||||
vector<S,T>
|
||||
gradient<S,T,L>::generate (pointi<S> p) const
|
||||
{
|
||||
return noise::rand<vector,T> (m_seed, p);
|
||||
return rand::coord<vector,T> (m_seed, p) * 2 - 1;
|
||||
}
|
||||
} } }
|
||||
|
||||
|
@ -61,7 +61,7 @@ namespace util { namespace noise { namespace basis {
|
||||
std::transform (std::begin (this->OFFSETS),
|
||||
std::end (this->OFFSETS),
|
||||
std::begin (centres),
|
||||
[this,p_int] (auto i) { return (noise::rand<point,T> (m_seed, p_int + i) + 1) / 2 + i; });
|
||||
[this,p_int] (auto i) { return rand::coord<point,T> (m_seed, p_int + i) + i; });
|
||||
|
||||
T distances[COUNT];
|
||||
std::transform (std::begin (centres),
|
||||
@ -96,7 +96,7 @@ namespace util { namespace noise { namespace basis {
|
||||
// to blend.
|
||||
for (size_t i = 0; i < hi_off; ++i)
|
||||
{
|
||||
auto v = util::noise::rand<T> (
|
||||
auto v = rand::scalar<T> (
|
||||
m_seed,
|
||||
p_int + this->OFFSETS[indices[i]]
|
||||
);
|
||||
|
@ -19,7 +19,6 @@
|
||||
#endif
|
||||
#define __UTIL_NOISE_BASIS_PERLIN_IPP
|
||||
|
||||
#include "../rand.hpp"
|
||||
#include "../../types.hpp"
|
||||
|
||||
|
||||
|
@ -77,7 +77,7 @@ namespace util { namespace noise { namespace basis {
|
||||
std::array<T,pow(2,S)> g_;
|
||||
std::transform (std::begin (p_), std::end (p_),
|
||||
std::begin (g_),
|
||||
[this] (auto i) { return noise::rand<float> (m_seed, i); });
|
||||
[this] (auto i) { return rand::scalar<float> (m_seed, i) * 2 - 1; });
|
||||
|
||||
// Interpolate on one dimension, then the other.
|
||||
T l_[pow(2,S)];
|
||||
|
@ -91,6 +91,6 @@ namespace util { namespace noise { namespace basis {
|
||||
point<S,T>
|
||||
worley<S,T,F>::generate (point<S,intmax_t> p) const
|
||||
{
|
||||
return (noise::rand<util::point,T> (m_seed, p) + 1) / 2;
|
||||
return rand::coord<util::point,T> (m_seed, p);
|
||||
}
|
||||
} } }
|
||||
|
@ -60,10 +60,10 @@ fill (util::image::buffer<T> &img,
|
||||
// do the centre
|
||||
{
|
||||
const auto avg = (v0 + v1 + v2 + v3) / 4;
|
||||
const auto val = avg + scale * util::noise::rand<T> (seed, target.centre ());
|
||||
const auto val = avg + scale * util::noise::rand::scalar<T> (seed, target.centre ());
|
||||
const auto pos = target.p + target.e / 2;
|
||||
|
||||
img[pos] = val;
|
||||
img[pos] = val * 2 - 1;
|
||||
}
|
||||
|
||||
// average the sides
|
||||
@ -73,15 +73,15 @@ fill (util::image::buffer<T> &img,
|
||||
const auto p32 = target.p + util::vector2u{w/2, h-1};
|
||||
const auto p20 = target.p + util::vector2u{0, h/2};
|
||||
|
||||
const auto v01 = (v0 + v1) / 2 + sides * scale * util::noise::rand<T> (seed, p01);
|
||||
const auto v13 = (v1 + v3) / 2 + sides * scale * util::noise::rand<T> (seed, p13);
|
||||
const auto v32 = (v3 + v2) / 2 + sides * scale * util::noise::rand<T> (seed, p32);
|
||||
const auto v20 = (v2 + v0) / 2 + sides * scale * util::noise::rand<T> (seed, p20);
|
||||
const auto v01 = (v0 + v1) / 2 + sides * scale * util::noise::rand::scalar<T> (seed, p01);
|
||||
const auto v13 = (v1 + v3) / 2 + sides * scale * util::noise::rand::scalar<T> (seed, p13);
|
||||
const auto v32 = (v3 + v2) / 2 + sides * scale * util::noise::rand::scalar<T> (seed, p32);
|
||||
const auto v20 = (v2 + v0) / 2 + sides * scale * util::noise::rand::scalar<T> (seed, p20);
|
||||
|
||||
img[p01] = v01;
|
||||
img[p13] = v13;
|
||||
img[p32] = v32;
|
||||
img[p20] = v20;
|
||||
img[p01] = v01 * 2 - 1;
|
||||
img[p13] = v13 * 2 - 1;
|
||||
img[p32] = v32 * 2 - 1;
|
||||
img[p20] = v20 * 2 - 1;
|
||||
}
|
||||
|
||||
// recurse
|
||||
@ -109,7 +109,7 @@ util::noise::midpoint (image::buffer<T> &img, uint64_t seed, float persistence,
|
||||
};
|
||||
|
||||
for (auto i: CORNERS)
|
||||
img[i] = util::noise::rand<T> (seed, i);
|
||||
img[i] = util::noise::rand::scalar<T> (seed, i) * 2 - 1;
|
||||
|
||||
fill (img, seed, { { 0, 0 }, img.extent () }, 1.f, persistence, sides);
|
||||
}
|
||||
|
@ -17,8 +17,11 @@
|
||||
#ifndef __UTIL_NOISE_RAND_HPP
|
||||
#define __UTIL_NOISE_RAND_HPP
|
||||
|
||||
namespace util { namespace noise {
|
||||
/// generate a uniform random floating point in the range [-1, 1] from a seed and vector
|
||||
#include "./rand/permute.hpp"
|
||||
#include "./rand/hash.hpp"
|
||||
|
||||
namespace util { namespace noise { namespace rand {
|
||||
/// generate a uniform random floating point in the range [0, 1] from a seed and vector
|
||||
template <
|
||||
typename U,
|
||||
size_t S,
|
||||
@ -26,8 +29,16 @@ namespace util { namespace noise {
|
||||
template <size_t,typename> class Q
|
||||
>
|
||||
U
|
||||
rand (uint64_t seed, Q<S,T> value);
|
||||
scalar (uint64_t seed, Q<S,T> value)
|
||||
{
|
||||
#if 1
|
||||
return permute::scalar<U> (seed, value);
|
||||
#else
|
||||
return hash::scalar<U> (seed, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// generate a coordinate type with uniform random components in the range [0, 1]
|
||||
template <
|
||||
template <size_t,typename> class R,
|
||||
typename U,
|
||||
@ -36,9 +47,14 @@ namespace util { namespace noise {
|
||||
template <size_t,typename> class Q
|
||||
>
|
||||
R<S,U>
|
||||
rand (uint64_t seed, Q<S,T> value);
|
||||
} }
|
||||
|
||||
#include "rand.ipp"
|
||||
coord (uint64_t seed, Q<S,T> value)
|
||||
{
|
||||
#if 1
|
||||
return permute::coord<R,U,S,T,Q> (seed, value);
|
||||
#else
|
||||
return hash::coord<R,U,S,T,Q> (seed, value);
|
||||
#endif
|
||||
}
|
||||
} } }
|
||||
|
||||
#endif
|
||||
|
49
noise/rand/hash.hpp
Normal file
49
noise/rand/hash.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __UTIL_NOISE_RAND_HASH_HPP
|
||||
#define __UTIL_NOISE_RAND_HASH_HPP
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace util { namespace noise { namespace rand {
|
||||
struct hash {
|
||||
/// generate a uniform random floating point in the range [0, 1] from a seed and vector
|
||||
template <
|
||||
typename U,
|
||||
size_t S,
|
||||
typename T,
|
||||
template <size_t,typename> class Q
|
||||
>
|
||||
static U
|
||||
scalar (uint64_t seed, Q<S,T> value);
|
||||
|
||||
/// generate a coordinate type with uniform random components in the range [0, 1]
|
||||
template <
|
||||
template <size_t,typename> class R,
|
||||
typename U,
|
||||
size_t S,
|
||||
typename T,
|
||||
template <size_t,typename> class Q
|
||||
>
|
||||
static R<S,U>
|
||||
coord (uint64_t seed, Q<S,T> value);
|
||||
};
|
||||
} } }
|
||||
|
||||
#include "./hash.hpp"
|
||||
|
||||
#endif
|
@ -15,15 +15,13 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __UTIL_NOISE_RAND_IPP
|
||||
#ifdef __UTIL_NOISE_RAND_HASH_IPP
|
||||
#error
|
||||
#endif
|
||||
#define __UTIL_NOISE_RAND_IPP
|
||||
|
||||
#include "../hash/murmur/murmur2.hpp"
|
||||
#define __UTIL_NOISE_RAND_HASH_IPP
|
||||
|
||||
|
||||
namespace util { namespace noise {
|
||||
namespace util { namespace noise { namespace rand {
|
||||
//-------------------------------------------------------------------------
|
||||
template <
|
||||
typename U,
|
||||
@ -32,21 +30,17 @@ namespace util { namespace noise {
|
||||
template <size_t,typename> class Q
|
||||
>
|
||||
U
|
||||
rand (uint64_t seed, Q<S,T> query)
|
||||
hash::scalar (uint64_t seed, Q<S,T> query)
|
||||
{
|
||||
constexpr decltype(seed) BITS = 0xFFFF;
|
||||
static_assert (std::is_integral<T>::value,
|
||||
"mixing only works on integral types");
|
||||
|
||||
uint64_t accum = seed;
|
||||
for (auto i: query)
|
||||
accum = hash::murmur2::mix (accum, i);
|
||||
accum = util::hash::murmur2::mix (accum, i);
|
||||
|
||||
U result = (accum & 0xFFFF) / U{0xFFFF};
|
||||
|
||||
result *= 2;
|
||||
result -= 1;
|
||||
|
||||
return result;
|
||||
return (accum & BITS) / U{BITS};
|
||||
}
|
||||
|
||||
|
||||
@ -59,18 +53,22 @@ namespace util { namespace noise {
|
||||
template <size_t,typename> class Q
|
||||
>
|
||||
R<S,U>
|
||||
rand (uint64_t seed, Q<S,T> query)
|
||||
hash::coord (uint64_t seed, Q<S,T> query)
|
||||
{
|
||||
uint64_t accum = seed;
|
||||
constexpr decltype(seed) PERTURB = 0x96c39996c36c36c3;
|
||||
constexpr decltype(seed) BITS = 0xFFFF;
|
||||
|
||||
auto accum = seed ^ PERTURB;
|
||||
for (auto i: query)
|
||||
accum = hash::murmur2::mix (accum, i);
|
||||
accum = util::hash::murmur2::mix (accum, i);
|
||||
|
||||
R<S,U> result;
|
||||
for (auto &i: result) {
|
||||
i = (accum & 0xFFFF) / U{0xFFFF};
|
||||
accum = hash::murmur2::mix (accum, seed);
|
||||
i = (accum & BITS);
|
||||
i /= BITS;
|
||||
accum = util::hash::murmur2::mix (accum, seed);
|
||||
}
|
||||
|
||||
return result * 2 - 1;
|
||||
return result;
|
||||
}
|
||||
} }
|
||||
} } }
|
25
noise/rand/permute.cpp
Normal file
25
noise/rand/permute.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "./permute.hpp"
|
||||
|
||||
|
||||
using util::noise::rand::permute;
|
||||
|
||||
// static permutation offsets. consists of numbers [0,255] in a randomised
|
||||
// pattern. the exact arrangement is irrelevant.
|
||||
const std::array<uint8_t,256> permute::PERMUTE = {
|
||||
148, 94, 173, 74, 199, 189, 102, 184, 149, 18, 177, 211, 16, 221, 252, 232,
|
||||
82, 104, 164, 196, 78, 4, 247, 11, 206, 176, 137, 45, 30, 118, 72, 59,
|
||||
39, 198, 158, 220, 213, 230, 197, 209, 145, 172, 188, 10, 214, 144, 241, 242,
|
||||
84, 128, 168, 229, 64, 32, 20, 249, 236, 194, 253, 183, 132, 6, 43, 96,
|
||||
181, 27, 127, 106, 63, 21, 134, 120, 170, 166, 93, 191, 70, 240, 46, 85,
|
||||
23, 56, 228, 28, 160, 67, 175, 161, 36, 61, 204, 71, 140, 103, 190, 66,
|
||||
100, 130, 192, 251, 174, 201, 79, 169, 231, 53, 48, 50, 119, 178, 87, 205,
|
||||
243, 165, 207, 13, 116, 235, 24, 224, 47, 81, 195, 218, 97, 83, 238, 227,
|
||||
113, 180, 33, 111, 126, 200, 153, 5, 146, 112, 179, 255, 250, 19, 92, 80,
|
||||
135, 222, 95, 22, 142, 40, 15, 107, 217, 41, 77, 110, 210, 246, 185, 54,
|
||||
163, 105, 114, 193, 215, 73, 150, 129, 208, 155, 171, 154, 115, 0, 8, 233,
|
||||
162, 138, 109, 157, 248, 26, 25, 244, 31, 62, 75, 35, 29, 60, 182, 156,
|
||||
55, 223, 125, 51, 76, 88, 9, 151, 117, 122, 38, 159, 124, 49, 44, 254,
|
||||
202, 147, 225, 219, 90, 234, 133, 212, 14, 7, 167, 2, 91, 68, 187, 216,
|
||||
65, 42, 69, 245, 123, 152, 89, 52, 37, 121, 143, 1, 57, 226, 3, 239,
|
||||
99, 98, 108, 186, 17, 139, 203, 58, 86, 131, 141, 136, 34, 101, 12, 237
|
||||
};
|
55
noise/rand/permute.hpp
Normal file
55
noise/rand/permute.hpp
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __UTIL_NOISE_RAND_PERMUTE_HPP
|
||||
#define __UTIL_NOISE_RAND_PERMUTE_HPP
|
||||
|
||||
#include <array>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace util { namespace noise { namespace rand {
|
||||
struct permute {
|
||||
/// generate a uniform random floating point in the range [0, 1] from a seed and vector
|
||||
template <
|
||||
typename U,
|
||||
size_t S,
|
||||
typename T,
|
||||
template <size_t,typename> class Q
|
||||
>
|
||||
static U
|
||||
scalar (uint64_t seed, Q<S,T> value);
|
||||
|
||||
/// generate a coordinate type with uniform random components in the range [0, 1]
|
||||
template <
|
||||
template <size_t,typename> class R,
|
||||
typename U,
|
||||
size_t S,
|
||||
typename T,
|
||||
template <size_t,typename> class Q
|
||||
>
|
||||
static R<S,U>
|
||||
coord (uint64_t seed, Q<S,T> value);
|
||||
|
||||
private:
|
||||
static const std::array<uint8_t, 256> PERMUTE;
|
||||
};
|
||||
} } }
|
||||
|
||||
#include "./permute.ipp"
|
||||
|
||||
#endif
|
||||
|
47
noise/rand/permute.ipp
Normal file
47
noise/rand/permute.ipp
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace util { namespace noise { namespace rand {
|
||||
template <
|
||||
typename U,
|
||||
size_t S,
|
||||
typename T,
|
||||
template <size_t,typename> class Q
|
||||
>
|
||||
U
|
||||
permute::scalar (uint64_t seed, Q<S,T> query)
|
||||
{
|
||||
|
||||
size_t idx = PERMUTE[seed&0xff];
|
||||
for (auto i: query)
|
||||
idx = PERMUTE[(idx+i)&0xff];
|
||||
return PERMUTE[idx] / U(0xff);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <
|
||||
template <size_t,typename> class R,
|
||||
typename U,
|
||||
size_t S,
|
||||
typename T,
|
||||
template <size_t,typename> class Q
|
||||
>
|
||||
R<S,U>
|
||||
permute::coord (uint64_t seed, Q<S,T> query)
|
||||
{
|
||||
auto accum = seed;
|
||||
for (auto q: query) {
|
||||
size_t idx = q + accum;
|
||||
accum = PERMUTE[idx & 0xff];
|
||||
}
|
||||
|
||||
R<S,U> res;
|
||||
for (size_t i = 0; i < S; ++i) {
|
||||
res[i] = PERMUTE[accum];
|
||||
res[i] /= 0xff;
|
||||
|
||||
accum = PERMUTE[(accum + i) & 0xff];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
} } }
|
@ -25,7 +25,7 @@
|
||||
#include "region.hpp"
|
||||
|
||||
|
||||
constexpr size_t S = 3;
|
||||
constexpr size_t S = 2;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template struct util::noise::fractal::fbm<S,float, util::noise::basis::perlin<S,float,util::lerp::cubic>>;
|
||||
|
Loading…
Reference in New Issue
Block a user