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.
This commit is contained in:
Michaël Lemaire 2016-01-03 20:22:06 +01:00
parent 0e6dca30fc
commit 959f0ddf8f
7 changed files with 87 additions and 38 deletions

View file

@ -1,5 +1,7 @@
#include "FractalNoise.h" #include "FractalNoise.h"
#include "PackStream.h"
FractalNoise::FractalNoise() { FractalNoise::FractalNoise() {
scaling = 1.0; scaling = 1.0;
height = 1.0; height = 1.0;
@ -10,6 +12,33 @@ FractalNoise::FractalNoise() {
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) { void FractalNoise::setScaling(double scaling, double height) {
this->scaling = scaling < 0.00000001 ? 0.0 : 1.0 / scaling; this->scaling = scaling < 0.00000001 ? 0.0 : 1.0 / scaling;
this->height = scaling * height; this->height = scaling * height;

View file

@ -16,6 +16,10 @@ class BASICSSHARED_EXPORT FractalNoise {
FractalNoise(); FractalNoise();
virtual ~FractalNoise(); virtual ~FractalNoise();
virtual void save(PackStream *stream) const;
virtual void load(PackStream *stream);
virtual void copy(FractalNoise *destination) const;
inline double getScaling() const { inline double getScaling() const {
return scaling; return scaling;
} }

View file

@ -469,11 +469,11 @@ double noiseSimplexGet4DValue(double x, double y, double z, double w) {
} }
double NoiseFunctionSimplex::getBase2d(double x, double y) const { 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 { 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; static Texture2D *_valueTexture = NULL;
@ -487,7 +487,7 @@ const Texture2D *NoiseFunctionSimplex::getValueTexture() {
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
for (int z = 0; z < height; z++) { 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)); _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 x = 0; x < width; x++) {
for (int z = 0; z < height; z++) { for (int z = 0; z < height; z++) {
// TODO Make texture tileable // TODO Make texture tileable
double vcenter = noiseSimplexGet2DValue(0.01 * to_double(x), 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); 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)); 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 normal = Geometry::getNormalFromTriangle(Vector3(0.0, vcenter, 0.0), Vector3(0.0, vsouth, 0.01),
Vector3(0.01, veast, 0.0)); Vector3(0.01, veast, 0.0));

View file

@ -1,24 +1,16 @@
#include "NoiseNode.h" #include "NoiseNode.h"
#include "NoiseGenerator.h" #include "NoiseFunctionSimplex.h"
#include "Logs.h" #include "Logs.h"
NoiseNode::NoiseNode(DefinitionNode *parent) : DefinitionNode(parent, "noise") { NoiseNode::NoiseNode(DefinitionNode *parent, const string &name) : DefinitionNode(parent, name) {
noise = new NoiseGenerator(); noise = new NoiseFunctionSimplex();
} }
NoiseNode::~NoiseNode() { NoiseNode::~NoiseNode() {
delete noise; 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 { void NoiseNode::save(PackStream *stream) const {
noise->save(stream); noise->save(stream);
} }
@ -29,13 +21,18 @@ void NoiseNode::load(PackStream *stream) {
void NoiseNode::copy(DefinitionNode *destination) const { void NoiseNode::copy(DefinitionNode *destination) const {
if (destination->getTypeName() == getTypeName()) { if (destination->getTypeName() == getTypeName()) {
noise->copy(((NoiseNode *)destination)->noise); auto tdestination = static_cast<NoiseNode *>(destination);
if (tdestination) {
noise->copy(tdestination->noise);
}
} else { } else {
Logs::error("Definition") << "Can't copy from " << getTypeName() << " to " << destination->getTypeName() Logs::error("Definition") << "Can't copy from " << getTypeName() << " to " << destination->getTypeName()
<< endl; << endl;
} }
} }
void NoiseNode::validate() { string NoiseNode::toString(int indent) const {
noise->validate(); return DefinitionNode::toString(indent) + " - scaling: " + to_string(noise->getScaling()) + " step " +
to_string(noise->getStepScaling()) + " - height: " + to_string(noise->getHeight()) + " step " +
to_string(noise->getStepScaling());
} }

View file

@ -13,26 +13,21 @@ namespace definition {
*/ */
class DEFINITIONSHARED_EXPORT NoiseNode : public DefinitionNode { class DEFINITIONSHARED_EXPORT NoiseNode : public DefinitionNode {
public: public:
NoiseNode(DefinitionNode *parent); NoiseNode(DefinitionNode *parent, const string &name = "noise");
virtual ~NoiseNode(); virtual ~NoiseNode();
inline const NoiseGenerator *getGenerator() { inline const FractalNoise *getGenerator() {
return noise; 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: protected:
virtual void save(PackStream *stream) const override; virtual void save(PackStream *stream) const override;
virtual void load(PackStream *stream) override; virtual void load(PackStream *stream) override;
virtual void copy(DefinitionNode *destination) const override; virtual void copy(DefinitionNode *destination) const override;
virtual void validate() override; virtual string toString(int indent) const override;
private: private:
NoiseGenerator *noise; FractalNoise *noise;
}; };
} }
} }

View file

@ -8,12 +8,11 @@
#include "VegetationInstance.h" #include "VegetationInstance.h"
#include "FloatNode.h" #include "FloatNode.h"
#include "NoiseNode.h" #include "NoiseNode.h"
#include "NoiseGenerator.h" #include "FractalNoise.h"
VegetationPresenceDefinition::VegetationPresenceDefinition(VegetationLayerDefinition *parent) VegetationPresenceDefinition::VegetationPresenceDefinition(VegetationLayerDefinition *parent)
: DefinitionNode(parent, "presence") { : DefinitionNode(parent, "presence") {
noise = new NoiseNode(this); noise = new NoiseNode(this);
noise->setLevels(4);
interval = new FloatNode(this, "interval", 0.1); interval = new FloatNode(this, "interval", 0.1);
} }
@ -29,22 +28,23 @@ bool VegetationPresenceDefinition::collectInstances(vector<VegetationInstance> *
zmax += max_radius; zmax += max_radius;
} }
bool added = 0; int added = 0;
const NoiseGenerator *generator = noise->getGenerator(); auto generator = noise->getGenerator();
double interval_value = interval->getValue(); double interval_value = interval->getValue();
double xstart = xmin - fmod(xmin, interval_value); double xstart = xmin - fmod(xmin, interval_value);
double zstart = zmin - fmod(zmin, interval_value); double zstart = zmin - fmod(zmin, interval_value);
for (double x = xstart; x < xmax; x += interval_value) { for (double x = xstart; x < xmax; x += interval_value) {
for (double z = zstart; z < zmax; z += 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) { if (noise_presence > 0.0) {
double size = double size =
0.1 + 0.2 * fabs(generator->get2DTotal(z * 10.0, x * 10.0)) * (noise_presence * 0.5 + 0.5); 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->get2DTotal(-x * 20.0, z * 20.0); // TODO balanced distribution double angle = 3.0 * generator->get2d(detail, -x * 20.0, z * 20.0); // TODO balanced distribution
double xo = x + fabs(generator->get2DTotal(x * 12.0, -z * 12.0)); double xo = x + fabs(generator->get2d(detail, x * 12.0, -z * 12.0));
double zo = z + fabs(generator->get2DTotal(-x * 27.0, -z * 27.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) { if (xo >= xmin and xo < xmax and zo >= zmin and zo < zmax) {
double y = getScenery()->getTerrain()->getInterpolatedHeight(xo, zo, true, true); double y = getScenery()->getTerrain()->getInterpolatedHeight(xo, zo, true, true);
result->push_back(VegetationInstance(model, Vector3(xo, y, zo), size, angle)); result->push_back(VegetationInstance(model, Vector3(xo, y, zo), size, angle));

View file

@ -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);
}
}