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/midpoint.hpp \
|
||||||
noise/rand.hpp \
|
noise/rand.hpp \
|
||||||
noise/rand.ipp \
|
noise/rand.ipp \
|
||||||
|
noise/rand/hash.hpp \
|
||||||
|
noise/rand/hash.ipp \
|
||||||
|
noise/rand/permute.cpp \
|
||||||
|
noise/rand/permute.hpp \
|
||||||
noise/turbulence.hpp \
|
noise/turbulence.hpp \
|
||||||
noise/turbulence.ipp \
|
noise/turbulence.ipp \
|
||||||
pascal.cpp \
|
pascal.cpp \
|
||||||
|
@ -38,7 +38,7 @@ namespace util { namespace noise { namespace basis {
|
|||||||
vector<S,T>
|
vector<S,T>
|
||||||
expgrad<S,T,L>::generate (pointi<S> p) const
|
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);
|
auto factor = std::pow (m_base, -t * m_exponent);
|
||||||
return factor * gradient<S,T,L>::generate (p);
|
return factor * gradient<S,T,L>::generate (p);
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ namespace util { namespace noise { namespace basis {
|
|||||||
vector<S,T>
|
vector<S,T>
|
||||||
gradient<S,T,L>::generate (pointi<S> p) const
|
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::transform (std::begin (this->OFFSETS),
|
||||||
std::end (this->OFFSETS),
|
std::end (this->OFFSETS),
|
||||||
std::begin (centres),
|
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];
|
T distances[COUNT];
|
||||||
std::transform (std::begin (centres),
|
std::transform (std::begin (centres),
|
||||||
@ -96,7 +96,7 @@ namespace util { namespace noise { namespace basis {
|
|||||||
// to blend.
|
// to blend.
|
||||||
for (size_t i = 0; i < hi_off; ++i)
|
for (size_t i = 0; i < hi_off; ++i)
|
||||||
{
|
{
|
||||||
auto v = util::noise::rand<T> (
|
auto v = rand::scalar<T> (
|
||||||
m_seed,
|
m_seed,
|
||||||
p_int + this->OFFSETS[indices[i]]
|
p_int + this->OFFSETS[indices[i]]
|
||||||
);
|
);
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#define __UTIL_NOISE_BASIS_PERLIN_IPP
|
#define __UTIL_NOISE_BASIS_PERLIN_IPP
|
||||||
|
|
||||||
#include "../rand.hpp"
|
|
||||||
#include "../../types.hpp"
|
#include "../../types.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ namespace util { namespace noise { namespace basis {
|
|||||||
std::array<T,pow(2,S)> g_;
|
std::array<T,pow(2,S)> g_;
|
||||||
std::transform (std::begin (p_), std::end (p_),
|
std::transform (std::begin (p_), std::end (p_),
|
||||||
std::begin (g_),
|
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.
|
// Interpolate on one dimension, then the other.
|
||||||
T l_[pow(2,S)];
|
T l_[pow(2,S)];
|
||||||
|
@ -91,6 +91,6 @@ namespace util { namespace noise { namespace basis {
|
|||||||
point<S,T>
|
point<S,T>
|
||||||
worley<S,T,F>::generate (point<S,intmax_t> p) const
|
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
|
// do the centre
|
||||||
{
|
{
|
||||||
const auto avg = (v0 + v1 + v2 + v3) / 4;
|
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;
|
const auto pos = target.p + target.e / 2;
|
||||||
|
|
||||||
img[pos] = val;
|
img[pos] = val * 2 - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// average the sides
|
// 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 p32 = target.p + util::vector2u{w/2, h-1};
|
||||||
const auto p20 = target.p + util::vector2u{0, h/2};
|
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 v01 = (v0 + v1) / 2 + sides * scale * util::noise::rand::scalar<T> (seed, p01);
|
||||||
const auto v13 = (v1 + v3) / 2 + sides * scale * util::noise::rand<T> (seed, p13);
|
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<T> (seed, p32);
|
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<T> (seed, p20);
|
const auto v20 = (v2 + v0) / 2 + sides * scale * util::noise::rand::scalar<T> (seed, p20);
|
||||||
|
|
||||||
img[p01] = v01;
|
img[p01] = v01 * 2 - 1;
|
||||||
img[p13] = v13;
|
img[p13] = v13 * 2 - 1;
|
||||||
img[p32] = v32;
|
img[p32] = v32 * 2 - 1;
|
||||||
img[p20] = v20;
|
img[p20] = v20 * 2 - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// recurse
|
// recurse
|
||||||
@ -109,7 +109,7 @@ util::noise::midpoint (image::buffer<T> &img, uint64_t seed, float persistence,
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (auto i: CORNERS)
|
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);
|
fill (img, seed, { { 0, 0 }, img.extent () }, 1.f, persistence, sides);
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,11 @@
|
|||||||
#ifndef __UTIL_NOISE_RAND_HPP
|
#ifndef __UTIL_NOISE_RAND_HPP
|
||||||
#define __UTIL_NOISE_RAND_HPP
|
#define __UTIL_NOISE_RAND_HPP
|
||||||
|
|
||||||
namespace util { namespace noise {
|
#include "./rand/permute.hpp"
|
||||||
/// generate a uniform random floating point in the range [-1, 1] from a seed and vector
|
#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 <
|
template <
|
||||||
typename U,
|
typename U,
|
||||||
size_t S,
|
size_t S,
|
||||||
@ -26,8 +29,16 @@ namespace util { namespace noise {
|
|||||||
template <size_t,typename> class Q
|
template <size_t,typename> class Q
|
||||||
>
|
>
|
||||||
U
|
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 <
|
||||||
template <size_t,typename> class R,
|
template <size_t,typename> class R,
|
||||||
typename U,
|
typename U,
|
||||||
@ -36,9 +47,14 @@ namespace util { namespace noise {
|
|||||||
template <size_t,typename> class Q
|
template <size_t,typename> class Q
|
||||||
>
|
>
|
||||||
R<S,U>
|
R<S,U>
|
||||||
rand (uint64_t seed, Q<S,T> value);
|
coord (uint64_t seed, Q<S,T> value)
|
||||||
} }
|
{
|
||||||
|
#if 1
|
||||||
#include "rand.ipp"
|
return permute::coord<R,U,S,T,Q> (seed, value);
|
||||||
|
#else
|
||||||
|
return hash::coord<R,U,S,T,Q> (seed, value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} } }
|
||||||
|
|
||||||
#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
|
#error
|
||||||
#endif
|
#endif
|
||||||
#define __UTIL_NOISE_RAND_IPP
|
|
||||||
|
|
||||||
#include "../hash/murmur/murmur2.hpp"
|
#define __UTIL_NOISE_RAND_HASH_IPP
|
||||||
|
|
||||||
|
namespace util { namespace noise { namespace rand {
|
||||||
namespace util { namespace noise {
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
template <
|
template <
|
||||||
typename U,
|
typename U,
|
||||||
@ -32,21 +30,17 @@ namespace util { namespace noise {
|
|||||||
template <size_t,typename> class Q
|
template <size_t,typename> class Q
|
||||||
>
|
>
|
||||||
U
|
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,
|
static_assert (std::is_integral<T>::value,
|
||||||
"mixing only works on integral types");
|
"mixing only works on integral types");
|
||||||
|
|
||||||
uint64_t accum = seed;
|
uint64_t accum = seed;
|
||||||
for (auto i: query)
|
for (auto i: query)
|
||||||
accum = hash::murmur2::mix (accum, i);
|
accum = util::hash::murmur2::mix (accum, i);
|
||||||
|
|
||||||
U result = (accum & 0xFFFF) / U{0xFFFF};
|
return (accum & BITS) / U{BITS};
|
||||||
|
|
||||||
result *= 2;
|
|
||||||
result -= 1;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -59,18 +53,22 @@ namespace util { namespace noise {
|
|||||||
template <size_t,typename> class Q
|
template <size_t,typename> class Q
|
||||||
>
|
>
|
||||||
R<S,U>
|
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)
|
for (auto i: query)
|
||||||
accum = hash::murmur2::mix (accum, i);
|
accum = util::hash::murmur2::mix (accum, i);
|
||||||
|
|
||||||
R<S,U> result;
|
R<S,U> result;
|
||||||
for (auto &i: result) {
|
for (auto &i: result) {
|
||||||
i = (accum & 0xFFFF) / U{0xFFFF};
|
i = (accum & BITS);
|
||||||
accum = hash::murmur2::mix (accum, seed);
|
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"
|
#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>>;
|
template struct util::noise::fractal::fbm<S,float, util::noise::basis::perlin<S,float,util::lerp::cubic>>;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user