Updated TerrainDefinition to use FractalNoise
This commit is contained in:
parent
a098a19ee3
commit
14143ee278
16 changed files with 224 additions and 142 deletions
|
@ -1,8 +1,11 @@
|
|||
#include "FractalNoise.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include "PackStream.h"
|
||||
#include "Vector3.h"
|
||||
#include "RandomGenerator.h"
|
||||
|
||||
FractalNoise::FractalNoise() {
|
||||
scaling = 1.0;
|
||||
|
@ -50,6 +53,11 @@ void FractalNoise::setScaling(double scaling, double height) {
|
|||
void FractalNoise::setStep(double scaling_factor, double height_factor) {
|
||||
this->step_scaling = scaling_factor < 0.00000001 ? 0.0 : 1.0 / scaling_factor;
|
||||
this->step_height = scaling_factor * height_factor;
|
||||
|
||||
// Ensure height will converge to 0
|
||||
if (this->step_height >= 0.99) {
|
||||
this->step_height = 0.99;
|
||||
}
|
||||
}
|
||||
|
||||
void FractalNoise::setState(const NoiseState &state) {
|
||||
|
@ -64,7 +72,7 @@ double FractalNoise::get1d(double detail, double x) const {
|
|||
decltype(state_level_count) i = 0;
|
||||
|
||||
while (current_height >= detail) {
|
||||
const NoiseState::NoiseOffset &offset = state.level_offsets[i];
|
||||
auto offset = state.level_offsets[i];
|
||||
|
||||
result += getBase1d(offset.x + x * current_scaling) * current_height;
|
||||
|
||||
|
@ -88,7 +96,7 @@ double FractalNoise::get2d(double detail, double x, double y) const {
|
|||
decltype(state_level_count) i = 0;
|
||||
|
||||
while (current_height >= detail) {
|
||||
const NoiseState::NoiseOffset &offset = state.level_offsets[i];
|
||||
auto offset = state.level_offsets[i];
|
||||
|
||||
result += getBase2d(offset.x + x * current_scaling, offset.y + y * current_scaling) * current_height;
|
||||
|
||||
|
@ -146,10 +154,16 @@ double FractalNoise::getTriplanar(double detail, const Vector3 &location, const
|
|||
return noiseXY * mXY + noiseXZ * mXZ + noiseYZ * mYZ;
|
||||
}
|
||||
|
||||
void FractalNoise::estimateRange(double *min, double *max) const {
|
||||
// TODO Better estimate
|
||||
*max = height;
|
||||
*min = -*max;
|
||||
void FractalNoise::estimateRange(double *min, double *max, double detail) const {
|
||||
*min = 0.0;
|
||||
*max = 0.0;
|
||||
|
||||
double current_height = height;
|
||||
while (current_height >= detail) {
|
||||
*min += -0.5 * current_height;
|
||||
*max += 0.5 * current_height;
|
||||
current_height *= step_height;
|
||||
}
|
||||
}
|
||||
|
||||
double FractalNoise::getBase1d(double x) const {
|
||||
|
@ -159,3 +173,48 @@ double FractalNoise::getBase1d(double x) const {
|
|||
double FractalNoise::getBase2d(double x, double y) const {
|
||||
return getBase3d(x, y, 0.0);
|
||||
}
|
||||
|
||||
string FractalNoise::checkDistribution() {
|
||||
stringstream result;
|
||||
|
||||
double val, min, max, mean;
|
||||
RandomGenerator random;
|
||||
|
||||
int samples = 10000000;
|
||||
double factor = 1.0 / to_double(samples);
|
||||
|
||||
min = 0.0;
|
||||
max = 0.0;
|
||||
mean = 0.0;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
val = getBase1d((random.genDouble() - 0.5) * 10.0);
|
||||
min = std::min(val, min);
|
||||
max = std::max(val, max);
|
||||
mean += val * factor;
|
||||
}
|
||||
result << "1d : min=" << min << " max=" << max << " mean=" << mean << endl;
|
||||
|
||||
min = 0.0;
|
||||
max = 0.0;
|
||||
mean = 0.0;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
val = getBase2d((random.genDouble() - 0.5) * 10.0, (random.genDouble() - 0.5) * 10.0);
|
||||
min = std::min(val, min);
|
||||
max = std::max(val, max);
|
||||
mean += val * factor;
|
||||
}
|
||||
result << "2d : min=" << min << " max=" << max << " mean=" << mean << endl;
|
||||
|
||||
min = 0.0;
|
||||
max = 0.0;
|
||||
mean = 0.0;
|
||||
for (int i = 0; i < samples; i++) {
|
||||
val = getBase3d((random.genDouble() - 0.5) * 10.0, (random.genDouble() - 0.5) * 10.0, (random.genDouble() - 0.5) * 10.0);
|
||||
min = std::min(val, min);
|
||||
max = std::max(val, max);
|
||||
mean += val * factor;
|
||||
}
|
||||
result << "3d : min=" << min << " max=" << max << " mean=" << mean << endl;
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "basics_global.h"
|
||||
|
||||
#include <string>
|
||||
#include "NoiseState.h"
|
||||
|
||||
namespace paysages {
|
||||
|
@ -56,7 +57,7 @@ class BASICSSHARED_EXPORT FractalNoise {
|
|||
/**
|
||||
* Estimate the range of values this generator will yield with a very small detail value.
|
||||
*/
|
||||
void estimateRange(double *min, double *max) const;
|
||||
void estimateRange(double *min, double *max, double detail=0.000001) const;
|
||||
|
||||
virtual double getBase1d(double x) const;
|
||||
virtual double getBase2d(double x, double y) const;
|
||||
|
@ -67,6 +68,11 @@ class BASICSSHARED_EXPORT FractalNoise {
|
|||
*/
|
||||
virtual double getBase3d(double x, double y, double z) const = 0;
|
||||
|
||||
/**
|
||||
* Test the noise distribution, and return the report.
|
||||
*/
|
||||
string checkDistribution();
|
||||
|
||||
private:
|
||||
NoiseState state;
|
||||
|
||||
|
|
|
@ -20,6 +20,11 @@ void NoiseNode::setConfig(double scaling, double height, double step_scaling, do
|
|||
noise->setStep(step_scaling, step_height);
|
||||
}
|
||||
|
||||
void NoiseNode::forceSetGenerator(FractalNoise *noise) {
|
||||
delete this->noise;
|
||||
this->noise = noise;
|
||||
}
|
||||
|
||||
void NoiseNode::save(PackStream *stream) const {
|
||||
noise->save(stream);
|
||||
}
|
||||
|
@ -43,5 +48,5 @@ void NoiseNode::copy(DefinitionNode *destination) const {
|
|||
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());
|
||||
to_string(noise->getStepHeight());
|
||||
}
|
||||
|
|
|
@ -30,6 +30,15 @@ class DEFINITIONSHARED_EXPORT NoiseNode : public DefinitionNode {
|
|||
*/
|
||||
void setConfig(double scaling, double height = 1.0, double step_scaling = 0.5, double step_height = 1.0);
|
||||
|
||||
/**
|
||||
* Force the noise generator to use.
|
||||
*
|
||||
* This should only be needed in testing, and is not thread-safe.
|
||||
*
|
||||
* The node will take ownership of the generator and will take care of its destruction.
|
||||
*/
|
||||
void forceSetGenerator(FractalNoise *noise);
|
||||
|
||||
protected:
|
||||
virtual void save(PackStream *stream) const override;
|
||||
virtual void load(PackStream *stream) override;
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
#include "NoiseGenerator.h"
|
||||
#include "PackStream.h"
|
||||
#include "FloatNode.h"
|
||||
#include "NoiseNode.h"
|
||||
#include "FractalNoise.h"
|
||||
|
||||
TerrainDefinition::TerrainDefinition(DefinitionNode *parent) : DefinitionNode(parent, "terrain", "terrain") {
|
||||
height = 1.0;
|
||||
shadow_smoothing = 0.0;
|
||||
|
||||
height_map = new TerrainHeightMap(this);
|
||||
|
@ -15,57 +16,42 @@ TerrainDefinition::TerrainDefinition(DefinitionNode *parent) : DefinitionNode(pa
|
|||
addChild(height_map);
|
||||
|
||||
water_height = new FloatNode(this, "water_height");
|
||||
|
||||
_height_noise = new NoiseGenerator;
|
||||
height_noise = new NoiseNode(this, "height_noise");
|
||||
}
|
||||
|
||||
TerrainDefinition::~TerrainDefinition() {
|
||||
delete _height_noise;
|
||||
}
|
||||
|
||||
void TerrainDefinition::validate() {
|
||||
_height_noise->validate();
|
||||
DefinitionNode::validate();
|
||||
|
||||
if (height < 1.0) {
|
||||
height = 1.0;
|
||||
}
|
||||
// Get base noise range
|
||||
height_noise->getGenerator()->estimateRange(&_min_height, &_max_height, 0.1);
|
||||
// TODO Alter limits with heightmap min/max, and displacement textures
|
||||
|
||||
/* Get minimal and maximal height */
|
||||
_height_noise->getRange(&_min_height, &_max_height);
|
||||
_min_height *= height;
|
||||
_max_height *= height;
|
||||
|
||||
/* TODO Alter limits with heightmap min/max */
|
||||
has_painting = height_map->hasPainting();
|
||||
}
|
||||
|
||||
void TerrainDefinition::copy(DefinitionNode *_destination) const {
|
||||
TerrainDefinition *destination = (TerrainDefinition *)_destination;
|
||||
if (auto destination = static_cast<TerrainDefinition *>(_destination)) {
|
||||
destination->shadow_smoothing = shadow_smoothing;
|
||||
|
||||
destination->height = height;
|
||||
destination->shadow_smoothing = shadow_smoothing;
|
||||
height_map->copy(destination->height_map);
|
||||
|
||||
height_map->copy(destination->height_map);
|
||||
|
||||
_height_noise->copy(destination->_height_noise);
|
||||
|
||||
destination->validate();
|
||||
destination->validate();
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainDefinition::save(PackStream *stream) const {
|
||||
DefinitionNode::save(stream);
|
||||
|
||||
stream->write(&height);
|
||||
stream->write(&shadow_smoothing);
|
||||
_height_noise->save(stream);
|
||||
}
|
||||
|
||||
void TerrainDefinition::load(PackStream *stream) {
|
||||
DefinitionNode::load(stream);
|
||||
|
||||
stream->read(&height);
|
||||
stream->read(&shadow_smoothing);
|
||||
_height_noise->load(stream);
|
||||
|
||||
validate();
|
||||
}
|
||||
|
@ -74,29 +60,26 @@ double TerrainDefinition::getGridHeight(int x, int z, bool with_painting) {
|
|||
double h;
|
||||
|
||||
if (!with_painting || !has_painting || !height_map->getGridValue(x, z, &h)) {
|
||||
h = _height_noise->get2DTotal(to_double(x), to_double(z));
|
||||
h = height_noise->getGenerator()->get2d(0.1, to_double(x), to_double(z));
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
double TerrainDefinition::getInterpolatedHeight(double x, double z, bool scaled, bool with_painting,
|
||||
double TerrainDefinition::getInterpolatedHeight(double x, double z, bool with_painting,
|
||||
bool water_offset) {
|
||||
double h;
|
||||
|
||||
if (!with_painting || !has_painting || !height_map->getInterpolatedValue(x, z, &h)) {
|
||||
h = _height_noise->get2DTotal(x, z);
|
||||
h = height_noise->getGenerator()->get2d(0.1, x, z);
|
||||
}
|
||||
|
||||
if (scaled) {
|
||||
return (water_offset ? (h - water_height->getValue()) : h) * height;
|
||||
} else {
|
||||
return h;
|
||||
}
|
||||
return (water_offset ? (h + getWaterOffset()) : h);
|
||||
}
|
||||
|
||||
double TerrainDefinition::getWaterOffset() const {
|
||||
return -water_height->getValue() * height;
|
||||
double height_power = (_max_height - _min_height) * 0.5;
|
||||
return -water_height->getValue() * height_power;
|
||||
}
|
||||
|
||||
HeightInfo TerrainDefinition::getHeightInfo() {
|
||||
|
@ -114,20 +97,12 @@ unsigned long TerrainDefinition::getMemoryStats() {
|
|||
}
|
||||
|
||||
void TerrainDefinition::applyPreset(TerrainPreset preset, RandomGenerator &random) {
|
||||
int resolution = 8;
|
||||
switch (preset) {
|
||||
case TERRAIN_PRESET_STANDARD:
|
||||
_height_noise->randomizeOffsets(random);
|
||||
_height_noise->clearLevels();
|
||||
_height_noise->addLevelSimple(pow(2.0, resolution + 1), -1.0, 1.0);
|
||||
_height_noise->addLevelsSimple(resolution - 2, pow(2.0, resolution - 1), -0.7, 0.7, 0.5);
|
||||
_height_noise->normalizeAmplitude(-1.0, 1.0, 0);
|
||||
_height_noise->setFunctionParams(NoiseGenerator::NOISE_FUNCTION_SIMPLEX, 0.0, 0.0);
|
||||
height = 30.0;
|
||||
height_noise->randomize(random);
|
||||
height_noise->setConfig(400.0, 0.1, 0.5, 1.02);
|
||||
shadow_smoothing = 0.03;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
water_height->setValue(-0.3);
|
||||
|
|
|
@ -28,9 +28,12 @@ class DEFINITIONSHARED_EXPORT TerrainDefinition : public DefinitionNode {
|
|||
inline FloatNode *propWaterHeight() const {
|
||||
return water_height;
|
||||
}
|
||||
inline NoiseNode *propHeightNoise() const {
|
||||
return height_noise;
|
||||
}
|
||||
|
||||
double getGridHeight(int x, int z, bool with_painting);
|
||||
double getInterpolatedHeight(double x, double z, bool scaled, bool with_painting, bool water_offset = true);
|
||||
double getInterpolatedHeight(double x, double z, bool with_painting, bool water_offset = true);
|
||||
double getWaterOffset() const;
|
||||
unsigned long getMemoryStats();
|
||||
HeightInfo getHeightInfo();
|
||||
|
@ -40,19 +43,17 @@ class DEFINITIONSHARED_EXPORT TerrainDefinition : public DefinitionNode {
|
|||
void applyPreset(TerrainPreset preset, RandomGenerator &random = RandomGeneratorDefault);
|
||||
|
||||
public:
|
||||
double height;
|
||||
double shadow_smoothing;
|
||||
|
||||
TerrainHeightMap *height_map;
|
||||
bool has_painting;
|
||||
|
||||
double _detail;
|
||||
NoiseGenerator *_height_noise;
|
||||
double _min_height;
|
||||
double _max_height;
|
||||
|
||||
private:
|
||||
FloatNode *water_height;
|
||||
NoiseNode *height_noise;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,29 +20,29 @@ double TerrainHeightMap::getInitialValue(double x, double y) const {
|
|||
|
||||
void TerrainHeightMap::brushElevation(const PaintedGridBrush &brush, double x, double y, double value, bool commit) {
|
||||
PaintedGridBrushRaiseLower sbrush(brush);
|
||||
applyBrush(sbrush, x, y, value / terrain->height, commit);
|
||||
applyBrush(sbrush, x, y, value, commit);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::brushFlatten(const PaintedGridBrush &brush, double x, double y, double height, double force,
|
||||
bool commit) {
|
||||
PaintedGridBrushFlatten sbrush(brush, height);
|
||||
applyBrush(sbrush, x, y, force / terrain->height, commit);
|
||||
applyBrush(sbrush, x, y, force, commit);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::brushSmooth(const PaintedGridBrush &brush, double x, double y, double value, bool commit) {
|
||||
PaintedGridBrushSmooth sbrush(brush);
|
||||
applyBrush(sbrush, x, y, value / terrain->height, commit);
|
||||
applyBrush(sbrush, x, y, value, commit);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::brushAddNoise(const PaintedGridBrush &brush, double x, double y, NoiseGenerator *generator,
|
||||
double value, bool commit) {
|
||||
PaintedGridBrushAddNoise sbrush(brush, generator);
|
||||
applyBrush(sbrush, x, y, value / terrain->height, commit);
|
||||
applyBrush(sbrush, x, y, value, commit);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::brushReset(const PaintedGridBrush &brush, double x, double y, double value, bool commit) {
|
||||
PaintedGridBrushReset sbrush(brush);
|
||||
applyBrush(sbrush, x, y, value / terrain->height, commit);
|
||||
applyBrush(sbrush, x, y, value, commit);
|
||||
}
|
||||
|
||||
void TerrainHeightMap::clearPainting() {
|
||||
|
|
|
@ -32,9 +32,8 @@ void TextureLayerDefinition::validate() {
|
|||
|
||||
material->validate();
|
||||
|
||||
/* Update zone height range */
|
||||
const Scenery *scenery = getScenery();
|
||||
if (scenery) {
|
||||
// Update zone height range
|
||||
if (auto scenery = getScenery()) {
|
||||
TerrainDefinition *terrain = scenery->getTerrain();
|
||||
HeightInfo height_info = terrain->getHeightInfo();
|
||||
terrain_zone->setRelativeHeight(height_info.min_height, height_info.base_height, height_info.max_height);
|
||||
|
@ -80,15 +79,15 @@ void TextureLayerDefinition::applyPreset(TextureLayerPreset preset, RandomGenera
|
|||
material->shininess = 4.0;
|
||||
break;
|
||||
case TEXTURES_LAYER_PRESET_ROCK:
|
||||
terrain_zone->addHeightRangeQuick(1.0, 0.55, 0.7, 0.9, 1.0);
|
||||
displacement_noise->setConfig(1.0, 0.3, 0.5, 0.85);
|
||||
terrain_zone->addHeightRangeQuick(1.0, 0.6, 0.7, 0.87, 0.95);
|
||||
displacement_noise->setConfig(1.0, 0.4, 0.5, 0.85);
|
||||
detail_noise->setConfig(0.02, 0.04);
|
||||
material->setColor(0.6, 0.55, 0.57, 1.0);
|
||||
material->reflection = 0.006;
|
||||
material->shininess = 6.0;
|
||||
break;
|
||||
case TEXTURES_LAYER_PRESET_GRASS:
|
||||
terrain_zone->addHeightRangeQuick(1.0, 0.45, 0.5, 0.8, 1.0);
|
||||
terrain_zone->addHeightRangeQuick(1.0, 0.45, 0.5, 0.7, 0.9);
|
||||
terrain_zone->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.05, 0.4);
|
||||
displacement_noise->setConfig(0.4, 0.05);
|
||||
detail_noise->setConfig(0.01, 0.1);
|
||||
|
@ -98,7 +97,7 @@ void TextureLayerDefinition::applyPreset(TextureLayerPreset preset, RandomGenera
|
|||
break;
|
||||
case TEXTURES_LAYER_PRESET_SAND:
|
||||
terrain_zone->addHeightRangeQuick(1.0, 0.495, 0.505, 0.56, 0.63);
|
||||
terrain_zone->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.1, 0.4);
|
||||
terrain_zone->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.05, 0.3);
|
||||
displacement_noise->setConfig(0.04, 0.1, 0.5, 0.3);
|
||||
detail_noise->setConfig(0.004, 0.08);
|
||||
material->setColor(1.2, 1.1, 0.9, 1.0);
|
||||
|
@ -106,8 +105,8 @@ void TextureLayerDefinition::applyPreset(TextureLayerPreset preset, RandomGenera
|
|||
material->shininess = 1.0;
|
||||
break;
|
||||
case TEXTURES_LAYER_PRESET_SNOW:
|
||||
terrain_zone->addHeightRangeQuick(1.0, 0.77, 0.85, 1.0, 1.0);
|
||||
terrain_zone->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.2, 1.0);
|
||||
terrain_zone->addHeightRangeQuick(1.0, 0.87, 0.95, 10.0, 100.0);
|
||||
terrain_zone->addSlopeRangeQuick(1.0, 0.0, 0.0, 0.1, 1.0);
|
||||
displacement_noise->setConfig(0.4, 0.07);
|
||||
detail_noise->setConfig(0.01, 0.03);
|
||||
material->setColor(5.0, 5.0, 5.0, 1.0);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "Zone.h"
|
||||
|
||||
#include <cstring>
|
||||
#include "Curve.h"
|
||||
#include "PackStream.h"
|
||||
#include "Vector3.h"
|
||||
|
@ -39,15 +38,15 @@ void Zone::load(PackStream *stream) {
|
|||
}
|
||||
|
||||
void Zone::copy(DefinitionNode *_destination) const {
|
||||
Zone *destination = (Zone *)_destination;
|
||||
if (auto destination = static_cast<Zone *>(_destination)) {
|
||||
destination->absolute_height = absolute_height;
|
||||
destination->relative_height_min = relative_height_min;
|
||||
destination->relative_height_middle = relative_height_middle;
|
||||
destination->relative_height_max = relative_height_max;
|
||||
|
||||
destination->absolute_height = absolute_height;
|
||||
destination->relative_height_min = relative_height_min;
|
||||
destination->relative_height_middle = relative_height_middle;
|
||||
destination->relative_height_max = relative_height_max;
|
||||
|
||||
value_by_height->copy(destination->value_by_height);
|
||||
value_by_slope->copy(destination->value_by_slope);
|
||||
value_by_height->copy(destination->value_by_height);
|
||||
value_by_slope->copy(destination->value_by_slope);
|
||||
}
|
||||
}
|
||||
|
||||
void Zone::clear() {
|
||||
|
|
|
@ -59,8 +59,14 @@ static void startTestRender(SoftwareCanvasRenderer *renderer, const string &name
|
|||
}
|
||||
|
||||
static void testNoise() {
|
||||
// TODO Test all noise functions similarly
|
||||
|
||||
NoiseFunctionSimplex noise;
|
||||
|
||||
cout << "Testing simplex distribution..." << endl;
|
||||
auto report = noise.checkDistribution();
|
||||
cout << report;
|
||||
|
||||
string filename = getFileName("noise_simplex_cache_value");
|
||||
cout << "Rendering " << filename << "..." << endl;
|
||||
noise.getValueTexture()->saveToFile(filename);
|
||||
|
@ -136,7 +142,7 @@ static void testCloudQuality() {
|
|||
scenery.autoPreset(3);
|
||||
scenery.getCamera()->setLocation(Vector3(5.0, 5.0, 5.0));
|
||||
scenery.getCamera()->setTarget(Vector3(8.0, 7.25, 8.0));
|
||||
scenery.getTerrain()->height = 0.0;
|
||||
scenery.getTerrain()->propHeightNoise()->setConfig(0.0);
|
||||
scenery.getTerrain()->validate();
|
||||
|
||||
SoftwareCanvasRenderer renderer(&scenery);
|
||||
|
@ -182,7 +188,7 @@ static void testGodRays() {
|
|||
scenery.getAtmosphere()->setDayTime(12);
|
||||
scenery.getCamera()->setLocation(Vector3(0.0, 1.0, -50.0));
|
||||
scenery.getCamera()->setTarget(Vector3(0.0, 15.0, 0.0));
|
||||
scenery.getTerrain()->height = 0.0;
|
||||
scenery.getTerrain()->propHeightNoise()->setConfig(0.0);
|
||||
scenery.getTerrain()->validate();
|
||||
scenery.getClouds()->clear();
|
||||
|
||||
|
@ -408,15 +414,15 @@ static void testTextures() {
|
|||
}
|
||||
|
||||
void runTestSuite() {
|
||||
testAtmosphereBruneton();
|
||||
testCloudQuality();
|
||||
testCloudsNearGround();
|
||||
testGodRays();
|
||||
testGroundShadowQuality();
|
||||
testNearFrustum();
|
||||
testNoise();
|
||||
testTextures();
|
||||
testGodRays();
|
||||
testNearFrustum();
|
||||
testCloudsNearGround();
|
||||
testVegetationModels();
|
||||
testOpenGLVegetationImpostor();
|
||||
testRasterizationQuality();
|
||||
testTextures();
|
||||
testVegetationModels();
|
||||
testGroundShadowQuality();
|
||||
testCloudQuality();
|
||||
testAtmosphereBruneton();
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ void TerrainRenderer::setQuality(double factor) {
|
|||
}
|
||||
|
||||
double TerrainRenderer::getHeight(double x, double z, bool with_painting, bool water_offset) {
|
||||
return parent->getScenery()->getTerrain()->getInterpolatedHeight(x, z, true, with_painting, water_offset);
|
||||
return parent->getScenery()->getTerrain()->getInterpolatedHeight(x, z, with_painting, water_offset);
|
||||
}
|
||||
|
||||
TerrainRenderer::TerrainResult TerrainRenderer::getResult(double x, double z, bool with_painting) {
|
||||
|
|
|
@ -204,3 +204,27 @@ TEST(FractalNoise, Noise3d) {
|
|||
ASSERT_EQ(2, noise.calls);
|
||||
EXPECT_DOUBLE_EQ(3.2 + 3.25, result);
|
||||
}
|
||||
|
||||
TEST(FractalNoise, estimateRange) {
|
||||
TestFractalNoise noise(0.8);
|
||||
noise.setScaling(1.0, 1.0);
|
||||
noise.setStep(0.1);
|
||||
|
||||
double min, max;
|
||||
|
||||
noise.estimateRange(&min, &max, 10.0);
|
||||
EXPECT_DOUBLE_EQ(0.0, min);
|
||||
EXPECT_DOUBLE_EQ(0.0, max);
|
||||
|
||||
noise.estimateRange(&min, &max, 0.5);
|
||||
EXPECT_DOUBLE_EQ(-0.5, min);
|
||||
EXPECT_DOUBLE_EQ(0.5, max);
|
||||
|
||||
noise.estimateRange(&min, &max, 0.05);
|
||||
EXPECT_DOUBLE_EQ(-0.55, min);
|
||||
EXPECT_DOUBLE_EQ(0.55, max);
|
||||
|
||||
noise.estimateRange(&min, &max, 0.005);
|
||||
EXPECT_DOUBLE_EQ(-0.555, min);
|
||||
EXPECT_DOUBLE_EQ(0.555, max);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
#include "Scenery.h"
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLVertexArray.h"
|
||||
#include "TerrainDefinition.h"
|
||||
#include "NoiseNode.h"
|
||||
#include "TestToolNoise.h"
|
||||
#include "Vector3.h"
|
||||
|
||||
static void checkVertex(const OpenGLVertexArray *array, int index, const Vector3 &expected_location, double expected_u,
|
||||
|
@ -20,6 +23,7 @@ static void checkVertex(const OpenGLVertexArray *array, int index, const Vector3
|
|||
|
||||
TEST(OpenGLTerrainChunk, setFirstStepVertices) {
|
||||
Scenery scenery;
|
||||
scenery.getTerrain()->propHeightNoise()->forceSetGenerator(new ConstantFractalNoise(0.0));
|
||||
OpenGLRenderer renderer(&scenery);
|
||||
OpenGLTerrainChunk chunk(&renderer, 0.0, 0.0, 1.0, 1);
|
||||
|
||||
|
@ -40,6 +44,7 @@ TEST(OpenGLTerrainChunk, setFirstStepVertices) {
|
|||
|
||||
TEST(OpenGLTerrainChunk, augmentVertices) {
|
||||
Scenery scenery;
|
||||
scenery.getTerrain()->propHeightNoise()->forceSetGenerator(new ConstantFractalNoise(0.0));
|
||||
OpenGLRenderer renderer(&scenery);
|
||||
OpenGLTerrainChunk chunk(&renderer, 0.0, 0.0, 1.0, 1);
|
||||
|
||||
|
|
|
@ -8,13 +8,13 @@ TEST(OpenGLVariable, setNoise) {
|
|||
NoiseFunctionSimplex noise;
|
||||
|
||||
noise.setScaling(0.5, 2.0);
|
||||
noise.setStep(3.0, 0.4);
|
||||
noise.setStep(0.5, 0.4);
|
||||
|
||||
var.set(noise);
|
||||
|
||||
EXPECT_EQ(4, var.getIntValue());
|
||||
EXPECT_FLOAT_EQ(2.0f, var.getFloatArrayValue(0));
|
||||
EXPECT_FLOAT_EQ(1.0f, var.getFloatArrayValue(1));
|
||||
EXPECT_FLOAT_EQ(1.0f / 3.0f, var.getFloatArrayValue(2));
|
||||
EXPECT_FLOAT_EQ(1.2f, var.getFloatArrayValue(3));
|
||||
EXPECT_FLOAT_EQ(2.0f, var.getFloatArrayValue(2));
|
||||
EXPECT_FLOAT_EQ(0.2f, var.getFloatArrayValue(3));
|
||||
}
|
||||
|
|
|
@ -2,39 +2,51 @@
|
|||
|
||||
#include <cmath>
|
||||
#include "Maths.h"
|
||||
#include "NoiseGenerator.h"
|
||||
#include "NoiseNode.h"
|
||||
#include "TestToolNoise.h"
|
||||
#include "TerrainDefinition.h"
|
||||
#include "TerrainHeightMap.h"
|
||||
#include "PaintedGridBrush.h"
|
||||
#include "FloatNode.h"
|
||||
|
||||
/* Noise sin period is defined at 20.0 */
|
||||
#define X_FACTOR (Maths::PI / 10.0)
|
||||
// Noise sin period is defined at 20.0
|
||||
static constexpr double X_FACTOR = Maths::PI / 10.0;
|
||||
|
||||
static double _noise1dMock(double x) {
|
||||
return sin(x * X_FACTOR) * 0.5 + 0.5;
|
||||
}
|
||||
namespace {
|
||||
class SinFractalNoise : public FractalNoise {
|
||||
public:
|
||||
SinFractalNoise() {
|
||||
setScaling(1.0, 2.0);
|
||||
setStep(0.0);
|
||||
NoiseState state;
|
||||
state.setLevelCount(1);
|
||||
state.setLevel(0, 0.0, 0.0, 0.0);
|
||||
setState(state);
|
||||
}
|
||||
virtual ~SinFractalNoise();
|
||||
virtual double getBase1d(double x) const override {
|
||||
return sin(x * X_FACTOR) * 0.5;
|
||||
}
|
||||
virtual double getBase2d(double x, double) const override {
|
||||
return sin(x * X_FACTOR) * 0.5;
|
||||
}
|
||||
virtual double getBase3d(double x, double, double) const override {
|
||||
return sin(x * X_FACTOR) * 0.5;
|
||||
}
|
||||
};
|
||||
|
||||
static double _noise2dMock(double x, double) {
|
||||
return sin(x * X_FACTOR) * 0.5 + 0.5;
|
||||
}
|
||||
|
||||
static double _noise3dMock(double x, double, double) {
|
||||
return sin(x * X_FACTOR) * 0.5 + 0.5;
|
||||
SinFractalNoise::~SinFractalNoise() {
|
||||
}
|
||||
|
||||
class TerrainPainting_Test : public BaseTestCase {
|
||||
public:
|
||||
virtual ~TerrainPainting_Test();
|
||||
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
terrain = new TerrainDefinition(NULL);
|
||||
terrain->height = 3.0;
|
||||
terrain->_height_noise->clearLevels();
|
||||
terrain->propHeightNoise()->forceSetGenerator(new SinFractalNoise);
|
||||
terrain->propWaterHeight()->setValue(0.0);
|
||||
NoiseGenerator::NoiseLevel level = {1.0, 2.0, -1.0};
|
||||
terrain->_height_noise->addLevel(level);
|
||||
noise_state.resetOffsets();
|
||||
terrain->_height_noise->setState(noise_state);
|
||||
terrain->_height_noise->setCustomFunction(_noise1dMock, _noise2dMock, _noise3dMock);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
|
@ -44,6 +56,9 @@ class TerrainPainting_Test : public BaseTestCase {
|
|||
TerrainDefinition *terrain;
|
||||
NoiseState noise_state;
|
||||
};
|
||||
TerrainPainting_Test::~TerrainPainting_Test() {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TerrainPainting_Test, grid) {
|
||||
/* Test base grid */
|
||||
|
@ -63,12 +78,9 @@ TEST_F(TerrainPainting_Test, grid) {
|
|||
EXPECT_DOUBLE_EQ(-1.0, terrain->getGridHeight(-5, 0, 0));
|
||||
|
||||
/* Test interpolated result */
|
||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(0.0, 0.0, 0, 0), 0.0);
|
||||
EXPECT_DOUBLE_IN_RANGE(terrain->getInterpolatedHeight(0.5, 0.0, 0, 0), 0.1564, 0.1566);
|
||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(1.0, 0.0, 0, 0), sin(1.0 * X_FACTOR));
|
||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(0.0, 0.0, 1, 0), 0.0);
|
||||
EXPECT_DOUBLE_IN_RANGE(terrain->getInterpolatedHeight(0.5, 0.0, 1, 0), 3.0 * 0.1564, 3.0 * 0.1566);
|
||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(1.0, 0.0, 1, 0), 3.0 * sin(1.0 * X_FACTOR));
|
||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(0.0, 0.0, false, false), 0.0);
|
||||
EXPECT_DOUBLE_IN_RANGE(terrain->getInterpolatedHeight(0.5, 0.0, false, false), 0.1564, 0.1566);
|
||||
EXPECT_DOUBLE_EQ(terrain->getInterpolatedHeight(1.0, 0.0, false, false), sin(X_FACTOR));
|
||||
}
|
||||
|
||||
static void _checkBrushResultSides(TerrainDefinition *terrain, PaintedGridBrush *, double center, double midhard,
|
||||
|
@ -103,8 +115,7 @@ static void _checkBrushResult(TerrainDefinition *terrain, PaintedGridBrush *brus
|
|||
TEST_F(TerrainPainting_Test, brush_flatten) {
|
||||
/* Set up */
|
||||
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
||||
terrain->height = 1.0;
|
||||
terrain->_height_noise->forceValue(0.0);
|
||||
terrain->propHeightNoise()->forceSetGenerator(new ConstantFractalNoise(0.0));
|
||||
|
||||
/* Test flattening center at 0.5 */
|
||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
||||
|
@ -120,21 +131,13 @@ TEST_F(TerrainPainting_Test, brush_flatten) {
|
|||
/* Test cumulative effect */
|
||||
terrain->height_map->brushFlatten(brush, 0.0, 0.0, 0.5, 0.01, true);
|
||||
_checkBrushResult(terrain, &brush, 0.00995, 0.00995, 0.00995, 0.0049875, 0.0, 0.0, 0);
|
||||
|
||||
/* Test with height modifier */
|
||||
terrain->height = 10.0;
|
||||
terrain->height_map->clearPainting();
|
||||
_checkBrushResult(terrain, &brush, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
|
||||
terrain->height_map->brushFlatten(brush, 0.0, 0.0, 0.5, 1.0, true);
|
||||
_checkBrushResult(terrain, &brush, 0.05, 0.05, 0.05, 0.025, 0.0, 0.0, 0);
|
||||
}
|
||||
|
||||
TEST_F(TerrainPainting_Test, brush_reset) {
|
||||
/* Set up */
|
||||
PaintedGridBrush brush(2.0, 2.0, 4.0);
|
||||
PaintedGridBrush brush_full(4.0, 0.0, 4.0);
|
||||
terrain->height = 1.0;
|
||||
terrain->_height_noise->forceValue(1.0);
|
||||
terrain->propHeightNoise()->forceSetGenerator(new ConstantFractalNoise(1.0));
|
||||
|
||||
/* Test resetting at center */
|
||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
||||
|
@ -154,13 +157,4 @@ TEST_F(TerrainPainting_Test, brush_reset) {
|
|||
/* Test cumulative effect */
|
||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 0.1, true);
|
||||
_checkBrushResult(terrain, &brush, 1.81, 1.81, 1.81, 1.9025, 2.0, 1.0, 0);
|
||||
|
||||
/* Test with height modifier */
|
||||
terrain->height = 10.0;
|
||||
terrain->height_map->clearPainting();
|
||||
_checkBrushResult(terrain, &brush, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);
|
||||
terrain->height_map->brushFlatten(brush_full, 0.0, 0.0, 2.0, 1.0, true);
|
||||
_checkBrushResult(terrain, &brush, 1.1, 1.1, 1.1, 1.1, 1.1, 1.0, 0);
|
||||
terrain->height_map->brushReset(brush, 0.0, 0.0, 0.1, true);
|
||||
_checkBrushResult(terrain, &brush, 1.099, 1.099, 1.099, 1.0995, 1.1, 1.0, 0);
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ namespace {
|
|||
class ConstantFractalNoise : public FractalNoise {
|
||||
public:
|
||||
ConstantFractalNoise(double value) : value(value) {
|
||||
// The noise will yield its value at first iteration, then its height will collapse to 0
|
||||
setScaling(1.0, 0.0);
|
||||
// The noise will yield its value at first iteration, then will collapse to 0
|
||||
setStep(0.0);
|
||||
}
|
||||
virtual double getBase3d(double, double, double) const {
|
||||
virtual double getBase3d(double, double, double) const override {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue