WIP on clouds
This commit is contained in:
parent
aa82a332d9
commit
6a5b55b077
19 changed files with 147 additions and 387 deletions
|
@ -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 {
|
double FractalNoise::getBase1d(double x) const {
|
||||||
return getBase2d(x, 0.0);
|
return getBase2d(x, 0.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,13 @@ class BASICSSHARED_EXPORT FractalNoise {
|
||||||
*/
|
*/
|
||||||
void estimateRange(double *min, double *max, double detail = 0.000001) const;
|
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 getBase1d(double x) const;
|
||||||
virtual double getBase2d(double x, double y) const;
|
virtual double getBase2d(double x, double y) const;
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
CloudLayerDefinition::CloudLayerDefinition(DefinitionNode *parent, const string &name)
|
CloudLayerDefinition::CloudLayerDefinition(DefinitionNode *parent, const string &name)
|
||||||
: DefinitionNode(parent, name, "cloudlayer") {
|
: DefinitionNode(parent, name, "cloudlayer") {
|
||||||
type = CIRRUS;
|
type = STRATOCUMULUS;
|
||||||
altitude = 0.5;
|
altitude = 0.5;
|
||||||
scaling = 0.5;
|
scaling = 0.5;
|
||||||
coverage = 0.5;
|
coverage = 0.5;
|
||||||
|
@ -64,14 +64,14 @@ void CloudLayerDefinition::load(PackStream *stream) {
|
||||||
void CloudLayerDefinition::copy(DefinitionNode *_destination) const {
|
void CloudLayerDefinition::copy(DefinitionNode *_destination) const {
|
||||||
DefinitionNode::copy(_destination);
|
DefinitionNode::copy(_destination);
|
||||||
|
|
||||||
CloudLayerDefinition *destination = (CloudLayerDefinition *)_destination;
|
if (auto destination = static_cast<CloudLayerDefinition *>(_destination)) {
|
||||||
|
destination->type = type;
|
||||||
|
destination->altitude = altitude;
|
||||||
|
destination->scaling = scaling;
|
||||||
|
destination->coverage = coverage;
|
||||||
|
|
||||||
destination->type = type;
|
noise_state.copy(&destination->noise_state);
|
||||||
destination->altitude = altitude;
|
}
|
||||||
destination->scaling = scaling;
|
|
||||||
destination->coverage = coverage;
|
|
||||||
|
|
||||||
noise_state.copy(&destination->noise_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloudLayerDefinition::validate() {
|
void CloudLayerDefinition::validate() {
|
||||||
|
|
|
@ -36,16 +36,16 @@ class DEFINITIONSHARED_EXPORT CloudLayerDefinition : public DefinitionNode {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef enum {
|
typedef enum {
|
||||||
STRATUS,
|
//STRATUS,
|
||||||
NIMBOSTRATUS,
|
//NIMBOSTRATUS,
|
||||||
CUMULUS,
|
//CUMULUS,
|
||||||
STRATOCUMULUS,
|
STRATOCUMULUS,
|
||||||
ALTOCUMULUS,
|
//ALTOCUMULUS,
|
||||||
ALTOSTRATUS,
|
//ALTOSTRATUS,
|
||||||
CUMULONIMBUS,
|
//CUMULONIMBUS,
|
||||||
CIRROCUMULUS,
|
//CIRROCUMULUS,
|
||||||
CIRROSTRATUS,
|
//CIRROSTRATUS,
|
||||||
CIRRUS,
|
//CIRRUS,
|
||||||
_COUNT
|
_COUNT
|
||||||
} CloudsType;
|
} CloudsType;
|
||||||
|
|
||||||
|
|
|
@ -467,8 +467,9 @@ static void testCloudsLighting() {
|
||||||
*min_altitude = 10.0 - scale;
|
*min_altitude = 10.0 - scale;
|
||||||
*max_altitude = 10.0 + scale;
|
*max_altitude = 10.0 + scale;
|
||||||
}
|
}
|
||||||
virtual double getDensity(const Vector3 &location, double) const override {
|
virtual CloudDensityInfo getDensity(const Vector3 &location, double) const override {
|
||||||
return 1.0 - location.sub(Vector3(0.0, 10.0, 0.0)).getNorm() / scale;
|
double val = 1.0 - location.sub(Vector3(0.0, 10.0, 0.0)).getNorm() / scale;
|
||||||
|
return {val, val};
|
||||||
}
|
}
|
||||||
double scale;
|
double scale;
|
||||||
};
|
};
|
||||||
|
@ -582,19 +583,19 @@ static void testCanvasAliasing() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void runTestSuite() {
|
void runTestSuite() {
|
||||||
testNoise();
|
// testNoise();
|
||||||
testCanvasAliasing();
|
// testCanvasAliasing();
|
||||||
testTextures();
|
// testTextures();
|
||||||
testGodRays();
|
// testGodRays();
|
||||||
testCelestialBodies();
|
// testCelestialBodies();
|
||||||
testNearFrustum();
|
// testNearFrustum();
|
||||||
testCloudsLighting();
|
// testCloudsLighting();
|
||||||
testCloudModels();
|
testCloudModels();
|
||||||
testCloudsNearGround();
|
// testCloudsNearGround();
|
||||||
testVegetationModels();
|
// testVegetationModels();
|
||||||
testOpenGLVegetationImpostor();
|
// testOpenGLVegetationImpostor();
|
||||||
testRasterizationQuality();
|
// testRasterizationQuality();
|
||||||
testGroundShadowQuality();
|
// testGroundShadowQuality();
|
||||||
testCloudQuality();
|
// testCloudQuality();
|
||||||
testAtmosphereBruneton();
|
// testAtmosphereBruneton();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "clouds/BaseCloudsModel.h"
|
#include "clouds/BaseCloudsModel.h"
|
||||||
#include "Vector3.h"
|
#include "Vector3.h"
|
||||||
|
#include "Color.h"
|
||||||
|
|
||||||
BaseCloudLayerRenderer::BaseCloudLayerRenderer(SoftwareRenderer *parent) : parent(parent) {
|
BaseCloudLayerRenderer::BaseCloudLayerRenderer(SoftwareRenderer *parent) : parent(parent) {
|
||||||
setQuality(0.5);
|
setQuality(0.5);
|
||||||
|
|
|
@ -51,7 +51,7 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
||||||
double current_total_length, current_inside_length;
|
double current_total_length, current_inside_length;
|
||||||
double step_length, segment_length;
|
double step_length, segment_length;
|
||||||
double min_step, max_step;
|
double min_step, max_step;
|
||||||
double noise_distance, previous_noise_distance;
|
BaseCloudsModel::CloudDensityInfo info, previous_info;
|
||||||
Vector3 walker, step, segment_start, offset;
|
Vector3 walker, step, segment_start, offset;
|
||||||
double render_precision;
|
double render_precision;
|
||||||
|
|
||||||
|
@ -77,9 +77,9 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
||||||
segment_length = 0.0;
|
segment_length = 0.0;
|
||||||
walker = start;
|
walker = start;
|
||||||
offset = Vector3(model->getLayer()->propXOffset()->getValue(), 0.0, model->getLayer()->propZOffset()->getValue());
|
offset = Vector3(model->getLayer()->propXOffset()->getValue(), 0.0, model->getLayer()->propZOffset()->getValue());
|
||||||
noise_distance = model->getDensity(start.add(offset), base_detail);
|
info = model->getDensity(start.add(offset), 1.0);
|
||||||
previous_noise_distance = noise_distance;
|
previous_info = info;
|
||||||
inside = noise_distance > 0.0;
|
inside = info.density > 0.0;
|
||||||
if (inside) {
|
if (inside) {
|
||||||
segment_start = start;
|
segment_start = start;
|
||||||
}
|
}
|
||||||
|
@ -89,19 +89,24 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
||||||
do {
|
do {
|
||||||
walker = walker.add(step);
|
walker = walker.add(step);
|
||||||
step_length = step.getNorm();
|
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;
|
current_total_length += step_length;
|
||||||
|
|
||||||
if (noise_distance > 0.0) {
|
if (info.density > 0.0) {
|
||||||
if (inside) {
|
if (inside) {
|
||||||
// inside the cloud
|
// inside the cloud
|
||||||
segment_length += step_length;
|
segment_length += step_length;
|
||||||
current_inside_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 {
|
} else {
|
||||||
// entering the cloud
|
// entering the cloud
|
||||||
inside = 1;
|
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);
|
assert(segment_length >= 0.0 && segment_length <= step_length);
|
||||||
segment_start = walker.add(direction.scale(-segment_length));
|
segment_start = walker.add(direction.scale(-segment_length));
|
||||||
current_inside_length += segment_length;
|
current_inside_length += segment_length;
|
||||||
|
@ -110,7 +115,7 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
||||||
} else {
|
} else {
|
||||||
if (inside) {
|
if (inside) {
|
||||||
// exiting the cloud
|
// 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);
|
assert(exit_length >= 0.0);
|
||||||
segment_length += exit_length;
|
segment_length += exit_length;
|
||||||
current_inside_length += exit_length;
|
current_inside_length += exit_length;
|
||||||
|
@ -128,12 +133,12 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
||||||
} else {
|
} else {
|
||||||
// searching for a cloud
|
// searching for a cloud
|
||||||
step =
|
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);
|
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 &&
|
stop = not(walker.y >= ymin - 0.001 && walker.y <= ymax + 0.001 && current_total_length < max_total_length &&
|
||||||
current_inside_length < max_inside_length);
|
current_inside_length < max_inside_length);
|
||||||
} while (inside or not stop);
|
} while (inside or not stop);
|
||||||
|
@ -143,14 +148,6 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
||||||
return segment_count;
|
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) {
|
Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location) {
|
||||||
int i, segment_count;
|
int i, segment_count;
|
||||||
double max_length, total_length, inside_length;
|
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,
|
segment_count = findSegments(model, start, direction, 30, transparency_depth, max_length, &inside_length,
|
||||||
&total_length, segments, 0.001);
|
&total_length, segments, 0.001);
|
||||||
for (i = segment_count - 1; i >= 0; i--) {
|
for (i = segment_count - 1; i >= 0; i--) {
|
||||||
Vector3 normal = VECTOR_ZERO;
|
|
||||||
const Vector3 &location = segments[i].start;
|
const Vector3 &location = segments[i].start;
|
||||||
normal = normal.add(_getPseudoNormal(model, location, VECTOR_UP));
|
col = parent->applyLightingToSurface(location, model->getNormal(location, 1.0), material);
|
||||||
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.a = (segments[i].length >= transparency_depth) ? 1.0 : (segments[i].length / transparency_depth);
|
col.a = (segments[i].length >= transparency_depth) ? 1.0 : (segments[i].length / transparency_depth);
|
||||||
result.mask(col);
|
result.mask(col);
|
||||||
|
|
|
@ -8,11 +8,9 @@
|
||||||
#include "CloudBasicLayerRenderer.h"
|
#include "CloudBasicLayerRenderer.h"
|
||||||
#include "CameraDefinition.h"
|
#include "CameraDefinition.h"
|
||||||
#include "Logs.h"
|
#include "Logs.h"
|
||||||
|
#include "Color.h"
|
||||||
|
|
||||||
#include "clouds/BaseCloudsModel.h"
|
#include "clouds/BaseCloudsModel.h"
|
||||||
#include "clouds/CloudModelAltoCumulus.h"
|
|
||||||
#include "clouds/CloudModelCirrus.h"
|
|
||||||
#include "clouds/CloudModelCumuloNimbus.h"
|
|
||||||
#include "clouds/CloudModelStratoCumulus.h"
|
#include "clouds/CloudModelStratoCumulus.h"
|
||||||
|
|
||||||
CloudsRenderer::CloudsRenderer(SoftwareRenderer *parent) : parent(parent) {
|
CloudsRenderer::CloudsRenderer(SoftwareRenderer *parent) : parent(parent) {
|
||||||
|
@ -70,21 +68,6 @@ void CloudsRenderer::update() {
|
||||||
case CloudLayerDefinition::STRATOCUMULUS:
|
case CloudLayerDefinition::STRATOCUMULUS:
|
||||||
model = new CloudModelStratoCumulus(layer);
|
model = new CloudModelStratoCumulus(layer);
|
||||||
break;
|
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:
|
case CloudLayerDefinition::_COUNT:
|
||||||
model = new BaseCloudsModel(layer);
|
model = new BaseCloudsModel(layer);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "BaseCloudsModel.h"
|
#include "BaseCloudsModel.h"
|
||||||
|
|
||||||
#include "CloudLayerDefinition.h"
|
#include "CloudLayerDefinition.h"
|
||||||
|
#include "Vector3.h"
|
||||||
|
|
||||||
BaseCloudsModel::BaseCloudsModel(CloudLayerDefinition *layer) : layer(layer) {
|
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;
|
*max_step = thickness * 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
double BaseCloudsModel::getProbability(const Vector3 &, double) const {
|
BaseCloudsModel::CloudDensityInfo BaseCloudsModel::getDensity(const Vector3 &, double) const {
|
||||||
// FIXME not used !
|
return {0.0, 1.0};
|
||||||
return 1.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double BaseCloudsModel::getDensity(const Vector3 &, double) const {
|
static inline Vector3 _getPseudoNormal(const BaseCloudsModel *model, const Vector3 &base, const Vector3 &direction, double base_density, double precision) {
|
||||||
return 0.0;
|
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 {
|
Vector3 BaseCloudsModel::getNormal(const Vector3 &location, double quality) const
|
||||||
// FIXME not used !
|
{
|
||||||
return light;
|
double precision = 0.3;
|
||||||
}
|
Vector3 normal = VECTOR_ZERO;
|
||||||
|
double base_density = getDensity(location, precision).density;
|
||||||
Color BaseCloudsModel::applyLightExit(const Color &light, const Vector3 &, const Vector3 &) const {
|
normal = normal.add(_getPseudoNormal(this, location, VECTOR_UP, base_density, precision));
|
||||||
// FIXME not used !
|
normal = normal.add(_getPseudoNormal(this, location, VECTOR_DOWN, base_density, precision));
|
||||||
return light;
|
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
#include "../software_global.h"
|
#include "../software_global.h"
|
||||||
|
|
||||||
#include "Color.h"
|
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace software {
|
namespace software {
|
||||||
|
|
||||||
|
@ -12,23 +10,39 @@ namespace software {
|
||||||
* Abstract class for all cloud models (cirrus, cumulus...).
|
* Abstract class for all cloud models (cirrus, cumulus...).
|
||||||
*/
|
*/
|
||||||
class SOFTWARESHARED_EXPORT BaseCloudsModel {
|
class SOFTWARESHARED_EXPORT BaseCloudsModel {
|
||||||
|
public:
|
||||||
|
typedef struct {
|
||||||
|
double density;
|
||||||
|
double border_distance;
|
||||||
|
} CloudDensityInfo;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BaseCloudsModel(CloudLayerDefinition *layer);
|
BaseCloudsModel(CloudLayerDefinition *layer);
|
||||||
virtual ~BaseCloudsModel();
|
virtual ~BaseCloudsModel();
|
||||||
|
|
||||||
|
inline CloudLayerDefinition *getLayer() const {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void update();
|
virtual void update();
|
||||||
|
|
||||||
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const;
|
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const;
|
||||||
virtual void getDetailRange(double *min_step, double *max_step) 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:
|
protected:
|
||||||
CloudLayerDefinition *layer;
|
CloudLayerDefinition *layer;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -1,11 +1,13 @@
|
||||||
#include "CloudModelStratoCumulus.h"
|
#include "CloudModelStratoCumulus.h"
|
||||||
|
|
||||||
#include "NoiseGenerator.h"
|
#include <cmath>
|
||||||
|
#include "NoiseFunctionSimplex.h"
|
||||||
#include "Vector3.h"
|
#include "Vector3.h"
|
||||||
#include "CloudLayerDefinition.h"
|
#include "CloudLayerDefinition.h"
|
||||||
|
|
||||||
CloudModelStratoCumulus::CloudModelStratoCumulus(CloudLayerDefinition *layer) : BaseCloudsModel(layer) {
|
CloudModelStratoCumulus::CloudModelStratoCumulus(CloudLayerDefinition *layer) : BaseCloudsModel(layer) {
|
||||||
noise = new NoiseGenerator();
|
noise = new NoiseFunctionSimplex();
|
||||||
|
base_detail = 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
CloudModelStratoCumulus::~CloudModelStratoCumulus() {
|
CloudModelStratoCumulus::~CloudModelStratoCumulus() {
|
||||||
|
@ -13,23 +15,10 @@ CloudModelStratoCumulus::~CloudModelStratoCumulus() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloudModelStratoCumulus::update() {
|
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->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 {
|
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;
|
*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 val;
|
||||||
double min_altitude, max_altitude;
|
double min_altitude, max_altitude;
|
||||||
double noise_scaling = 30.0 * layer->scaling;
|
|
||||||
|
|
||||||
getAltitudeRange(&min_altitude, &max_altitude);
|
getAltitudeRange(&min_altitude, &max_altitude);
|
||||||
|
|
||||||
if (location.y < min_altitude || location.y > max_altitude) {
|
if (location.y < min_altitude) {
|
||||||
return 0.0;
|
return {0.0, min_altitude - location.y};
|
||||||
|
} else if (location.y > max_altitude) {
|
||||||
|
return {0.0, location.y - max_altitude};
|
||||||
} else {
|
} else {
|
||||||
double x = 0.3 * location.x / noise_scaling;
|
val = noise->get3d(base_detail, 0.3 * location.x, location.y - min_altitude, 0.3 * location.z);
|
||||||
double y = (location.y - min_altitude) / noise_scaling;
|
val = val - 0.8 + layer->coverage;
|
||||||
double z = 0.3 * location.z / noise_scaling;
|
return {val, fabs(val)};
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,11 @@ class CloudModelStratoCumulus : public BaseCloudsModel {
|
||||||
virtual void update() override;
|
virtual void update() override;
|
||||||
|
|
||||||
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const 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:
|
private:
|
||||||
NoiseGenerator *noise;
|
FractalNoise *noise;
|
||||||
|
double base_detail;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,3 +228,16 @@ TEST(FractalNoise, estimateRange) {
|
||||||
EXPECT_DOUBLE_EQ(-0.555, min);
|
EXPECT_DOUBLE_EQ(-0.555, min);
|
||||||
EXPECT_DOUBLE_EQ(0.555, max);
|
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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue