n/basis: fix integer position extract when -ve
This commit is contained in:
parent
3a8179dfff
commit
b4ddd287bf
@ -24,7 +24,7 @@ using util::noise::basis::perlin;
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <typename T>
|
template <typename T>
|
||||||
util::vector<2,T>
|
util::vector<2,T>
|
||||||
generate (util::point<2,T> p, uint64_t seed)
|
generate (util::point<2,intmax_t> p, uint64_t seed)
|
||||||
{
|
{
|
||||||
using util::hash::murmur2::mix;
|
using util::hash::murmur2::mix;
|
||||||
|
|
||||||
@ -75,31 +75,36 @@ template <typename T, util::noise::lerp_t<T> L>
|
|||||||
T
|
T
|
||||||
perlin<T,L>::operator() (util::point<2,T> p) const
|
perlin<T,L>::operator() (util::point<2,T> p) const
|
||||||
{
|
{
|
||||||
|
// extract integer and fractional parts. be careful to always round down
|
||||||
|
// (particularly with negatives) and avoid rounding errors.
|
||||||
auto p_int = p.template cast<intmax_t> ();
|
auto p_int = p.template cast<intmax_t> ();
|
||||||
auto p_rem = p - p_int;
|
if (p.x < 0) p_int.x -= 1;
|
||||||
|
if (p.y < 0) p_int.y -= 1;
|
||||||
|
auto p_rem = abs (p - p_int);
|
||||||
|
|
||||||
// Shift the coordinate system down a little to ensure we get unit weights
|
// generate the corner positions
|
||||||
// for the lerp. It's better to do this than abs the fractional portion so
|
auto p0 = p_int + util::vector<2,intmax_t> { 0, 0 };
|
||||||
// we don't get reflections along the origin.
|
auto p1 = p_int + util::vector<2,intmax_t> { 1, 0 };
|
||||||
if (p.x < 0) { p_rem.x = 1 + p_rem.x; p_int.x -= 1; }
|
auto p2 = p_int + util::vector<2,intmax_t> { 0, 1 };
|
||||||
if (p.y < 0) { p_rem.y = 1 + p_rem.y; p_int.y -= 1; }
|
auto p3 = p_int + util::vector<2,intmax_t> { 1, 1 };
|
||||||
|
|
||||||
// Generate the four corner values. It's not strictly necessary to
|
// generate the corner gradients
|
||||||
// normalise the values, but we get a more consistent and visually
|
auto g0 = generate<T> (p0, this->seed);
|
||||||
// appealing range of outputs with normalised values.
|
auto g1 = generate<T> (p1, this->seed);
|
||||||
auto p0 = generate<T> (p_int + util::vector<2,T> { 0, 0 }, this->seed).normalise ();
|
auto g2 = generate<T> (p2, this->seed);
|
||||||
auto p1 = generate<T> (p_int + util::vector<2,T> { 1, 0 }, this->seed).normalise ();
|
auto g3 = generate<T> (p3, this->seed);
|
||||||
auto p2 = generate<T> (p_int + util::vector<2,T> { 0, 1 }, this->seed).normalise ();
|
|
||||||
auto p3 = generate<T> (p_int + util::vector<2,T> { 1, 1 }, this->seed).normalise ();
|
|
||||||
|
|
||||||
T v0 = p0.x * p_rem.x + p0.y * p_rem.y;
|
// compute the dot products
|
||||||
T v1 = p1.x * (p_rem.x - 1) + p1.y * p_rem.y;
|
T v0 = dot (g0, p - p0);
|
||||||
T v2 = p2.x * p_rem.x + p2.y * (p_rem.y - 1);
|
T v1 = dot (g1, p - p1);
|
||||||
T v3 = p3.x * (p_rem.x - 1) + p3.y * (p_rem.y - 1);
|
T v2 = dot (g2, p - p2);
|
||||||
|
T v3 = dot (g3, p - p3);
|
||||||
|
|
||||||
|
// interpolate the results
|
||||||
auto L0 = L (v0, v1, p_rem.x);
|
auto L0 = L (v0, v1, p_rem.x);
|
||||||
auto L1 = L (v2, v3, p_rem.x);
|
auto L1 = L (v2, v3, p_rem.x);
|
||||||
auto L_ = L (L0, L1, p_rem.y);
|
auto L_ = L (L0, L1, p_rem.y);
|
||||||
|
|
||||||
return L_;
|
return L_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,10 +114,14 @@ perlin<T,L>::operator() (util::point<2,T> p) const
|
|||||||
|
|
||||||
namespace util { namespace noise { namespace basis {
|
namespace util { namespace noise { namespace basis {
|
||||||
template struct perlin<float, lerp::linear>;
|
template struct perlin<float, lerp::linear>;
|
||||||
|
template struct perlin<float, lerp::cosine>;
|
||||||
template struct perlin<float, lerp::cubic>;
|
template struct perlin<float, lerp::cubic>;
|
||||||
template struct perlin<float, lerp::quintic>;
|
template struct perlin<float, lerp::quintic>;
|
||||||
|
template struct perlin<float, lerp::trunc>;
|
||||||
|
|
||||||
template struct perlin<double, lerp::linear>;
|
template struct perlin<double, lerp::linear>;
|
||||||
|
template struct perlin<double, lerp::cosine>;
|
||||||
template struct perlin<double, lerp::cubic>;
|
template struct perlin<double, lerp::cubic>;
|
||||||
template struct perlin<double, lerp::quintic>;
|
template struct perlin<double, lerp::quintic>;
|
||||||
|
template struct perlin<double, lerp::trunc>;
|
||||||
} } }
|
} } }
|
||||||
|
@ -25,15 +25,19 @@ using util::noise::basis::value;
|
|||||||
// Generate a type from [-UNIT..UNIT]
|
// Generate a type from [-UNIT..UNIT]
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T
|
T
|
||||||
generate (util::point<2,T> p, uint64_t seed)
|
generate (util::point<2,intmax_t> p, uint64_t seed)
|
||||||
{
|
{
|
||||||
using util::hash::murmur2::mix;
|
using util::hash::murmur2::mix;
|
||||||
|
|
||||||
T v = mix (seed, mix (uint64_t (p.y), uint64_t (p.x))) & 0xffff;
|
T v = mix (
|
||||||
v = v / T{0xffff} * 2 - 1;
|
seed,
|
||||||
|
mix (
|
||||||
|
uint64_t (p.y),
|
||||||
|
uint64_t (p.x)
|
||||||
|
)
|
||||||
|
) & 0xffff;
|
||||||
|
|
||||||
CHECK_GE (v, T{0});
|
v = v / T{0xffff} * 2 - 1;
|
||||||
CHECK_LE (v, T{1});
|
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@ -67,25 +71,31 @@ template <typename T, util::noise::lerp_t<T> L>
|
|||||||
T
|
T
|
||||||
value<T,L>::operator() (util::point<2,T> p) const
|
value<T,L>::operator() (util::point<2,T> p) const
|
||||||
{
|
{
|
||||||
|
// extract integer and fractional parts. be careful to always round down
|
||||||
|
// (particularly with negatives) and avoid rounding errors.
|
||||||
auto p_int = p.template cast<intmax_t> ();
|
auto p_int = p.template cast<intmax_t> ();
|
||||||
auto p_rem = p - p_int;
|
if (p.x < 0) p_int.x -= 1;
|
||||||
|
if (p.y < 0) p_int.y -= 1;
|
||||||
|
auto p_rem = abs (p - p_int);
|
||||||
|
|
||||||
// Shift the coordinate system down a little to ensure we get unit weights
|
// generate the corner points
|
||||||
// for the lerp. It's better to do this than abs the fractional portion so
|
auto p0 = p_int + util::vector<2,intmax_t> { 0, 0 };
|
||||||
// we don't get reflections along the origin.
|
auto p1 = p_int + util::vector<2,intmax_t> { 1, 0 };
|
||||||
if (p.x < 0) { p_rem.x = 1 + p_rem.x; p_int.x -= 1; }
|
auto p2 = p_int + util::vector<2,intmax_t> { 0, 1 };
|
||||||
if (p.y < 0) { p_rem.y = 1 + p_rem.y; p_int.y -= 1; }
|
auto p3 = p_int + util::vector<2,intmax_t> { 1, 1 };
|
||||||
|
|
||||||
// Generate the four corner values
|
// Generate the four corner values
|
||||||
T p0 = generate<T> (p_int + util::vector<2,T>{ 0, 0 }, this->seed);
|
T g0 = generate<T> (p0, this->seed);
|
||||||
T p1 = generate<T> (p_int + util::vector<2,T>{ 1, 0 }, this->seed);
|
T g1 = generate<T> (p1, this->seed);
|
||||||
T p2 = generate<T> (p_int + util::vector<2,T>{ 0, 0 }, this->seed);
|
T g2 = generate<T> (p2, this->seed);
|
||||||
T p3 = generate<T> (p_int + util::vector<2,T>{ 1, 1 }, this->seed);
|
T g3 = generate<T> (p3, this->seed);
|
||||||
|
|
||||||
// Interpolate on one dimension, then the other.
|
// Interpolate on one dimension, then the other.
|
||||||
return L (L (p0, p1, p_rem.x),
|
auto l0 = L (g0, g1, p_rem.x);
|
||||||
L (p2, p3, p_rem.x),
|
auto l1 = L (g2, g3, p_rem.x);
|
||||||
p_rem.y);
|
auto l_ = L (l0, l1, p_rem.y);
|
||||||
|
|
||||||
|
return l_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -94,6 +104,7 @@ value<T,L>::operator() (util::point<2,T> p) const
|
|||||||
|
|
||||||
namespace util { namespace noise { namespace basis {
|
namespace util { namespace noise { namespace basis {
|
||||||
template struct value<float, lerp::trunc>;
|
template struct value<float, lerp::trunc>;
|
||||||
|
template struct value<float, lerp::cosine>;
|
||||||
template struct value<float, lerp::linear>;
|
template struct value<float, lerp::linear>;
|
||||||
template struct value<float, lerp::cubic>;
|
template struct value<float, lerp::cubic>;
|
||||||
template struct value<float, lerp::quintic>;
|
template struct value<float, lerp::quintic>;
|
||||||
|
@ -71,14 +71,12 @@ template <typename T>
|
|||||||
T
|
T
|
||||||
worley<T>::operator() (util::point<2,T> p) const
|
worley<T>::operator() (util::point<2,T> p) const
|
||||||
{
|
{
|
||||||
|
// extract integer and fractional parts. be careful to always round down
|
||||||
|
// (particularly with negatives) and avoid rounding errors.
|
||||||
auto p_int = p.template cast<intmax_t> ();
|
auto p_int = p.template cast<intmax_t> ();
|
||||||
auto p_rem = p - p_int;
|
if (p.x < 0) p_int.x -= 1;
|
||||||
|
if (p.y < 0) p_int.y -= 1;
|
||||||
// Generate the four corner values. It's not strictly necessary to
|
auto p_rem = abs (p - p_int);
|
||||||
// normalise the values, but we get a more consistent and visually
|
|
||||||
// appealing range of outputs with normalised values.
|
|
||||||
if (p.x < 0) { p_rem.x = 1 + p_rem.x; p_int.x -= 1; }
|
|
||||||
if (p.y < 0) { p_rem.y = 1 + p_rem.y; p_int.y -= 1; }
|
|
||||||
|
|
||||||
// +---+---+---+
|
// +---+---+---+
|
||||||
// | 0 | 1 | 2 |
|
// | 0 | 1 | 2 |
|
||||||
@ -102,7 +100,7 @@ worley<T>::operator() (util::point<2,T> p) const
|
|||||||
CHECK (off.y >= 0 && off.y <= 1);
|
CHECK (off.y >= 0 && off.y <= 1);
|
||||||
|
|
||||||
pos += off;
|
pos += off;
|
||||||
*cursor++ = pos.difference2 (p_rem);
|
*cursor++ = pos.difference2 (p_rem.template as<util::vector> ());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort (std::begin (distances), std::end (distances));
|
std::sort (std::begin (distances), std::end (distances));
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "fractal.hpp"
|
#include "fractal.hpp"
|
||||||
|
|
||||||
|
#include "basis/constant.hpp"
|
||||||
#include "basis/value.hpp"
|
#include "basis/value.hpp"
|
||||||
#include "basis/perlin.hpp"
|
#include "basis/perlin.hpp"
|
||||||
#include "basis/worley.hpp"
|
#include "basis/worley.hpp"
|
||||||
@ -125,10 +126,15 @@ fbm<T,B>::operator() (util::point<2,T> p) const {
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template struct util::noise::fbm<float, util::noise::basis::worley<float>>;
|
template struct util::noise::fbm<float, util::noise::basis::worley<float>>;
|
||||||
|
template struct util::noise::fbm<float, util::noise::basis::constant<float>>;
|
||||||
|
template struct util::noise::fbm<float, util::noise::basis::perlin<float,util::lerp::trunc>>;
|
||||||
template struct util::noise::fbm<float, util::noise::basis::perlin<float,util::lerp::linear>>;
|
template struct util::noise::fbm<float, util::noise::basis::perlin<float,util::lerp::linear>>;
|
||||||
|
template struct util::noise::fbm<float, util::noise::basis::perlin<float,util::lerp::cubic>>;
|
||||||
template struct util::noise::fbm<float, util::noise::basis::perlin<float,util::lerp::quintic>>;
|
template struct util::noise::fbm<float, util::noise::basis::perlin<float,util::lerp::quintic>>;
|
||||||
template struct util::noise::fbm<float, util::noise::basis::value<float,util::lerp::trunc>>;
|
template struct util::noise::fbm<float, util::noise::basis::value<float,util::lerp::trunc>>;
|
||||||
template struct util::noise::fbm<float, util::noise::basis::value<float,util::lerp::linear>>;
|
template struct util::noise::fbm<float, util::noise::basis::value<float,util::lerp::linear>>;
|
||||||
|
template struct util::noise::fbm<float, util::noise::basis::value<float,util::lerp::cosine>>;
|
||||||
|
template struct util::noise::fbm<float, util::noise::basis::value<float,util::lerp::cubic>>;
|
||||||
template struct util::noise::fbm<float, util::noise::basis::value<float,util::lerp::quintic>>;
|
template struct util::noise::fbm<float, util::noise::basis::value<float,util::lerp::quintic>>;
|
||||||
|
|
||||||
template struct util::noise::fbm<double, util::noise::basis::worley<double>>;
|
template struct util::noise::fbm<double, util::noise::basis::worley<double>>;
|
||||||
|
Loading…
Reference in New Issue
Block a user