From 959f0ddf8fc839276b4434fe863334f6e41b936e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 3 Jan 2016 20:22:06 +0100 Subject: [PATCH] Updated NoiseNode to use FractalNoise instead of NoiseGenerator Also fixed the range returned by NoiseFunctionSimplex (when used by FractalNoise), and added a test to validate it. --- src/basics/FractalNoise.cpp | 29 +++++++++++++++++++ src/basics/FractalNoise.h | 4 +++ src/basics/NoiseFunctionSimplex.cpp | 12 ++++---- src/definition/NoiseNode.cpp | 25 +++++++--------- src/definition/NoiseNode.h | 13 +++------ .../VegetationPresenceDefinition.cpp | 18 ++++++------ src/tests/NoiseFunctionSimplex_Test.cpp | 24 +++++++++++++++ 7 files changed, 87 insertions(+), 38 deletions(-) create mode 100644 src/tests/NoiseFunctionSimplex_Test.cpp diff --git a/src/basics/FractalNoise.cpp b/src/basics/FractalNoise.cpp index a6c29bc..e75c5b1 100644 --- a/src/basics/FractalNoise.cpp +++ b/src/basics/FractalNoise.cpp @@ -1,5 +1,7 @@ #include "FractalNoise.h" +#include "PackStream.h" + FractalNoise::FractalNoise() { scaling = 1.0; height = 1.0; @@ -10,6 +12,33 @@ FractalNoise::FractalNoise() { FractalNoise::~FractalNoise() { } +void FractalNoise::save(PackStream *stream) const +{ + stream->write(&scaling); + stream->write(&height); + stream->write(&step_scaling); + stream->write(&step_height); + state.save(stream); +} + +void FractalNoise::load(PackStream *stream) +{ + stream->read(&scaling); + stream->read(&height); + stream->read(&step_scaling); + stream->read(&step_height); + state.load(stream); +} + +void FractalNoise::copy(FractalNoise *destination) const +{ + destination->scaling = scaling; + destination->height = height; + destination->step_scaling = step_scaling; + destination->step_height = step_height; + state.copy(&destination->state); +} + void FractalNoise::setScaling(double scaling, double height) { this->scaling = scaling < 0.00000001 ? 0.0 : 1.0 / scaling; this->height = scaling * height; diff --git a/src/basics/FractalNoise.h b/src/basics/FractalNoise.h index 2bdb7bf..ab72895 100644 --- a/src/basics/FractalNoise.h +++ b/src/basics/FractalNoise.h @@ -16,6 +16,10 @@ class BASICSSHARED_EXPORT FractalNoise { FractalNoise(); virtual ~FractalNoise(); + virtual void save(PackStream *stream) const; + virtual void load(PackStream *stream); + virtual void copy(FractalNoise *destination) const; + inline double getScaling() const { return scaling; } diff --git a/src/basics/NoiseFunctionSimplex.cpp b/src/basics/NoiseFunctionSimplex.cpp index 97a615c..a38a21a 100644 --- a/src/basics/NoiseFunctionSimplex.cpp +++ b/src/basics/NoiseFunctionSimplex.cpp @@ -469,11 +469,11 @@ double noiseSimplexGet4DValue(double x, double y, double z, double w) { } double NoiseFunctionSimplex::getBase2d(double x, double y) const { - return noiseSimplexGet2DValue(x, y); + return noiseSimplexGet2DValue(x, y) - 0.5; } double NoiseFunctionSimplex::getBase3d(double x, double y, double z) const { - return noiseSimplexGet3DValue(x, y, z); + return noiseSimplexGet3DValue(x, y, z) - 0.5; } static Texture2D *_valueTexture = NULL; @@ -487,7 +487,7 @@ const Texture2D *NoiseFunctionSimplex::getValueTexture() { for (int x = 0; x < width; x++) { for (int z = 0; z < height; z++) { - double val = noiseSimplexGet2DValue(to_double(x), to_double(z)); + double val = noiseSimplexGet2DValue(to_double(x), to_double(z)) - 0.5; _valueTexture->setPixel(x, z, Color(val, val, val)); } } @@ -508,9 +508,9 @@ const Texture2D *NoiseFunctionSimplex::getNormalTexture() { for (int x = 0; x < width; x++) { for (int z = 0; z < height; z++) { // TODO Make texture tileable - double vcenter = noiseSimplexGet2DValue(0.01 * to_double(x), 0.01 * to_double(z)); - double vsouth = noiseSimplexGet2DValue(0.01 * to_double(x), 0.01 * to_double(z) + 0.001); - double veast = noiseSimplexGet2DValue(0.01 * to_double(x) + 0.001, 0.01 * to_double(z)); + double vcenter = noiseSimplexGet2DValue(0.01 * to_double(x), 0.01 * to_double(z)) - 0.5; + double vsouth = noiseSimplexGet2DValue(0.01 * to_double(x), 0.01 * to_double(z) + 0.001) - 0.5; + double veast = noiseSimplexGet2DValue(0.01 * to_double(x) + 0.001, 0.01 * to_double(z)) - 0.5; Vector3 normal = Geometry::getNormalFromTriangle(Vector3(0.0, vcenter, 0.0), Vector3(0.0, vsouth, 0.01), Vector3(0.01, veast, 0.0)); diff --git a/src/definition/NoiseNode.cpp b/src/definition/NoiseNode.cpp index 4b98895..9f045f2 100644 --- a/src/definition/NoiseNode.cpp +++ b/src/definition/NoiseNode.cpp @@ -1,24 +1,16 @@ #include "NoiseNode.h" -#include "NoiseGenerator.h" +#include "NoiseFunctionSimplex.h" #include "Logs.h" -NoiseNode::NoiseNode(DefinitionNode *parent) : DefinitionNode(parent, "noise") { - noise = new NoiseGenerator(); +NoiseNode::NoiseNode(DefinitionNode *parent, const string &name) : DefinitionNode(parent, name) { + noise = new NoiseFunctionSimplex(); } NoiseNode::~NoiseNode() { delete noise; } -void NoiseNode::setLevels(int levels, double min_value, double max_value) { - noise->clearLevels(); - noise->addLevelsSimple(levels, 1.0, -1.0, 1.0, 0.5); - noise->normalizeAmplitude(min_value, max_value, false); - noise->randomizeOffsets(); - noise->validate(); -} - void NoiseNode::save(PackStream *stream) const { noise->save(stream); } @@ -29,13 +21,18 @@ void NoiseNode::load(PackStream *stream) { void NoiseNode::copy(DefinitionNode *destination) const { if (destination->getTypeName() == getTypeName()) { - noise->copy(((NoiseNode *)destination)->noise); + auto tdestination = static_cast(destination); + if (tdestination) { + noise->copy(tdestination->noise); + } } else { Logs::error("Definition") << "Can't copy from " << getTypeName() << " to " << destination->getTypeName() << endl; } } -void NoiseNode::validate() { - noise->validate(); +string NoiseNode::toString(int indent) const { + return DefinitionNode::toString(indent) + " - scaling: " + to_string(noise->getScaling()) + " step " + + to_string(noise->getStepScaling()) + " - height: " + to_string(noise->getHeight()) + " step " + + to_string(noise->getStepScaling()); } diff --git a/src/definition/NoiseNode.h b/src/definition/NoiseNode.h index 6168d47..ce076d6 100644 --- a/src/definition/NoiseNode.h +++ b/src/definition/NoiseNode.h @@ -13,26 +13,21 @@ namespace definition { */ class DEFINITIONSHARED_EXPORT NoiseNode : public DefinitionNode { public: - NoiseNode(DefinitionNode *parent); + NoiseNode(DefinitionNode *parent, const string &name = "noise"); virtual ~NoiseNode(); - inline const NoiseGenerator *getGenerator() { + inline const FractalNoise *getGenerator() { return noise; } - /** - * Set the number of levels to use in the noise generator. - */ - void setLevels(int levels, double min_value = -1.0, double max_value = 1.0); - protected: virtual void save(PackStream *stream) const override; virtual void load(PackStream *stream) override; virtual void copy(DefinitionNode *destination) const override; - virtual void validate() override; + virtual string toString(int indent) const override; private: - NoiseGenerator *noise; + FractalNoise *noise; }; } } diff --git a/src/definition/VegetationPresenceDefinition.cpp b/src/definition/VegetationPresenceDefinition.cpp index 02592c0..da65145 100644 --- a/src/definition/VegetationPresenceDefinition.cpp +++ b/src/definition/VegetationPresenceDefinition.cpp @@ -8,12 +8,11 @@ #include "VegetationInstance.h" #include "FloatNode.h" #include "NoiseNode.h" -#include "NoiseGenerator.h" +#include "FractalNoise.h" VegetationPresenceDefinition::VegetationPresenceDefinition(VegetationLayerDefinition *parent) : DefinitionNode(parent, "presence") { noise = new NoiseNode(this); - noise->setLevels(4); interval = new FloatNode(this, "interval", 0.1); } @@ -29,22 +28,23 @@ bool VegetationPresenceDefinition::collectInstances(vector * zmax += max_radius; } - bool added = 0; + int added = 0; - const NoiseGenerator *generator = noise->getGenerator(); + auto generator = noise->getGenerator(); double interval_value = interval->getValue(); double xstart = xmin - fmod(xmin, interval_value); double zstart = zmin - fmod(zmin, interval_value); for (double x = xstart; x < xmax; x += interval_value) { for (double z = zstart; z < zmax; z += interval_value) { - double noise_presence = generator->get2DTotal(x * 0.1, z * 0.1); + double detail = interval_value * 0.1; + double noise_presence = generator->get2d(detail, x * 0.1, z * 0.1); if (noise_presence > 0.0) { double size = - 0.1 + 0.2 * fabs(generator->get2DTotal(z * 10.0, x * 10.0)) * (noise_presence * 0.5 + 0.5); - double angle = 3.0 * generator->get2DTotal(-x * 20.0, z * 20.0); // TODO balanced distribution - double xo = x + fabs(generator->get2DTotal(x * 12.0, -z * 12.0)); - double zo = z + fabs(generator->get2DTotal(-x * 27.0, -z * 27.0)); + 0.1 + 0.2 * fabs(generator->get2d(detail, z * 10.0, x * 10.0)) * (noise_presence * 0.5 + 0.5); + double angle = 3.0 * generator->get2d(detail, -x * 20.0, z * 20.0); // TODO balanced distribution + double xo = x + fabs(generator->get2d(detail, x * 12.0, -z * 12.0)); + double zo = z + fabs(generator->get2d(detail, -x * 27.0, -z * 27.0)); if (xo >= xmin and xo < xmax and zo >= zmin and zo < zmax) { double y = getScenery()->getTerrain()->getInterpolatedHeight(xo, zo, true, true); result->push_back(VegetationInstance(model, Vector3(xo, y, zo), size, angle)); diff --git a/src/tests/NoiseFunctionSimplex_Test.cpp b/src/tests/NoiseFunctionSimplex_Test.cpp new file mode 100644 index 0000000..5eebb80 --- /dev/null +++ b/src/tests/NoiseFunctionSimplex_Test.cpp @@ -0,0 +1,24 @@ +#include "BaseTestCase.h" +#include "NoiseFunctionSimplex.h" + +#include "RandomGenerator.h" + +TEST(NoiseFunctionSimplex, range) { + NoiseFunctionSimplex noise; + RandomGenerator random(17124); + + for (int i = 0; i < 100000; i++) { + double x = random.genDouble() - 0.5; + double y = random.genDouble() - 0.5; + double z = random.genDouble() - 0.5; + double scale = random.genDouble() * 5.0 + 0.1; + + // TODO Test repartition and filling + + double val2 = noise.get2d(1.0, x * scale, y * scale); + EXPECT_DOUBLE_IN_RANGE(val2, -0.5, 0.5); + + double val3 = noise.get3d(1.0, x * scale, y * scale, z * scale); + EXPECT_DOUBLE_IN_RANGE(val3, -0.5, 0.5); + } +}