diff --git a/src/basics/FractalNoise.cpp b/src/basics/FractalNoise.cpp index 0570aff..e5d9ec5 100644 --- a/src/basics/FractalNoise.cpp +++ b/src/basics/FractalNoise.cpp @@ -166,6 +166,19 @@ void FractalNoise::estimateRange(double *min, double *max, double detail) const } } +void FractalNoise::normalizeRange(double norm, double detail, bool adjust_scaling) { + double min, max; + estimateRange(&min, &max, detail); + + if (max > 0.0) { + double factor = norm / max; + height *= factor; + if (adjust_scaling) { + scaling /= factor; + } + } +} + double FractalNoise::getBase1d(double x) const { return getBase2d(x, 0.0); } diff --git a/src/basics/FractalNoise.h b/src/basics/FractalNoise.h index c9560e9..595a5a9 100644 --- a/src/basics/FractalNoise.h +++ b/src/basics/FractalNoise.h @@ -59,6 +59,13 @@ class BASICSSHARED_EXPORT FractalNoise { */ void estimateRange(double *min, double *max, double detail = 0.000001) const; + /** + * Normalize the range of values, to be in [-norm, norm], for the given detail. + * + * If "adjust_scaling" is set to true, scaling will be changed accordingly. + */ + void normalizeRange(double norm = 1.0, double detail = 0.000001, bool adjust_scaling = false); + virtual double getBase1d(double x) const; virtual double getBase2d(double x, double y) const; /** diff --git a/src/definition/CloudLayerDefinition.cpp b/src/definition/CloudLayerDefinition.cpp index 0628919..9a408fa 100644 --- a/src/definition/CloudLayerDefinition.cpp +++ b/src/definition/CloudLayerDefinition.cpp @@ -8,7 +8,7 @@ CloudLayerDefinition::CloudLayerDefinition(DefinitionNode *parent, const string &name) : DefinitionNode(parent, name, "cloudlayer") { - type = CIRRUS; + type = STRATOCUMULUS; altitude = 0.5; scaling = 0.5; coverage = 0.5; @@ -64,14 +64,14 @@ void CloudLayerDefinition::load(PackStream *stream) { void CloudLayerDefinition::copy(DefinitionNode *_destination) const { DefinitionNode::copy(_destination); - CloudLayerDefinition *destination = (CloudLayerDefinition *)_destination; + if (auto destination = static_cast(_destination)) { + destination->type = type; + destination->altitude = altitude; + destination->scaling = scaling; + destination->coverage = coverage; - destination->type = type; - destination->altitude = altitude; - destination->scaling = scaling; - destination->coverage = coverage; - - noise_state.copy(&destination->noise_state); + noise_state.copy(&destination->noise_state); + } } void CloudLayerDefinition::validate() { diff --git a/src/definition/CloudLayerDefinition.h b/src/definition/CloudLayerDefinition.h index d0e3b52..66a5d9e 100644 --- a/src/definition/CloudLayerDefinition.h +++ b/src/definition/CloudLayerDefinition.h @@ -36,16 +36,16 @@ class DEFINITIONSHARED_EXPORT CloudLayerDefinition : public DefinitionNode { public: typedef enum { - STRATUS, - NIMBOSTRATUS, - CUMULUS, + //STRATUS, + //NIMBOSTRATUS, + //CUMULUS, STRATOCUMULUS, - ALTOCUMULUS, - ALTOSTRATUS, - CUMULONIMBUS, - CIRROCUMULUS, - CIRROSTRATUS, - CIRRUS, + //ALTOCUMULUS, + //ALTOSTRATUS, + //CUMULONIMBUS, + //CIRROCUMULUS, + //CIRROSTRATUS, + //CIRRUS, _COUNT } CloudsType; diff --git a/src/interface/commandline/tests.cpp b/src/interface/commandline/tests.cpp index cacb990..19e0cf8 100644 --- a/src/interface/commandline/tests.cpp +++ b/src/interface/commandline/tests.cpp @@ -467,8 +467,9 @@ static void testCloudsLighting() { *min_altitude = 10.0 - scale; *max_altitude = 10.0 + scale; } - virtual double getDensity(const Vector3 &location, double) const override { - return 1.0 - location.sub(Vector3(0.0, 10.0, 0.0)).getNorm() / scale; + virtual CloudDensityInfo getDensity(const Vector3 &location, double) const override { + double val = 1.0 - location.sub(Vector3(0.0, 10.0, 0.0)).getNorm() / scale; + return {val, val}; } double scale; }; @@ -582,19 +583,19 @@ static void testCanvasAliasing() { } void runTestSuite() { - testNoise(); - testCanvasAliasing(); - testTextures(); - testGodRays(); - testCelestialBodies(); - testNearFrustum(); - testCloudsLighting(); +// testNoise(); +// testCanvasAliasing(); +// testTextures(); +// testGodRays(); +// testCelestialBodies(); +// testNearFrustum(); +// testCloudsLighting(); testCloudModels(); - testCloudsNearGround(); - testVegetationModels(); - testOpenGLVegetationImpostor(); - testRasterizationQuality(); - testGroundShadowQuality(); - testCloudQuality(); - testAtmosphereBruneton(); +// testCloudsNearGround(); +// testVegetationModels(); +// testOpenGLVegetationImpostor(); +// testRasterizationQuality(); +// testGroundShadowQuality(); +// testCloudQuality(); +// testAtmosphereBruneton(); } diff --git a/src/render/software/BaseCloudLayerRenderer.cpp b/src/render/software/BaseCloudLayerRenderer.cpp index 8499370..7dcd098 100644 --- a/src/render/software/BaseCloudLayerRenderer.cpp +++ b/src/render/software/BaseCloudLayerRenderer.cpp @@ -2,6 +2,7 @@ #include "clouds/BaseCloudsModel.h" #include "Vector3.h" +#include "Color.h" BaseCloudLayerRenderer::BaseCloudLayerRenderer(SoftwareRenderer *parent) : parent(parent) { setQuality(0.5); diff --git a/src/render/software/CloudBasicLayerRenderer.cpp b/src/render/software/CloudBasicLayerRenderer.cpp index 2fb852a..7b4e350 100644 --- a/src/render/software/CloudBasicLayerRenderer.cpp +++ b/src/render/software/CloudBasicLayerRenderer.cpp @@ -51,7 +51,7 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 double current_total_length, current_inside_length; double step_length, segment_length; double min_step, max_step; - double noise_distance, previous_noise_distance; + BaseCloudsModel::CloudDensityInfo info, previous_info; Vector3 walker, step, segment_start, offset; double render_precision; @@ -77,9 +77,9 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 segment_length = 0.0; walker = start; offset = Vector3(model->getLayer()->propXOffset()->getValue(), 0.0, model->getLayer()->propZOffset()->getValue()); - noise_distance = model->getDensity(start.add(offset), base_detail); - previous_noise_distance = noise_distance; - inside = noise_distance > 0.0; + info = model->getDensity(start.add(offset), 1.0); + previous_info = info; + inside = info.density > 0.0; if (inside) { segment_start = start; } @@ -89,19 +89,24 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 do { walker = walker.add(step); step_length = step.getNorm(); - noise_distance = stop ? 0.0 : model->getDensity(walker.add(offset), base_detail); + if (stop) { + info.density = 0.0; + info.border_distance = 0.0; + } else { + info = model->getDensity(walker.add(offset), 1.0); + } current_total_length += step_length; - if (noise_distance > 0.0) { + if (info.density > 0.0) { if (inside) { // inside the cloud segment_length += step_length; current_inside_length += step_length; - step = direction.scale((noise_distance < 1.0) ? render_precision : (noise_distance * render_precision)); + step = direction.scale((info.border_distance < 1.0) ? render_precision : (info.border_distance * render_precision)); } else { // entering the cloud inside = 1; - segment_length = step_length - Maths::zeroPoint(step_length, previous_noise_distance, noise_distance); + segment_length = step_length - Maths::zeroPoint(step_length, previous_info.density, info.density); assert(segment_length >= 0.0 && segment_length <= step_length); segment_start = walker.add(direction.scale(-segment_length)); current_inside_length += segment_length; @@ -110,7 +115,7 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 } else { if (inside) { // exiting the cloud - double exit_length = Maths::zeroPoint(step_length, previous_noise_distance, noise_distance); + double exit_length = Maths::zeroPoint(step_length, previous_info.density, info.density); assert(exit_length >= 0.0); segment_length += exit_length; current_inside_length += exit_length; @@ -128,12 +133,12 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 } else { // searching for a cloud step = - direction.scale((noise_distance > -1.0) ? render_precision : (-noise_distance * render_precision)); + direction.scale((info.border_distance < 1.0) ? render_precision : (info.border_distance * render_precision)); } } render_precision *= 1.0 + 0.001 / (quality + 0.1); - previous_noise_distance = noise_distance; + previous_info = info; stop = not(walker.y >= ymin - 0.001 && walker.y <= ymax + 0.001 && current_total_length < max_total_length && current_inside_length < max_inside_length); } while (inside or not stop); @@ -143,14 +148,6 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 return segment_count; } -static inline Vector3 _getPseudoNormal(const BaseCloudsModel *model, const Vector3 &base, const Vector3 &direction) { - double precision = 0.3; - double base_density = model->getDensity(base, precision); // TODO keep - double density = model->getDensity(base.add(direction.scale(precision * 10.0)), precision); - double diff = base_density - density; - return direction.scale(diff > 0.0 ? diff : 0.0); -} - Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location) { int i, segment_count; double max_length, total_length, inside_length; @@ -183,15 +180,8 @@ Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &e segment_count = findSegments(model, start, direction, 30, transparency_depth, max_length, &inside_length, &total_length, segments, 0.001); for (i = segment_count - 1; i >= 0; i--) { - Vector3 normal = VECTOR_ZERO; const Vector3 &location = segments[i].start; - normal = normal.add(_getPseudoNormal(model, location, VECTOR_UP)); - normal = normal.add(_getPseudoNormal(model, location, VECTOR_DOWN)); - normal = normal.add(_getPseudoNormal(model, location, VECTOR_EAST)); - normal = normal.add(_getPseudoNormal(model, location, VECTOR_WEST)); - normal = normal.add(_getPseudoNormal(model, location, VECTOR_NORTH)); - normal = normal.add(_getPseudoNormal(model, location, VECTOR_SOUTH)); - col = parent->applyLightingToSurface(location, normal.normalize(), material); + col = parent->applyLightingToSurface(location, model->getNormal(location, 1.0), material); col.a = (segments[i].length >= transparency_depth) ? 1.0 : (segments[i].length / transparency_depth); result.mask(col); diff --git a/src/render/software/CloudsRenderer.cpp b/src/render/software/CloudsRenderer.cpp index a1e7d39..f7c1e7e 100644 --- a/src/render/software/CloudsRenderer.cpp +++ b/src/render/software/CloudsRenderer.cpp @@ -8,11 +8,9 @@ #include "CloudBasicLayerRenderer.h" #include "CameraDefinition.h" #include "Logs.h" +#include "Color.h" #include "clouds/BaseCloudsModel.h" -#include "clouds/CloudModelAltoCumulus.h" -#include "clouds/CloudModelCirrus.h" -#include "clouds/CloudModelCumuloNimbus.h" #include "clouds/CloudModelStratoCumulus.h" CloudsRenderer::CloudsRenderer(SoftwareRenderer *parent) : parent(parent) { @@ -70,21 +68,6 @@ void CloudsRenderer::update() { case CloudLayerDefinition::STRATOCUMULUS: model = new CloudModelStratoCumulus(layer); break; - case CloudLayerDefinition::ALTOCUMULUS: - model = new CloudModelAltoCumulus(layer); - break; - case CloudLayerDefinition::CIRRUS: - model = new CloudModelCirrus(layer); - break; - case CloudLayerDefinition::CUMULONIMBUS: - model = new CloudModelCumuloNimbus(layer); - break; - case CloudLayerDefinition::STRATUS: - case CloudLayerDefinition::NIMBOSTRATUS: - case CloudLayerDefinition::CUMULUS: - case CloudLayerDefinition::ALTOSTRATUS: - case CloudLayerDefinition::CIRROCUMULUS: - case CloudLayerDefinition::CIRROSTRATUS: case CloudLayerDefinition::_COUNT: model = new BaseCloudsModel(layer); break; diff --git a/src/render/software/clouds/BaseCloudsModel.cpp b/src/render/software/clouds/BaseCloudsModel.cpp index 6e56873..4210acd 100644 --- a/src/render/software/clouds/BaseCloudsModel.cpp +++ b/src/render/software/clouds/BaseCloudsModel.cpp @@ -1,6 +1,7 @@ #include "BaseCloudsModel.h" #include "CloudLayerDefinition.h" +#include "Vector3.h" BaseCloudsModel::BaseCloudsModel(CloudLayerDefinition *layer) : layer(layer) { } @@ -24,21 +25,26 @@ void BaseCloudsModel::getDetailRange(double *min_step, double *max_step) const { *max_step = thickness * 0.2; } -double BaseCloudsModel::getProbability(const Vector3 &, double) const { - // FIXME not used ! - return 1.0; +BaseCloudsModel::CloudDensityInfo BaseCloudsModel::getDensity(const Vector3 &, double) const { + return {0.0, 1.0}; } -double BaseCloudsModel::getDensity(const Vector3 &, double) const { - return 0.0; +static inline Vector3 _getPseudoNormal(const BaseCloudsModel *model, const Vector3 &base, const Vector3 &direction, double base_density, double precision) { + double density = model->getDensity(base.add(direction.scale(precision * 10.0)), precision).density; + double diff = base_density - density; + return direction.scale(diff > 0.0 ? diff : 0.0); } -Color BaseCloudsModel::filterLight(const Color &light, double, double) const { - // FIXME not used ! - return light; -} - -Color BaseCloudsModel::applyLightExit(const Color &light, const Vector3 &, const Vector3 &) const { - // FIXME not used ! - return light; +Vector3 BaseCloudsModel::getNormal(const Vector3 &location, double quality) const +{ + double precision = 0.3; + Vector3 normal = VECTOR_ZERO; + double base_density = getDensity(location, precision).density; + normal = normal.add(_getPseudoNormal(this, location, VECTOR_UP, base_density, precision)); + normal = normal.add(_getPseudoNormal(this, location, VECTOR_DOWN, base_density, precision)); + normal = normal.add(_getPseudoNormal(this, location, VECTOR_EAST, base_density, precision)); + normal = normal.add(_getPseudoNormal(this, location, VECTOR_WEST, base_density, precision)); + normal = normal.add(_getPseudoNormal(this, location, VECTOR_NORTH, base_density, precision)); + normal = normal.add(_getPseudoNormal(this, location, VECTOR_SOUTH, base_density, precision)); + return normal.normalize(); } diff --git a/src/render/software/clouds/BaseCloudsModel.h b/src/render/software/clouds/BaseCloudsModel.h index efa36ab..59c9737 100644 --- a/src/render/software/clouds/BaseCloudsModel.h +++ b/src/render/software/clouds/BaseCloudsModel.h @@ -3,8 +3,6 @@ #include "../software_global.h" -#include "Color.h" - namespace paysages { namespace software { @@ -12,23 +10,39 @@ namespace software { * Abstract class for all cloud models (cirrus, cumulus...). */ class SOFTWARESHARED_EXPORT BaseCloudsModel { + public: + typedef struct { + double density; + double border_distance; + } CloudDensityInfo; + public: BaseCloudsModel(CloudLayerDefinition *layer); virtual ~BaseCloudsModel(); + inline CloudLayerDefinition *getLayer() const { + return layer; + } + virtual void update(); virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const; virtual void getDetailRange(double *min_step, double *max_step) const; - virtual double getProbability(const Vector3 &location, double radius) const; - virtual double getDensity(const Vector3 &location, double precision) const; - virtual Color filterLight(const Color &light, double length, double density) const; - virtual Color applyLightExit(const Color &light, const Vector3 &light_direction, - const Vector3 &direction_to_eye) const; - inline CloudLayerDefinition *getLayer() const { - return layer; - } + /** + * Get the cloud density info at a given location. + * + * This will contain the local density (0.0-1.0), and an estimated distance to the nearest border. + */ + virtual CloudDensityInfo getDensity(const Vector3 &location, double quality) const; + + /** + * Get the normal vector at a given location, to be used by lighting. + * + * The length of the result vector indicates its relevance. A short vector marks an area + * where applying a normal vector is not relevant. + */ + virtual Vector3 getNormal(const Vector3 &location, double quality) const; protected: CloudLayerDefinition *layer; diff --git a/src/render/software/clouds/CloudModelAltoCumulus.cpp b/src/render/software/clouds/CloudModelAltoCumulus.cpp deleted file mode 100644 index f8df3e8..0000000 --- a/src/render/software/clouds/CloudModelAltoCumulus.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "CloudModelAltoCumulus.h" - -#include "NoiseGenerator.h" -#include "Vector3.h" -#include "CloudLayerDefinition.h" - -CloudModelAltoCumulus::CloudModelAltoCumulus(CloudLayerDefinition *layer) : BaseCloudsModel(layer) { - noise = new NoiseGenerator(); -} - -CloudModelAltoCumulus::~CloudModelAltoCumulus() { - delete noise; -} - -void CloudModelAltoCumulus::update() { - noise->clearLevels(); - noise->addLevelSimple(4.0, -1.0, 1.0); - noise->addLevelSimple(1.0 / 2.0, -0.6, 0.6); - noise->addLevelSimple(1.0 / 4.0, -0.3, 0.3); - noise->addLevelSimple(1.0 / 10.0, -0.15, 0.15); - noise->addLevelSimple(1.0 / 20.0, -0.09, 0.09); - noise->addLevelSimple(1.0 / 40.0, -0.06, 0.06); - noise->addLevelSimple(1.0 / 60.0, -0.03, 0.03); - noise->addLevelSimple(1.0 / 80.0, -0.015, 0.015); - noise->addLevelSimple(1.0 / 100.0, -0.06, 0.06); - noise->normalizeAmplitude(-4.0, 3.0, 0); - noise->setState(layer->getNoiseState()); -} - -void CloudModelAltoCumulus::getAltitudeRange(double *min_altitude, double *max_altitude) const { - *min_altitude = 15.0 + 10.0 * layer->altitude; - *max_altitude = *min_altitude + 18.0 * layer->scaling; -} - -double CloudModelAltoCumulus::getDensity(const Vector3 &location, double) const { - double val; - double min_altitude, max_altitude; - double noise_scaling = 18.0 * layer->scaling; - - getAltitudeRange(&min_altitude, &max_altitude); - - if (location.y < min_altitude || location.y > max_altitude) { - return 0.0; - } else { - double x = 0.6 * location.x / noise_scaling; - double y = (location.y - min_altitude) / noise_scaling; - double z = 0.6 * location.z / noise_scaling; - - // double coverage = layer->coverage * layer->_coverage_by_altitude->getValue((position.y - layer->altitude) / - // layer->scaling); - double coverage = layer->coverage; - - val = 0.5 * noise->get3DTotal(x, y, z); - return val - 1.1 + coverage; - } -} diff --git a/src/render/software/clouds/CloudModelAltoCumulus.h b/src/render/software/clouds/CloudModelAltoCumulus.h deleted file mode 100644 index 306c8cb..0000000 --- a/src/render/software/clouds/CloudModelAltoCumulus.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef CLOUDMODELALTOCUMULUS_H -#define CLOUDMODELALTOCUMULUS_H - -#include "../software_global.h" - -#include "BaseCloudsModel.h" - -namespace paysages { -namespace software { - -class CloudModelAltoCumulus : public BaseCloudsModel { - public: - CloudModelAltoCumulus(CloudLayerDefinition *layer); - virtual ~CloudModelAltoCumulus(); - - virtual void update() override; - - virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override; - virtual double getDensity(const Vector3 &location, double precision) const override; - - private: - NoiseGenerator *noise; -}; -} -} - -#endif // CLOUDMODELALTOCUMULUS_H diff --git a/src/render/software/clouds/CloudModelCirrus.cpp b/src/render/software/clouds/CloudModelCirrus.cpp deleted file mode 100644 index 1fcdb45..0000000 --- a/src/render/software/clouds/CloudModelCirrus.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "CloudModelCirrus.h" - -#include "NoiseGenerator.h" -#include "Vector3.h" -#include "CloudLayerDefinition.h" - -CloudModelCirrus::CloudModelCirrus(CloudLayerDefinition *layer) : BaseCloudsModel(layer) { - noise = new NoiseGenerator(); -} - -CloudModelCirrus::~CloudModelCirrus() { - delete noise; -} - -void CloudModelCirrus::update() { - noise->clearLevels(); - noise->addLevelSimple(1.0, -1.0, 1.0); - noise->addLevelSimple(1.0 / 6.0, -0.6, 0.6); - noise->addLevelSimple(1.0 / 10.0, -0.15, 0.15); - noise->addLevelSimple(1.0 / 20.0, -0.09, 0.09); - noise->addLevelSimple(1.0 / 40.0, -0.06, 0.06); - noise->addLevelSimple(1.0 / 120.0, -0.03, 0.03); - noise->addLevelSimple(1.0 / 300.0, -0.01, 0.01); - noise->normalizeAmplitude(-4.0, 3.0, 0); - noise->setState(layer->getNoiseState()); -} - -void CloudModelCirrus::getAltitudeRange(double *min_altitude, double *max_altitude) const { - *min_altitude = 45.0 + 20.0 * layer->altitude; - *max_altitude = *min_altitude + 20.0 * layer->scaling; -} - -double CloudModelCirrus::getDensity(const Vector3 &location, double) const { - double val; - double min_altitude, max_altitude; - double noise_scaling = 30.0 * layer->scaling; - - getAltitudeRange(&min_altitude, &max_altitude); - - if (location.y < min_altitude || location.y > max_altitude) { - return 0.0; - } else { - double x = 0.03 * location.x / noise_scaling; - double y = (location.y - min_altitude) / noise_scaling; - double z = 0.03 * location.z / noise_scaling; - - // double coverage = layer->coverage * layer->_coverage_by_altitude->getValue((position.y - layer->altitude) / - // layer->scaling); - double coverage = layer->coverage; - - val = 0.6 * noise->get3DTotal(x, y, z); - return val - 1.1 + coverage; - } -} diff --git a/src/render/software/clouds/CloudModelCirrus.h b/src/render/software/clouds/CloudModelCirrus.h deleted file mode 100644 index 7b2b56b..0000000 --- a/src/render/software/clouds/CloudModelCirrus.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef CLOUDMODELCIRRUS_H -#define CLOUDMODELCIRRUS_H - -#include "../software_global.h" - -#include "BaseCloudsModel.h" - -namespace paysages { -namespace software { - -class CloudModelCirrus : public BaseCloudsModel { - public: - CloudModelCirrus(CloudLayerDefinition *layer); - virtual ~CloudModelCirrus(); - - virtual void update() override; - - virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override; - virtual double getDensity(const Vector3 &location, double precision) const override; - - private: - NoiseGenerator *noise; -}; -} -} - -#endif // CLOUDMODELCIRRUS_H diff --git a/src/render/software/clouds/CloudModelCumuloNimbus.cpp b/src/render/software/clouds/CloudModelCumuloNimbus.cpp deleted file mode 100644 index dfa0337..0000000 --- a/src/render/software/clouds/CloudModelCumuloNimbus.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "CloudModelCumuloNimbus.h" - -#include "NoiseGenerator.h" -#include "Vector3.h" -#include "CloudLayerDefinition.h" - -CloudModelCumuloNimbus::CloudModelCumuloNimbus(CloudLayerDefinition *layer) : BaseCloudsModel(layer) { - noise = new NoiseGenerator(); -} - -CloudModelCumuloNimbus::~CloudModelCumuloNimbus() { - delete noise; -} - -void CloudModelCumuloNimbus::update() { - noise->clearLevels(); - noise->addLevelSimple(8.0, -1.0, 1.0); - noise->addLevelSimple(7.0 / 2.0, -0.6, 0.6); - noise->addLevelSimple(6.0 / 4.0, -0.3, 0.3); - noise->addLevelSimple(5.0 / 10.0, -0.15, 0.15); - /*noise->addLevelSimple(1.0 / 20.0, -0.09, 0.09); - noise->addLevelSimple(1.0 / 40.0, -0.06, 0.06); - noise->addLevelSimple(1.0 / 60.0, -0.03, 0.03);*/ - noise->addLevelSimple(1.0 / 80.0, -0.015, 0.015); - noise->addLevelSimple(1.0 / 100.0, -0.06, 0.06); - noise->addLevelSimple(1.0 / 150.0, -0.015, 0.015); - noise->addLevelSimple(1.0 / 200.0, -0.009, 0.009); - noise->addLevelSimple(1.0 / 400.0, -0.024, 0.024); - noise->addLevelSimple(1.0 / 800.0, -0.003, 0.003); - noise->addLevelSimple(1.0 / 1000.0, -0.0015, 0.0015); - noise->normalizeAmplitude(-3.0, 4.0, 0); - noise->setState(layer->getNoiseState()); -} - -void CloudModelCumuloNimbus::getAltitudeRange(double *min_altitude, double *max_altitude) const { - *min_altitude = 5.0 + 10.0 * layer->altitude; - *max_altitude = *min_altitude + 50.0 + 50.0 * layer->scaling; -} - -double CloudModelCumuloNimbus::getDensity(const Vector3 &location, double) const { - double val; - double min_altitude, max_altitude; - double noise_scaling = 60.0 * layer->scaling; - - getAltitudeRange(&min_altitude, &max_altitude); - - if (location.y < min_altitude || location.y > max_altitude) { - return 0.0; - } else { - double x = 1.5 * location.x / noise_scaling; - double y = (location.y - min_altitude) / noise_scaling; - double z = 1.5 * location.z / noise_scaling; - - // double coverage = layer->coverage * layer->_coverage_by_altitude->getValue((position.y - layer->altitude) / - // layer->scaling); - double coverage = layer->coverage; - - val = 0.5 * noise->get3DTotal(x, y, z); - return val - 1.0 + coverage; - } -} diff --git a/src/render/software/clouds/CloudModelCumuloNimbus.h b/src/render/software/clouds/CloudModelCumuloNimbus.h deleted file mode 100644 index 6d329bc..0000000 --- a/src/render/software/clouds/CloudModelCumuloNimbus.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef CLOUDMODELCUMULONIMBUS_H -#define CLOUDMODELCUMULONIMBUS_H - -#include "../software_global.h" - -#include "BaseCloudsModel.h" - -namespace paysages { -namespace software { - -class CloudModelCumuloNimbus : public BaseCloudsModel { - public: - CloudModelCumuloNimbus(CloudLayerDefinition *layer); - virtual ~CloudModelCumuloNimbus(); - - virtual void update() override; - - virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override; - virtual double getDensity(const Vector3 &location, double precision) const override; - - private: - NoiseGenerator *noise; -}; -} -} - -#endif // CLOUDMODELCUMULONIMBUS_H diff --git a/src/render/software/clouds/CloudModelStratoCumulus.cpp b/src/render/software/clouds/CloudModelStratoCumulus.cpp index f2b83a6..6fe8d0c 100644 --- a/src/render/software/clouds/CloudModelStratoCumulus.cpp +++ b/src/render/software/clouds/CloudModelStratoCumulus.cpp @@ -1,11 +1,13 @@ #include "CloudModelStratoCumulus.h" -#include "NoiseGenerator.h" +#include +#include "NoiseFunctionSimplex.h" #include "Vector3.h" #include "CloudLayerDefinition.h" CloudModelStratoCumulus::CloudModelStratoCumulus(CloudLayerDefinition *layer) : BaseCloudsModel(layer) { - noise = new NoiseGenerator(); + noise = new NoiseFunctionSimplex(); + base_detail = 0.1; } CloudModelStratoCumulus::~CloudModelStratoCumulus() { @@ -13,23 +15,10 @@ CloudModelStratoCumulus::~CloudModelStratoCumulus() { } void CloudModelStratoCumulus::update() { - noise->clearLevels(); - noise->addLevelSimple(1.0, -1.0, 1.0); - noise->addLevelSimple(1.0 / 2.0, -0.6, 0.6); - noise->addLevelSimple(1.0 / 4.0, -0.3, 0.3); - noise->addLevelSimple(1.0 / 10.0, -0.15, 0.15); - noise->addLevelSimple(1.0 / 20.0, -0.09, 0.09); - noise->addLevelSimple(1.0 / 40.0, -0.06, 0.06); - noise->addLevelSimple(1.0 / 60.0, -0.03, 0.03); - noise->addLevelSimple(1.0 / 80.0, -0.015, 0.015); - noise->addLevelSimple(1.0 / 100.0, -0.06, 0.06); - noise->addLevelSimple(1.0 / 150.0, -0.015, 0.015); - noise->addLevelSimple(1.0 / 200.0, -0.009, 0.009); - noise->addLevelSimple(1.0 / 400.0, -0.024, 0.024); - noise->addLevelSimple(1.0 / 800.0, -0.003, 0.003); - noise->addLevelSimple(1.0 / 1000.0, -0.0015, 0.0015); - noise->normalizeAmplitude(-3.0, 3.0, 0); noise->setState(layer->getNoiseState()); + + noise->setScaling(30.0 * layer->scaling); + noise->normalizeRange(1.0, base_detail); } void CloudModelStratoCumulus::getAltitudeRange(double *min_altitude, double *max_altitude) const { @@ -37,25 +26,19 @@ void CloudModelStratoCumulus::getAltitudeRange(double *min_altitude, double *max *max_altitude = *min_altitude + 11.0 * layer->scaling; } -double CloudModelStratoCumulus::getDensity(const Vector3 &location, double precision) const { +BaseCloudsModel::CloudDensityInfo CloudModelStratoCumulus::getDensity(const Vector3 &location, double quality) const { double val; double min_altitude, max_altitude; - double noise_scaling = 30.0 * layer->scaling; getAltitudeRange(&min_altitude, &max_altitude); - if (location.y < min_altitude || location.y > max_altitude) { - return 0.0; + if (location.y < min_altitude) { + return {0.0, min_altitude - location.y}; + } else if (location.y > max_altitude) { + return {0.0, location.y - max_altitude}; } else { - double x = 0.3 * location.x / noise_scaling; - double y = (location.y - min_altitude) / noise_scaling; - double z = 0.3 * location.z / noise_scaling; - - // double coverage = layer->coverage * layer->_coverage_by_altitude->getValue((position.y - layer->altitude) / - // layer->scaling); - double coverage = layer->coverage; - - val = 0.5 * noise->get3DDetail(x, y, z, precision); - return val - 0.9 + coverage; + val = noise->get3d(base_detail, 0.3 * location.x, location.y - min_altitude, 0.3 * location.z); + val = val - 0.8 + layer->coverage; + return {val, fabs(val)}; } } diff --git a/src/render/software/clouds/CloudModelStratoCumulus.h b/src/render/software/clouds/CloudModelStratoCumulus.h index 027535f..8bc2ccd 100644 --- a/src/render/software/clouds/CloudModelStratoCumulus.h +++ b/src/render/software/clouds/CloudModelStratoCumulus.h @@ -16,10 +16,11 @@ class CloudModelStratoCumulus : public BaseCloudsModel { virtual void update() override; virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override; - virtual double getDensity(const Vector3 &location, double precision) const override; + virtual CloudDensityInfo getDensity(const Vector3 &location, double quality) const override; private: - NoiseGenerator *noise; + FractalNoise *noise; + double base_detail; }; } } diff --git a/src/tests/FractalNoise_Test.cpp b/src/tests/FractalNoise_Test.cpp index 04a908e..a463611 100644 --- a/src/tests/FractalNoise_Test.cpp +++ b/src/tests/FractalNoise_Test.cpp @@ -228,3 +228,16 @@ TEST(FractalNoise, estimateRange) { EXPECT_DOUBLE_EQ(-0.555, min); EXPECT_DOUBLE_EQ(0.555, max); } + +TEST(FractalNoise, normalizeRange) { + TestFractalNoise noise(0.8); + noise.setScaling(1.0, 1.0); + noise.setStep(0.1); + + double min, max; + + noise.normalizeRange(1.8, 0.01); + noise.estimateRange(&min, &max, 0.01); + EXPECT_DOUBLE_EQ(-1.8, min); + EXPECT_DOUBLE_EQ(1.8, max); +}