noise/basis: add exp weighted perlin gradient basis

useful for terrain generation
This commit is contained in:
Danny Robson 2015-09-29 17:41:04 +10:00
parent 96713038d5
commit 0f0e3a8c93
8 changed files with 245 additions and 46 deletions

View File

@ -150,6 +150,8 @@ UTIL_FILES = \
noise/basis/constant.cpp \ noise/basis/constant.cpp \
noise/basis/constant.hpp \ noise/basis/constant.hpp \
noise/basis/constant.ipp \ noise/basis/constant.ipp \
noise/basis/expdist.hpp \
noise/basis/expdist.ipp \
noise/basis/patch.hpp \ noise/basis/patch.hpp \
noise/basis/patch.ipp \ noise/basis/patch.ipp \
noise/basis/perlin.hpp \ noise/basis/perlin.hpp \

48
noise/basis/expgrad.hpp Normal file
View File

@ -0,0 +1,48 @@
/*
* 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_BASIS_EXPGRAD_HPP
#define __UTIL_NOISE_BASIS_EXPGRAD_HPP
#include "./gradient.hpp"
#include "../fwd.hpp"
#include "../../point.hpp"
#include "../../range.hpp"
namespace util { namespace noise { namespace basis {
template <typename T, lerp_t<T> L>
struct expgrad : public gradient<T,L> {
explicit expgrad <T,L> (seed_t seed, T base = (T)1.02, T exponent = T{256});
T base (void) const;
T base (T);
T exponent (void) const;
T exponent (T);
protected:
vector<2,T> generate (point<2,intmax_t>) const;
T m_base;
T m_exponent;
};
} } }
#include "expgrad.ipp"
#endif

44
noise/basis/expgrad.ipp Normal file
View File

@ -0,0 +1,44 @@
/*
* 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 2012-2015 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_NOISE_BASIS_EXPGRAD_IPP
#error
#endif
#define __UTIL_NOISE_BASIS_EXPGRAD_IPP
#include "../rand.hpp"
namespace util { namespace noise { namespace basis {
///////////////////////////////////////////////////////////////////////////
template <typename T, util::noise::lerp_t<T> L>
expgrad<T,L>::expgrad (seed_t _seed, T _base, T _exponent):
gradient<T,L> (_seed),
m_base (_base),
m_exponent (_exponent)
{ ; }
///////////////////////////////////////////////////////////////////////////
template <typename T, util::noise::lerp_t<T> L>
vector<2,T>
expgrad<T,L>::generate (point<2,intmax_t> p) const
{
auto t = (noise::rand<float> (this->seed (), p) + 1) / 2;
auto factor = std::pow (m_base, -t * m_exponent);
return factor * gradient<T,L>::generate (p);
}
} } }

44
noise/basis/gradient.hpp Normal file
View File

@ -0,0 +1,44 @@
/*
* 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 2012-2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_NOISE_BASIS_GRADIENT_HPP
#define __UTIL_NOISE_BASIS_GRADIENT_HPP
#include "../fwd.hpp"
#include "../../point.hpp"
#include "../../range.hpp"
namespace util { namespace noise { namespace basis {
/// Perlin: interpolated value across each grid space
template <typename T, lerp_t<T> L>
struct gradient {
gradient (seed_t);
seed_t seed (void) const;
seed_t seed (seed_t);
protected:
vector<2,T> generate (point<2,intmax_t>) const;
seed_t m_seed;
};
} } }
#include "gradient.ipp"
#endif

58
noise/basis/gradient.ipp Normal file
View File

@ -0,0 +1,58 @@
/*
* 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 2012-2015 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_NOISE_BASIS_GRADIENT_IPP
#error
#endif
#define __UTIL_NOISE_BASIS_GRADIENT_IPP
#include "../rand.hpp"
namespace util { namespace noise { namespace basis {
///////////////////////////////////////////////////////////////////////////
template <typename T, util::noise::lerp_t<T> L>
gradient<T,L>::gradient (seed_t _seed):
m_seed (_seed)
{ ; }
//-------------------------------------------------------------------------
template <typename T, lerp_t<T> L>
seed_t
gradient<T,L>::seed (void) const
{
return m_seed;
}
//-------------------------------------------------------------------------
template <typename T, lerp_t<T> L>
seed_t
gradient<T,L>::seed (seed_t _seed)
{
return m_seed = _seed;
}
//-------------------------------------------------------------------------
template <typename T, util::noise::lerp_t<T> L>
vector<2,T>
gradient<T,L>::generate (point<2,intmax_t> p) const
{
return noise::rand<2,T> (m_seed, p);
}
} } }

View File

@ -18,24 +18,27 @@
#ifndef __UTIL_NOISE_BASIS_PERLIN_HPP #ifndef __UTIL_NOISE_BASIS_PERLIN_HPP
#define __UTIL_NOISE_BASIS_PERLIN_HPP #define __UTIL_NOISE_BASIS_PERLIN_HPP
#include "./gradient.hpp"
#include "../fwd.hpp" #include "../fwd.hpp"
#include "../../point.hpp" #include "../../point.hpp"
#include "../../range.hpp" #include "../../range.hpp"
namespace util { namespace noise { namespace basis { namespace util { namespace noise { namespace basis {
/// Perlin: interpolated value across each grid space /// Perlin: interpolated value across each grid space
template <typename T, lerp_t<T> L> template <
struct perlin { typename T, // arithmetic and result value_type, must be floating point
lerp_t<T> L, // gradient interpolation function
template < // gradient provider class, must provide generate(point_t)
typename,
lerp_t<T>
> class G = gradient
>
struct perlin : public G<T,L> {
perlin (seed_t); perlin (seed_t);
range<T> bounds (void) const; range<T> bounds (void) const;
T operator() (point<2,T>) const; T operator() (point<2,T>) const;
seed_t seed (void) const;
seed_t seed (seed_t);
private:
seed_t m_seed;
}; };
} } } } } }

View File

@ -23,16 +23,16 @@
namespace util { namespace noise { namespace basis { namespace util { namespace noise { namespace basis {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template <typename T, util::noise::lerp_t<T> L> template <typename T, util::noise::lerp_t<T> L, template <typename,lerp_t<T>> class G>
perlin<T,L>::perlin (seed_t _seed): perlin<T,L,G>::perlin (seed_t _seed):
m_seed (_seed) G<T,L> (_seed)
{ ; } { ; }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
template <typename T, util::noise::lerp_t<T> L> template <typename T, util::noise::lerp_t<T> L, template <typename,lerp_t<T>> class G>
util::range<T> util::range<T>
perlin<T,L>::bounds (void) const perlin<T,L,G>::bounds (void) const
{ {
return { return {
-std::sqrt (T{2}) / 2, -std::sqrt (T{2}) / 2,
@ -42,27 +42,9 @@ namespace util { namespace noise { namespace basis {
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
template <typename T, lerp_t<T> L> template <typename T, util::noise::lerp_t<T> L, template <typename,lerp_t<T>> class G>
seed_t
perlin<T,L>::seed (void) const
{
return m_seed;
}
//-------------------------------------------------------------------------
template <typename T, lerp_t<T> L>
seed_t
perlin<T,L>::seed (seed_t _seed)
{
return m_seed = _seed;
}
//-------------------------------------------------------------------------
template <typename T, util::noise::lerp_t<T> L>
T T
perlin<T,L>::operator() (util::point<2,T> p) const perlin<T,L,G>::operator() (util::point<2,T> p) const
{ {
// extract integer and fractional parts. be careful to always round down // extract integer and fractional parts. be careful to always round down
// (particularly with negatives) and avoid rounding errors. // (particularly with negatives) and avoid rounding errors.
@ -78,10 +60,10 @@ namespace util { namespace noise { namespace basis {
auto p3 = p_int + util::vector<2,intmax_t> { 1, 1 }; auto p3 = p_int + util::vector<2,intmax_t> { 1, 1 };
// generate the corner gradients // generate the corner gradients
auto g0 = noise::rand<2,T> (m_seed, p0); auto g0 = G<T,L>::generate (p0);
auto g1 = noise::rand<2,T> (m_seed, p1); auto g1 = G<T,L>::generate (p1);
auto g2 = noise::rand<2,T> (m_seed, p2); auto g2 = G<T,L>::generate (p2);
auto g3 = noise::rand<2,T> (m_seed, p3); auto g3 = G<T,L>::generate (p3);
// compute the dot products // compute the dot products
T v0 = dot (g0, p - p0); T v0 = dot (g0, p - p0);

View File

@ -8,6 +8,7 @@
#include "noise/fractal/runtime.hpp" #include "noise/fractal/runtime.hpp"
#include "noise/lerp.hpp" #include "noise/lerp.hpp"
#include "noise/basis/constant.hpp" #include "noise/basis/constant.hpp"
#include "noise/basis/expgrad.hpp"
#include "noise/basis/value.hpp" #include "noise/basis/value.hpp"
#include "noise/basis/patch.hpp" #include "noise/basis/patch.hpp"
#include "noise/basis/perlin.hpp" #include "noise/basis/perlin.hpp"
@ -36,7 +37,8 @@ enum basis_t {
VALUE, VALUE,
PERLIN, PERLIN,
WORLEY, WORLEY,
PATCH PATCH,
EXPDIST
}; };
@ -66,10 +68,11 @@ operator>> (std::istream &is, basis_t &b)
std::string name; std::string name;
is >> name; is >> name;
b = name == "value" ? VALUE : b = name == "value" ? VALUE :
name == "perlin" ? PERLIN : name == "perlin" ? PERLIN :
name == "worley" ? WORLEY : name == "worley" ? WORLEY :
name == "patch" ? PATCH : name == "patch" ? PATCH :
name == "expgrad" ? EXPDIST :
(is.setstate (std::istream::failbit), b); (is.setstate (std::istream::failbit), b);
return is; return is;
@ -81,10 +84,11 @@ std::ostream&
operator<< (std::ostream &os, basis_t b) operator<< (std::ostream &os, basis_t b)
{ {
switch (b) { switch (b) {
case VALUE: os << "value"; return os; case VALUE: os << "value"; return os;
case PERLIN: os << "perlin"; return os; case PERLIN: os << "perlin"; return os;
case WORLEY: os << "worley"; return os; case WORLEY: os << "worley"; return os;
case PATCH: os << "patch"; return os; case PATCH: os << "patch"; return os;
case EXPDIST: os << "expgrad"; return os;
default: default:
unreachable (); unreachable ();
@ -268,6 +272,20 @@ main (int argc, char **argv)
break; break;
} }
case EXPDIST: {
switch (lerp) {
case LINEAR: b.reset<basis::perlin<float,util::lerp::linear,basis::expgrad>> (seed); break;
case CUBIC: b.reset<basis::perlin<float,util::lerp::cubic,basis::expgrad>> (seed); break;
case QUINTIC: b.reset<basis::perlin<float,util::lerp::quintic,basis::expgrad>> (seed); break;
case COSINE: b.reset<basis::perlin<float,util::lerp::cosine,basis::expgrad>> (seed); break;
case TRUNC: b.reset<basis::perlin<float,util::lerp::trunc,basis::expgrad>> (seed); break;
default:
unreachable ();
}
break;
}
case VALUE: { case VALUE: {
switch (lerp) { switch (lerp) {
case LINEAR: b.reset<basis::value<float,util::lerp::linear>> (seed); break; case LINEAR: b.reset<basis::value<float,util::lerp::linear>> (seed); break;