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:
parent
0e6dca30fc
commit
959f0ddf8f
7 changed files with 87 additions and 38 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
24
src/tests/NoiseFunctionSimplex_Test.cpp
Normal file
24
src/tests/NoiseFunctionSimplex_Test.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue