From bc1c576297a78e7ff43359ad1579aa0caf2108a1 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 2 Jun 2015 00:15:02 +1000 Subject: [PATCH] n/fractal: use hurst parameters consistently --- noise/fractal/fbm.hpp | 17 ++++++++++++----- noise/fractal/fbm.ipp | 11 ++++++++--- noise/fractal/hetero.hpp | 4 ++++ noise/fractal/hetero.ipp | 21 +++++++++++---------- noise/fractal/hmf.hpp | 7 ++++++- noise/fractal/hmf.ipp | 19 ++++++++++--------- noise/fractal/rmf.hpp | 24 ++++++++++++++++++++---- noise/fractal/rmf.ipp | 34 ++++++++++++++++++++-------------- 8 files changed, 91 insertions(+), 46 deletions(-) diff --git a/noise/fractal/fbm.hpp b/noise/fractal/fbm.hpp index 6c370e24..bb1ca7aa 100644 --- a/noise/fractal/fbm.hpp +++ b/noise/fractal/fbm.hpp @@ -36,13 +36,15 @@ namespace util { namespace noise { namespace fractal { struct fbm { using seed_t = uint64_t; - static constexpr unsigned DEFAULT_OCTAVES = 8; - static constexpr T DEFAULT_FREQUENCY = T(0.1); - static constexpr T DEFAULT_LACUNARITY = 2; - static constexpr T DEFAULT_AMPLITUDE = 1; - static constexpr T DEFAULT_GAIN = 1 / T(2); + static constexpr unsigned DEFAULT_OCTAVES = 8; + static constexpr T DEFAULT_H = 1; + static constexpr T DEFAULT_FREQUENCY = T(0.1); + static constexpr T DEFAULT_LACUNARITY = 2; + static constexpr T DEFAULT_AMPLITUDE = 1; + static constexpr T DEFAULT_GAIN = 1 / DEFAULT_LACUNARITY; fbm (unsigned octaves, + T H, T frequency, T lacunarity, T amplitude, @@ -52,6 +54,7 @@ namespace util { namespace noise { namespace fractal { seed_t seed; unsigned octaves; + T H; T frequency; T lacunarity; @@ -61,6 +64,10 @@ namespace util { namespace noise { namespace fractal { B basis; constexpr T operator() (util::point<2,T>) const; + + private: + T invAH; + T invGH; }; } } } diff --git a/noise/fractal/fbm.ipp b/noise/fractal/fbm.ipp index 8a81f3bd..2a13fd72 100644 --- a/noise/fractal/fbm.ipp +++ b/noise/fractal/fbm.ipp @@ -25,6 +25,7 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// template fbm::fbm (unsigned _octaves, + T _H, T _frequency, T _lacunarity, T _amplitude, @@ -32,11 +33,14 @@ namespace util { namespace noise { namespace fractal { seed_t _seed): seed (_seed), octaves (_octaves), + H (_H), frequency (_frequency), lacunarity (_lacunarity), amplitude (_amplitude), gain (_gain), - basis (_seed) + basis (_seed), + invAH (std::pow (amplitude, -H)), + invGH (std::pow (gain, H)) { CHECK_NEQ (octaves, 0); CHECK_NEQ (frequency, 0); @@ -48,6 +52,7 @@ namespace util { namespace noise { namespace fractal { template fbm::fbm (): fbm (DEFAULT_OCTAVES, + DEFAULT_H, DEFAULT_FREQUENCY, DEFAULT_LACUNARITY, DEFAULT_AMPLITUDE, @@ -63,13 +68,13 @@ namespace util { namespace noise { namespace fractal { { T total = 0; T f = frequency; - T a = amplitude; + T a = invAH; for (size_t i = 0; i < octaves; ++i) { total += basis (p * f) * a; f *= lacunarity; - a *= gain; + a *= invGH; } return total; diff --git a/noise/fractal/hetero.hpp b/noise/fractal/hetero.hpp index bc238e89..d8955881 100644 --- a/noise/fractal/hetero.hpp +++ b/noise/fractal/hetero.hpp @@ -45,6 +45,10 @@ namespace util { namespace noise { namespace fractal { B basis; constexpr T operator() (util::point<2,T>) const; + + private: + T invAH; + T invGH; }; } } } diff --git a/noise/fractal/hetero.ipp b/noise/fractal/hetero.ipp index a0928de3..f0817ab3 100644 --- a/noise/fractal/hetero.ipp +++ b/noise/fractal/hetero.ipp @@ -29,7 +29,9 @@ namespace util { namespace noise { namespace fractal { lacunarity (2), offset (0.7f), amplitude (1), - gain (1) + gain (1/lacunarity), + invAH (std::pow (amplitude, -H)), + invGH (std::pow (gain, H)) { ; } @@ -38,20 +40,19 @@ namespace util { namespace noise { namespace fractal { constexpr T hetero::operator() (util::point<2,T> p) const { - T exponents[octaves]; - for (size_t i = 0; i < octaves; ++i) - exponents[i] = std::pow (std::pow (lacunarity, float (i)), -H); - - T result = 0; - T increment = 0; + T scale = invAH; p *= frequency; - result = basis (p) + offset; + T result = (basis (p) + offset) * scale; p *= lacunarity; - for (size_t i = 0; i < octaves; ++i) { + T increment = 0; + + for (size_t i = 1; i < octaves; ++i) { + scale *= invGH; + increment = basis (p) + offset; - increment *= exponents[i]; + increment *= scale; increment *= result; result += increment; diff --git a/noise/fractal/hmf.hpp b/noise/fractal/hmf.hpp index 1b627f41..465d27af 100644 --- a/noise/fractal/hmf.hpp +++ b/noise/fractal/hmf.hpp @@ -23,6 +23,7 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////// + /// Musgrave's "Hybrid MultiFractal" template struct hmf { using seed_t = uint64_t; @@ -44,7 +45,11 @@ namespace util { namespace noise { namespace fractal { B basis; - constexpr T operator() (util::point<2,T>) const; + constexpr T operator() (point<2,T>) const; + + private: + T invAH; + T invGH; }; } } } diff --git a/noise/fractal/hmf.ipp b/noise/fractal/hmf.ipp index 3b623ea4..645fefa6 100644 --- a/noise/fractal/hmf.ipp +++ b/noise/fractal/hmf.ipp @@ -22,6 +22,7 @@ namespace util { namespace noise { namespace fractal { //------------------------------------------------------------------------- + // H should be fairly low due to the decreasing weight parameter in eval template hmf::hmf (): H (0.25f), @@ -30,7 +31,9 @@ namespace util { namespace noise { namespace fractal { lacunarity (2), offset (0.7f), amplitude (1), - gain (1) + gain (1 / lacunarity), + invAH (std::pow (amplitude, -H)), + invGH (std::pow (gain, H)) { ; } @@ -39,9 +42,7 @@ namespace util { namespace noise { namespace fractal { constexpr T hmf::operator() (util::point<2,T> p) const { - T exponents[octaves]; - for (size_t i = 0; i < octaves; ++i) - exponents[i] = std::pow (std::pow (lacunarity, float (i)), -H); + T scale = invAH; T result = 0; T signal = 0; @@ -50,13 +51,13 @@ namespace util { namespace noise { namespace fractal { p *= frequency; for (size_t i = 0; i < octaves; ++i) { - signal = (basis (p) + offset) * exponents[i]; - result += weight * signal; + signal = (basis (p) + offset) * scale; + result += signal * weight; - weight *= gain * signal; - if (weight > 1) - weight = 1; + weight *= signal; + weight = min (weight, T{1}); + scale *= invGH; p *= lacunarity; } diff --git a/noise/fractal/rmf.hpp b/noise/fractal/rmf.hpp index 90c11d95..e453ec93 100644 --- a/noise/fractal/rmf.hpp +++ b/noise/fractal/rmf.hpp @@ -25,19 +25,27 @@ namespace util { namespace noise { namespace fractal { /// Rigid Multifractal summation, based on Musgrave's algorithm /// /// octaves: count of layers to be summed + /// H: hurst parameter (~roughness) + /// offset: TODO /// frequency: point scaling factor for the base octave - /// lacunarity: per octave frequency scaling factor + /// lacunarity: incremental octave frequency scaling factor + /// amplitude: value scaling factor for the base octave + /// gain: incremental octave value scaling factor template struct rmf { using seed_t = uint64_t; static constexpr unsigned DEFAULT_OCTAVES = 5; - static constexpr T DEFAULT_FREQUENCY = T(1); + static constexpr T DEFAULT_H = 1; + static constexpr T DEFAULT_OFFSET = 1; + static constexpr T DEFAULT_FREQUENCY = 1; static constexpr T DEFAULT_LACUNARITY = 2; - static constexpr T DEFAULT_AMPLITUDE = 1; - static constexpr T DEFAULT_GAIN = 2; + static constexpr T DEFAULT_AMPLITUDE = 2; + static constexpr T DEFAULT_GAIN = 1 / DEFAULT_LACUNARITY; rmf (unsigned octaves, + T H, + T offset, T frequency, T lacunarity, T amplitude, @@ -46,7 +54,10 @@ namespace util { namespace noise { namespace fractal { rmf (); seed_t seed; + unsigned octaves; + T H; + T offset; T frequency; T lacunarity; @@ -55,7 +66,12 @@ namespace util { namespace noise { namespace fractal { T gain; B basis; + constexpr T operator() (util::point<2,T>) const; + + private: + T invAH; + T invGH; }; } } } diff --git a/noise/fractal/rmf.ipp b/noise/fractal/rmf.ipp index f8f1c87c..cb930209 100644 --- a/noise/fractal/rmf.ipp +++ b/noise/fractal/rmf.ipp @@ -24,18 +24,24 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// template rmf::rmf (unsigned _octaves, - T _frequency, - T _lacunarity, - T _amplitude, - T _gain, - seed_t _seed): + T _H, + T _offset, + T _frequency, + T _lacunarity, + T _amplitude, + T _gain, + seed_t _seed): seed (_seed), octaves (_octaves), + H (_H), + offset (_offset), frequency (_frequency), lacunarity (_lacunarity), amplitude (_amplitude), gain (_gain), - basis (_seed) + basis (_seed), + invAH (std::pow (amplitude, -H)), + invGH (std::pow (gain, H)) { ; } @@ -43,6 +49,8 @@ namespace util { namespace noise { namespace fractal { template rmf::rmf (): rmf (DEFAULT_OCTAVES, + DEFAULT_H, + DEFAULT_OFFSET, DEFAULT_FREQUENCY, DEFAULT_LACUNARITY, DEFAULT_AMPLITUDE, @@ -52,16 +60,13 @@ namespace util { namespace noise { namespace fractal { //------------------------------------------------------------------------- + // we use the name 'amplitude' instead of musgrave's 'gain'. + // assumes basis distribution [-1,1] and offset ~= 1 template constexpr T rmf::operator() (util::point<2,T> p) const { - const T offset = 1; - const T H = 1.f; - - T exponents[octaves]; - for (size_t i = 0; i < octaves; ++i) - exponents[i] = std::pow (std::pow (lacunarity, float (i)), -H); + T scale = invAH; T signal = 0; T result = 0; @@ -82,12 +87,13 @@ namespace util { namespace noise { namespace fractal { signal *= weight; // contribute to the weight - weight = signal * gain; + weight = signal * amplitude; weight = limit (weight, 0, 1); // record and continue - result += signal * exponents[i]; + result += signal * scale; + scale *= invGH; p *= lacunarity; }