From 040497887ccf97738c48c5f6cc432f27bbb60dc9 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Thu, 24 Sep 2020 19:06:33 +0300 Subject: [PATCH] Implement fractal perlin noise --- libs/pcg/include/psemek/pcg/perlin.hpp | 22 +++++++++ libs/pcg/source/perlin.cpp | 64 ++++++++++++++++++++++++++ todo.md | 1 + 3 files changed, 87 insertions(+) diff --git a/libs/pcg/include/psemek/pcg/perlin.hpp b/libs/pcg/include/psemek/pcg/perlin.hpp index 716b9b52..57c940da 100644 --- a/libs/pcg/include/psemek/pcg/perlin.hpp +++ b/libs/pcg/include/psemek/pcg/perlin.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace psemek::pcg { @@ -37,4 +39,24 @@ namespace psemek::pcg gfx::basic_pixmap> grad_map_; }; + struct fractal_perlin + { + fractal_perlin() = default; + fractal_perlin(std::vector>> grad_maps); + fractal_perlin(std::vector>> grad_maps, std::vector weights); + fractal_perlin(std::vector>> const & grad_maps, seamless_tag); + fractal_perlin(std::vector>> const & grad_maps, std::vector 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 octaves_; + std::vector weights_; + }; + } diff --git a/libs/pcg/source/perlin.cpp b/libs/pcg/source/perlin.cpp index 4ebcd909..8aac4cb2 100644 --- a/libs/pcg/source/perlin.cpp +++ b/libs/pcg/source/perlin.cpp @@ -64,4 +64,68 @@ namespace psemek::pcg return 0.5f + v * 0.5f; } + static std::vector estimate_weights(std::vector>> const & grad_maps) + { + std::vector 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>> 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>> grad_maps, std::vector 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>> 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>> const & grad_maps, std::vector 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; + } + } diff --git a/todo.md b/todo.md index 4f5fb661..579cd1b0 100644 --- a/todo.md +++ b/todo.md @@ -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