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 "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;

View file

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

View file

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

View file

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

View file

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

View file

@ -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<VegetationInstance> *
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));

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