From 6278902e3ea5c499acd64d2ec23686975836df2e Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 2 Jun 2015 16:13:12 +1000 Subject: [PATCH] n/fractal: use a common base class some working variables need to be precomputed. it makes sense to do this in a base class. --- Makefile.am | 2 + noise/fractal/base.hpp | 84 ++++++++++++++++++++++++++++++++++ noise/fractal/base.ipp | 99 ++++++++++++++++++++++++++++++++++++++++ noise/fractal/fbm.hpp | 28 +++--------- noise/fractal/fbm.ipp | 65 ++++++++++++-------------- noise/fractal/hetero.hpp | 37 ++++++++------- noise/fractal/hetero.ipp | 58 +++++++++++++++-------- noise/fractal/hmf.hpp | 38 +++++++-------- noise/fractal/hmf.ipp | 55 ++++++++++++++-------- noise/fractal/rmf.hpp | 29 ++++-------- noise/fractal/rmf.ipp | 51 ++++++++++----------- tools/noise.cpp | 26 ++++++----- 12 files changed, 383 insertions(+), 189 deletions(-) create mode 100644 noise/fractal/base.hpp create mode 100644 noise/fractal/base.ipp diff --git a/Makefile.am b/Makefile.am index 340eab21..bce0fd9c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -145,6 +145,8 @@ UTIL_FILES = \ noise/basis/perlin.ipp \ noise/basis/worley.hpp \ noise/basis/worley.ipp \ + noise/fractal/base.hpp \ + noise/fractal/base.ipp \ noise/fractal/fbm.hpp \ noise/fractal/fbm.ipp \ noise/fractal/hetero.hpp \ diff --git a/noise/fractal/base.hpp b/noise/fractal/base.hpp new file mode 100644 index 00000000..6d8ae58d --- /dev/null +++ b/noise/fractal/base.hpp @@ -0,0 +1,84 @@ +/* + * 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 + */ + +#ifndef __UTIL_NOISE_FRACTAL_BASE_HPP +#define __UTIL_NOISE_FRACTAL_BASE_HPP + +#include + +#include "../../point.hpp" + +namespace util { namespace noise { namespace fractal { + /// Fractal Brownian Motion summation. + /// + /// Sum progressive layers of a noise basis with scaling frequency + /// and amplitude. + /// + /// octaves: count of layers to be summed + /// frequency: point scaling factor for the base octave + /// lacunarity: per octave frequency scaling factor + /// amplitude: maximum absolute value of the noise + /// gain: per octave amplitude scaling factor. typically 1/f. + template + struct base { + using seed_t = uint64_t; + + // constructors + base (seed_t, + unsigned octaves, + T H, + T frequency, + T lacunarity, + T amplitude, + T gain); + + // accessors + constexpr unsigned octaves (void) const; + unsigned octaves (unsigned); + + constexpr T H (void) const; + T H (T); + + constexpr T frequency (void) const; + T frequency (T); + + constexpr T lacunarity (void) const; + T lacunarity (T); + + constexpr seed_t seed (void) const; + seed_t seed (seed_t); + + protected: + unsigned m_octaves; + T m_H; + + T m_frequency; + T m_lacunarity; + + T m_amplitude; + T m_gain; + + B m_basis; + + T m_invAH; + T m_invGH; + }; +} } } + +#include "base.ipp" + +#endif + diff --git a/noise/fractal/base.ipp b/noise/fractal/base.ipp new file mode 100644 index 00000000..179ee309 --- /dev/null +++ b/noise/fractal/base.ipp @@ -0,0 +1,99 @@ +/* + * 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 + */ + +#ifdef __UTIL_NOISE_FRACTAL_BASE_IPP +#error +#endif +#define __UTIL_NOISE_FRACTAL_BASE_IPP + +#include + +namespace util { namespace noise { namespace fractal { + /////////////////////////////////////////////////////////////////////////// + template + base::base (seed_t _seed, + unsigned _octaves, + T _H, + T _frequency, + T _lacunarity, + T _amplitude, + T _gain): + // literals + m_octaves (_octaves), + m_H (_H), + m_frequency (_frequency), + m_lacunarity (_lacunarity), + m_amplitude (_amplitude), + m_gain (_gain), + // compound + m_basis (_seed), + // calculated + m_invAH (std::pow (_amplitude, -_H)), + m_invGH (std::pow (_gain, _H)) + { + CHECK_NEQ (m_octaves, 0); + CHECK_NEQ (m_frequency, 0); + CHECK_NEQ (m_amplitude, 0); + } + + + /////////////////////////////////////////////////////////////////////////// + template + unsigned + base::octaves (unsigned _octaves) + { + return m_octaves = _octaves; + } + + + //------------------------------------------------------------------------- + template + T + base::H (T _h) + { + m_H = _h; + m_invAH = std::pow (m_amplitude, -m_H); + m_invGH = std::pow (m_gain, m_H); + return H; + } + + + //------------------------------------------------------------------------- + template + T + base::frequency (T _frequency) + { + return m_frequency = _frequency; + } + + + //------------------------------------------------------------------------- + template + T + base::lacunarity (T _lacunarity) + { + return m_lacunarity = _lacunarity; + } + + + //------------------------------------------------------------------------- + //template + //typename base::seed_t + //base::seed (seed_t _seed) + //{ + // return basis.seed (_seed); + //} +} } } diff --git a/noise/fractal/fbm.hpp b/noise/fractal/fbm.hpp index bb1ca7aa..9ead4977 100644 --- a/noise/fractal/fbm.hpp +++ b/noise/fractal/fbm.hpp @@ -19,6 +19,7 @@ #include +#include "base.hpp" #include "../../point.hpp" namespace util { namespace noise { namespace fractal { @@ -33,8 +34,8 @@ namespace util { namespace noise { namespace fractal { /// amplitude: maximum absolute value of the noise /// gain: per octave amplitude scaling factor. typically 1/f. template - struct fbm { - using seed_t = uint64_t; + struct fbm : public base { + using seed_t = typename base::seed_t; static constexpr unsigned DEFAULT_OCTAVES = 8; static constexpr T DEFAULT_H = 1; @@ -43,31 +44,16 @@ namespace util { namespace noise { namespace fractal { static constexpr T DEFAULT_AMPLITUDE = 1; static constexpr T DEFAULT_GAIN = 1 / DEFAULT_LACUNARITY; - fbm (unsigned octaves, + fbm (seed_t seed, + unsigned octaves, T H, T frequency, T lacunarity, T amplitude, - T gain, - seed_t seed); - fbm (); + T gain); + fbm (seed_t); - seed_t seed; - unsigned octaves; - T H; - - T frequency; - T lacunarity; - - T amplitude; - T gain; - - 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 2a13fd72..8302b61a 100644 --- a/noise/fractal/fbm.ipp +++ b/noise/fractal/fbm.ipp @@ -24,57 +24,50 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// template - fbm::fbm (unsigned _octaves, + fbm::fbm (seed_t _seed, + unsigned _octaves, T _H, T _frequency, T _lacunarity, T _amplitude, - T _gain, - seed_t _seed): - seed (_seed), - octaves (_octaves), - H (_H), - frequency (_frequency), - lacunarity (_lacunarity), - amplitude (_amplitude), - gain (_gain), - basis (_seed), - invAH (std::pow (amplitude, -H)), - invGH (std::pow (gain, H)) - { - CHECK_NEQ (octaves, 0); - CHECK_NEQ (frequency, 0); - CHECK_NEQ (amplitude, 0); - } - - - //------------------------------------------------------------------------- - template - fbm::fbm (): - fbm (DEFAULT_OCTAVES, - DEFAULT_H, - DEFAULT_FREQUENCY, - DEFAULT_LACUNARITY, - DEFAULT_AMPLITUDE, - DEFAULT_GAIN, - rand ()) + T _gain): + base (_seed, + _octaves, + _H, + _frequency, + _lacunarity, + _amplitude, + _gain) { ; } //------------------------------------------------------------------------- template + fbm::fbm (seed_t _seed): + fbm (_seed, + DEFAULT_OCTAVES, + DEFAULT_H, + DEFAULT_FREQUENCY, + DEFAULT_LACUNARITY, + DEFAULT_AMPLITUDE, + DEFAULT_GAIN) + { ; } + + + /////////////////////////////////////////////////////////////////////////// + template constexpr T fbm::operator() (util::point<2,T> p) const { T total = 0; - T f = frequency; - T a = invAH; + T f = this->m_frequency; + T a = this->m_invAH; - for (size_t i = 0; i < octaves; ++i) { - total += basis (p * f) * a; + for (size_t i = 0; i < this->m_octaves; ++i) { + total += this->m_basis (p * f) * a; - f *= lacunarity; - a *= invGH; + f *= this->m_lacunarity; + a *= this->m_invGH; } return total; diff --git a/noise/fractal/hetero.hpp b/noise/fractal/hetero.hpp index d8955881..a6610f5b 100644 --- a/noise/fractal/hetero.hpp +++ b/noise/fractal/hetero.hpp @@ -19,36 +19,39 @@ #include +#include "base.hpp" #include "../../point.hpp" namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////// /// Heterogeneous procedural terrain fucntion: stats by altitude method template - struct hetero { - using seed_t = uint64_t; + struct hetero : public base { + using seed_t = typename base::seed_t; - hetero (); + static constexpr T DEFAULT_H = T(0.75); + static constexpr T DEFAULT_OCTAVES = 6; + 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; + static constexpr T DEFAULT_OFFSET = T(0.7); - seed_t seed; - T H; - unsigned octaves; + hetero (seed_t, + unsigned octaves, + T H, + T frequency, + T lacunarity, + T amplitude, + T gain, + T offset); - T frequency; - T lacunarity; - - T offset; - - T amplitude; - T gain; - - B basis; + hetero (seed_t); constexpr T operator() (util::point<2,T>) const; private: - T invAH; - T invGH; + T m_offset; }; } } } diff --git a/noise/fractal/hetero.ipp b/noise/fractal/hetero.ipp index f0817ab3..35168cfe 100644 --- a/noise/fractal/hetero.ipp +++ b/noise/fractal/hetero.ipp @@ -20,44 +20,64 @@ #define __UTIL_NOISE_FRACTAL_HETERO_IPP namespace util { namespace noise { namespace fractal { - //------------------------------------------------------------------------- + /////////////////////////////////////////////////////////////////////////// template - hetero::hetero(): - H (0.75f), - octaves (6), - frequency (0.1f), - lacunarity (2), - offset (0.7f), - amplitude (1), - gain (1/lacunarity), - invAH (std::pow (amplitude, -H)), - invGH (std::pow (gain, H)) + hetero::hetero(seed_t _seed, + unsigned _octaves, + T _H, + T _frequency, + T _lacunarity, + T _amplitude, + T _gain, + T _offset): + base (_seed, + _octaves, + _H, + _frequency, + _lacunarity, + _amplitude, + _gain), + m_offset (_offset) { ; } //------------------------------------------------------------------------- template + hetero::hetero (seed_t _seed): + hetero (_seed, + DEFAULT_OCTAVES, + DEFAULT_H, + DEFAULT_FREQUENCY, + DEFAULT_LACUNARITY, + DEFAULT_AMPLITUDE, + DEFAULT_GAIN, + DEFAULT_OFFSET) + { ; } + + + /////////////////////////////////////////////////////////////////////////// + template constexpr T hetero::operator() (util::point<2,T> p) const { - T scale = invAH; + T scale = this->m_invAH; - p *= frequency; - T result = (basis (p) + offset) * scale; - p *= lacunarity; + p *= this->m_frequency; + T result = (this->m_basis (p) + m_offset) * scale; + p *= this->m_lacunarity; T increment = 0; - for (size_t i = 1; i < octaves; ++i) { - scale *= invGH; + for (size_t i = 1; i < this->m_octaves; ++i) { + scale *= this->m_invGH; - increment = basis (p) + offset; + increment = this->m_basis (p) + m_offset; increment *= scale; increment *= result; result += increment; - p *= lacunarity; + p *= this->m_lacunarity; } return result; diff --git a/noise/fractal/hmf.hpp b/noise/fractal/hmf.hpp index 465d27af..b1daaee1 100644 --- a/noise/fractal/hmf.hpp +++ b/noise/fractal/hmf.hpp @@ -25,31 +25,33 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////// /// Musgrave's "Hybrid MultiFractal" template - struct hmf { - using seed_t = uint64_t; + struct hmf : public base { + using seed_t = typename base::seed_t; - hmf (); + // H should be fairly low due to the decreasing weight parameter in eval + static constexpr unsigned DEFAULT_OCTAVES = 6; + static constexpr T DEFAULT_H = T(0.25); + 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; + static constexpr T DEFAULT_OFFSET = T(0.7); - seed_t seed; + hmf (seed_t, + unsigned octaves, + T H, + T frequency, + T lacunarity, + T amplitude, + T gain, + T offset); - T H; - unsigned octaves; - - T frequency; - T lacunarity; - - T offset; - - T amplitude; - T gain; - - B basis; + hmf (seed_t); constexpr T operator() (point<2,T>) const; private: - T invAH; - T invGH; + T m_offset; }; } } } diff --git a/noise/fractal/hmf.ipp b/noise/fractal/hmf.ipp index 645fefa6..c17352ad 100644 --- a/noise/fractal/hmf.ipp +++ b/noise/fractal/hmf.ipp @@ -21,44 +21,63 @@ 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), - octaves (6), - frequency (0.1f), - lacunarity (2), - offset (0.7f), - amplitude (1), - gain (1 / lacunarity), - invAH (std::pow (amplitude, -H)), - invGH (std::pow (gain, H)) + hmf::hmf (seed_t _seed, + unsigned _octaves, + T _H, + T _frequency, + T _lacunarity, + T _amplitude, + T _gain, + T _offset): + base (_seed, + _octaves, + _H, + _frequency, + _lacunarity, + _amplitude, + _gain), + m_offset (_offset) { ; } //------------------------------------------------------------------------- template + hmf::hmf (seed_t _seed): + hmf (_seed, + DEFAULT_OCTAVES, + DEFAULT_H, + DEFAULT_FREQUENCY, + DEFAULT_LACUNARITY, + DEFAULT_AMPLITUDE, + DEFAULT_GAIN, + DEFAULT_OFFSET) + { ; } + + + /////////////////////////////////////////////////////////////////////////// + template constexpr T hmf::operator() (util::point<2,T> p) const { - T scale = invAH; + T scale = this->m_invAH; T result = 0; T signal = 0; T weight = 1; - p *= frequency; + p *= this->m_frequency; - for (size_t i = 0; i < octaves; ++i) { - signal = (basis (p) + offset) * scale; + for (size_t i = 0; i < this->m_octaves; ++i) { + signal = (this->m_basis (p) + m_offset) * scale; result += signal * weight; weight *= signal; weight = min (weight, T{1}); - scale *= invGH; - p *= lacunarity; + scale *= this->m_invGH; + p *= this->m_lacunarity; } return result; diff --git a/noise/fractal/rmf.hpp b/noise/fractal/rmf.hpp index e453ec93..ce8299da 100644 --- a/noise/fractal/rmf.hpp +++ b/noise/fractal/rmf.hpp @@ -19,6 +19,7 @@ #include +#include "base.hpp" #include "../../point.hpp" namespace util { namespace noise { namespace fractal { @@ -32,8 +33,8 @@ namespace util { namespace noise { namespace fractal { /// amplitude: value scaling factor for the base octave /// gain: incremental octave value scaling factor template - struct rmf { - using seed_t = uint64_t; + struct rmf : public base { + using seed_t = typename base::seed_t; static constexpr unsigned DEFAULT_OCTAVES = 5; static constexpr T DEFAULT_H = 1; @@ -43,35 +44,21 @@ namespace util { namespace noise { namespace fractal { static constexpr T DEFAULT_AMPLITUDE = 2; static constexpr T DEFAULT_GAIN = 1 / DEFAULT_LACUNARITY; - rmf (unsigned octaves, + rmf (seed_t, + unsigned octaves, T H, - T offset, T frequency, T lacunarity, T amplitude, T gain, - seed_t seed); - rmf (); + T offset); - seed_t seed; - - unsigned octaves; - T H; - T offset; - - T frequency; - T lacunarity; - - T amplitude; - T gain; - - B basis; + rmf (seed_t); constexpr T operator() (util::point<2,T>) const; private: - T invAH; - T invGH; + T m_offset; }; } } } diff --git a/noise/fractal/rmf.ipp b/noise/fractal/rmf.ipp index cb930209..a9bef006 100644 --- a/noise/fractal/rmf.ipp +++ b/noise/fractal/rmf.ipp @@ -23,62 +23,59 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// template - rmf::rmf (unsigned _octaves, + rmf::rmf (seed_t _seed, + unsigned _octaves, 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), - invAH (std::pow (amplitude, -H)), - invGH (std::pow (gain, H)) + T _gain): + base (_seed, + _octaves, + _H, + _frequency, + _lacunarity, + _amplitude, + _gain), + m_offset (_offset) { ; } //------------------------------------------------------------------------- template - rmf::rmf (): - rmf (DEFAULT_OCTAVES, + rmf::rmf (seed_t _seed): + rmf (_seed, + DEFAULT_OCTAVES, DEFAULT_H, - DEFAULT_OFFSET, DEFAULT_FREQUENCY, DEFAULT_LACUNARITY, DEFAULT_AMPLITUDE, DEFAULT_GAIN, - rand ()) + DEFAULT_OFFSET) { ; } - //------------------------------------------------------------------------- + /////////////////////////////////////////////////////////////////////////// // 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 { - T scale = invAH; + T scale = this->m_invAH; T signal = 0; T result = 0; T weight = 1; - p *= frequency; + p *= this->m_frequency; - for (size_t i = 0; i < octaves; ++i) { + for (size_t i = 0; i < this->m_octaves; ++i) { // generates ridged noise - signal = basis (p); + signal = this->m_basis (p); signal = std::fabs (signal); - signal = offset - signal; + signal = m_offset - signal; // sharpens the ridges signal *= signal; @@ -87,14 +84,14 @@ namespace util { namespace noise { namespace fractal { signal *= weight; // contribute to the weight - weight = signal * amplitude; + weight = signal * this->m_amplitude; weight = limit (weight, 0, 1); // record and continue result += signal * scale; - scale *= invGH; - p *= lacunarity; + scale *= this->m_invGH; + p *= this->m_lacunarity; } return result; diff --git a/tools/noise.cpp b/tools/noise.cpp index 4a00bc83..1fb06b63 100644 --- a/tools/noise.cpp +++ b/tools/noise.cpp @@ -25,19 +25,21 @@ main (void) util::extent2u size {1920, 1080}; util::image::buffer img (size); - // setup the noise generator - //util::noise::fractal::fbm> b; - //util::noise::fractal::rmf> b; - //util::noise::fractal::fbm> b; - //util::noise::fractal::rmf> b; - util::noise::fractal::hmf> b; - //util::noise::fractal::hetero> b; + uint64_t seed = time (nullptr); - b.octaves = 8; - b.frequency = 10.f / size.w; - b.lacunarity = 2.f; - //b.H = 0.75f; - b.basis.seed = time (NULL); + // setup the noise generator + util::noise::fractal::fbm> b (seed); + //util::noise::fractal::rmf> b (seed); + //util::noise::fractal::fbm> b (seed); + //util::noise::fractal::rmf> b (seed); + //util::noise::fractal::hmf> b (seed); + //util::noise::fractal::hetero> b (seed); + + b.octaves (8); + b.frequency (10.f / size.w); + //b.lacunarity = 2.f; + //b.H = 1.0f; + //b.basis.seed = time (NULL); // generate the values. offset positions slightly to avoid simple axis issues with perlin basis {