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