Implement fractal perlin noise

This commit is contained in:
Nikita Lisitsa 2020-09-24 19:06:33 +03:00
parent aba0afa15e
commit 040497887c
3 changed files with 87 additions and 0 deletions

View file

@ -4,6 +4,8 @@
#include <psemek/geom/vector.hpp>
#include <psemek/pcg/seamless.hpp>
#include <vector>
namespace psemek::pcg
{
@ -37,4 +39,24 @@ namespace psemek::pcg
gfx::basic_pixmap<geom::vector<float, 2>> grad_map_;
};
struct fractal_perlin
{
fractal_perlin() = default;
fractal_perlin(std::vector<gfx::basic_pixmap<geom::vector<float, 2>>> grad_maps);
fractal_perlin(std::vector<gfx::basic_pixmap<geom::vector<float, 2>>> grad_maps, std::vector<float> weights);
fractal_perlin(std::vector<gfx::basic_pixmap<geom::vector<float, 2>>> const & grad_maps, seamless_tag);
fractal_perlin(std::vector<gfx::basic_pixmap<geom::vector<float, 2>>> const & grad_maps, std::vector<float> weights, seamless_tag);
fractal_perlin(fractal_perlin &&) = default;
fractal_perlin & operator = (fractal_perlin &&) = default;
// x \in [0.0 .. 1.0]
// y \in [0.0 .. 1.0]
float operator()(float x, float y) const;
private:
std::vector<perlin> octaves_;
std::vector<float> weights_;
};
}

View file

@ -64,4 +64,68 @@ namespace psemek::pcg
return 0.5f + v * 0.5f;
}
static std::vector<float> estimate_weights(std::vector<gfx::basic_pixmap<geom::vector<float, 2>>> const & grad_maps)
{
std::vector<float> weights(grad_maps.size());
float sum = 0.f;
for (std::size_t i = 0; i < grad_maps.size(); ++i)
{
auto const & m = grad_maps[i];
weights[i] = 1.f / std::sqrt(m.width() * m.width() + m.height() * m.height());
sum += weights[i];
}
for (std::size_t i = 0; i < grad_maps.size(); ++i)
weights[i] /= sum;
return weights;
}
fractal_perlin::fractal_perlin(std::vector<gfx::basic_pixmap<geom::vector<float, 2>>> grad_maps)
{
weights_ = estimate_weights(grad_maps);
octaves_.resize(grad_maps.size());
for (std::size_t i = 0; i < grad_maps.size(); ++i)
octaves_[i] = perlin(std::move(grad_maps[i]));
}
fractal_perlin::fractal_perlin(std::vector<gfx::basic_pixmap<geom::vector<float, 2>>> grad_maps, std::vector<float> weights)
: weights_{std::move(weights)}
{
assert(weights_.size() == grad_maps.size());
octaves_.resize(grad_maps.size());
for (std::size_t i = 0; i < grad_maps.size(); ++i)
octaves_[i] = perlin(std::move(grad_maps[i]));
}
fractal_perlin::fractal_perlin(std::vector<gfx::basic_pixmap<geom::vector<float, 2>>> const & grad_maps, seamless_tag)
{
weights_ = estimate_weights(grad_maps);
octaves_.resize(grad_maps.size());
for (std::size_t i = 0; i < grad_maps.size(); ++i)
octaves_[i] = perlin(grad_maps[i], seamless);
}
fractal_perlin::fractal_perlin(std::vector<gfx::basic_pixmap<geom::vector<float, 2>>> const & grad_maps, std::vector<float> weights, seamless_tag)
: weights_{std::move(weights)}
{
assert(weights_.size() == grad_maps.size());
octaves_.resize(grad_maps.size());
for (std::size_t i = 0; i < grad_maps.size(); ++i)
octaves_[i] = perlin(grad_maps[i], seamless);
}
float fractal_perlin::operator()(float x, float y) const
{
float v = 0.f;
for (std::size_t i = 0; i < octaves_.size(); ++i)
v += weights_[i] * octaves_[i](x, y);
return v;
}
}

View file

@ -7,3 +7,4 @@
* gfx: design & implement simple rendering pipelines
* pcg: add clean Generator, Sampler & Pixmap processor concepts, uniformize interfaces, be type & dimension agnostic when possible
* pcg: add more vector & point distributions
* pcg: make template fractal generator, replace fractal_perlin with it