diff --git a/TODO b/TODO index 4999d07..82c883d 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,6 @@ Technology Preview 2 : - Add initial terrain offset so that the (0,0) coordinates are above water. +- Use water height as 0.0 (offset the terrain). - Finalize lighting/clouds refactoring => Restore cloud lighting => Improve cloud rendering precision (and beware of precision discontinuity when rendering clouds in front of ground (shorter distance)). diff --git a/src/basics/Color.h b/src/basics/Color.h index 78ed134..594dd4c 100644 --- a/src/basics/Color.h +++ b/src/basics/Color.h @@ -10,7 +10,7 @@ class Color { public: Color(); - Color(double r, double g, double b, double a); + Color(double r, double g, double b, double a=1.0); void save(PackStream* stream) const; void load(PackStream* stream); diff --git a/src/definition/CloudLayerDefinition.cpp b/src/definition/CloudLayerDefinition.cpp index 9f5d115..eb4ce25 100644 --- a/src/definition/CloudLayerDefinition.cpp +++ b/src/definition/CloudLayerDefinition.cpp @@ -8,20 +8,14 @@ CloudLayerDefinition::CloudLayerDefinition(BaseDefinition* parent): BaseDefinition(parent) { - _coverage_by_altitude = new Curve; - _coverage_noise = new NoiseGenerator(); - _shape_noise = new NoiseGenerator(); - _edge_noise = new NoiseGenerator(); - material = new SurfaceMaterial; + type = CIRRUS; + altitude = 0.5; + scaling = 0.5; + coverage = 0.5; } CloudLayerDefinition::~CloudLayerDefinition() { - delete _coverage_by_altitude; - delete _coverage_noise; - delete _shape_noise; - delete _edge_noise; - delete material; } CloudLayerDefinition* CloudLayerDefinition::newCopy(const CloudLayerDefinition& other, BaseDefinition* parent) @@ -45,21 +39,9 @@ void CloudLayerDefinition::save(PackStream* stream) const int clouds_type = (int)type; stream->write(&clouds_type); - stream->write(&lower_altitude); - stream->write(&thickness); - _coverage_by_altitude->save(stream); - _coverage_noise->save(stream); - _shape_noise->save(stream); - _edge_noise->save(stream); - materialSave(stream, material); - stream->write(&hardness); - stream->write(&transparencydepth); - stream->write(&lighttraversal); - stream->write(&minimumlight); - stream->write(&shape_scaling); - stream->write(&edge_scaling); - stream->write(&edge_length); - stream->write(&base_coverage); + stream->write(&altitude); + stream->write(&scaling); + stream->write(&coverage); } void CloudLayerDefinition::load(PackStream* stream) @@ -70,21 +52,9 @@ void CloudLayerDefinition::load(PackStream* stream) stream->read(&clouds_type); type = (CloudsType)clouds_type; - stream->read(&lower_altitude); - stream->read(&thickness); - _coverage_by_altitude->load(stream); - _coverage_noise->load(stream); - _shape_noise->load(stream); - _edge_noise->load(stream); - materialLoad(stream, material); - stream->read(&hardness); - stream->read(&transparencydepth); - stream->read(&lighttraversal); - stream->read(&minimumlight); - stream->read(&shape_scaling); - stream->read(&edge_scaling); - stream->read(&edge_length); - stream->read(&base_coverage); + stream->read(&altitude); + stream->read(&scaling); + stream->read(&coverage); validate(); } @@ -96,168 +66,15 @@ void CloudLayerDefinition::copy(BaseDefinition* _destination) const CloudLayerDefinition* destination = (CloudLayerDefinition*)_destination; destination->type = type; - destination->lower_altitude = lower_altitude; - destination->thickness = thickness; - _coverage_by_altitude->copy(destination->_coverage_by_altitude); - _coverage_noise->copy(destination->_coverage_noise); - _shape_noise->copy(destination->_shape_noise); - _edge_noise->copy(destination->_edge_noise); - *destination->material = *material; - destination->hardness = hardness; - destination->transparencydepth = transparencydepth; - destination->lighttraversal = lighttraversal; - destination->minimumlight = minimumlight; - destination->shape_scaling = shape_scaling; - destination->edge_scaling = edge_scaling; - destination->edge_length = edge_length; - destination->base_coverage = base_coverage; + destination->altitude = altitude; + destination->scaling = scaling; + destination->coverage = coverage; } void CloudLayerDefinition::validate() { - if (shape_scaling < 0.0001) + if (scaling < 0.1) { - shape_scaling = 0.00001; + scaling = 0.1; } - if (edge_scaling < 0.0001) - { - edge_scaling = 0.00001; - } - - _coverage_by_altitude->clear(); - _shape_noise->clearLevels(); - _edge_noise->clearLevels(); - _coverage_noise->clearLevels(); - - _coverage_noise->addLevelsSimple(2, 10.0, 0.0, 1.0, 0.0); - _coverage_noise->addLevelsSimple(2, 1.0, 0.0, 1.0, 0.0); - _coverage_noise->setFunctionParams(NOISE_FUNCTION_NAIVE, 0.0, 0.0); - switch (type) - { - case CLOUDS_TYPE_CIRRUS: - _coverage_by_altitude->addPoint(0.0, 0.0); - _coverage_by_altitude->addPoint(0.5, 1.0); - _coverage_by_altitude->addPoint(1.0, 0.0); - _shape_noise->addLevelsSimple(3, 1.0, 0.0, 1.0, 0.5); - _shape_noise->setFunctionParams(NOISE_FUNCTION_SIMPLEX, 0.0, 0.0); - _edge_noise->addLevelsSimple(4, 1.0, -0.5, 0.5, 0.5); - _edge_noise->setFunctionParams(NOISE_FUNCTION_SIMPLEX, -0.2, 0.0); - break; - case CLOUDS_TYPE_CUMULUS: - _coverage_by_altitude->addPoint(0.0, 0.0); - _coverage_by_altitude->addPoint(0.1, 1.0); - _coverage_by_altitude->addPoint(0.4, 0.8); - _coverage_by_altitude->addPoint(0.7, 1.0); - _coverage_by_altitude->addPoint(1.0, 0.0); - _shape_noise->addLevelsSimple(7, 1.0, 0.0, 1.0, 0.5); - _shape_noise->setFunctionParams(NOISE_FUNCTION_SIMPLEX, 0.4, 0.0); - _edge_noise->addLevelsSimple(4, 1.0, -0.5, 0.5, 0.5); - _edge_noise->setFunctionParams(NOISE_FUNCTION_SIMPLEX, 0.8, 0.0); - break; - case CLOUDS_TYPE_STRATOCUMULUS: - _coverage_by_altitude->addPoint(0.0, 0.0); - _coverage_by_altitude->addPoint(0.2, 1.0); - _coverage_by_altitude->addPoint(0.5, 1.0); - _coverage_by_altitude->addPoint(1.0, 0.0); - _shape_noise->addLevelsSimple(4, 1.0, 0.0, 1.0, 0.5); - _shape_noise->setFunctionParams(NOISE_FUNCTION_SIMPLEX, 0.3, 0.0); - _edge_noise->addLevelsSimple(6, 1.0, -0.5, 0.5, 0.5); - _edge_noise->setFunctionParams(NOISE_FUNCTION_SIMPLEX, 0.5, 0.0); - break; - case CLOUDS_TYPE_STRATUS: - _coverage_by_altitude->addPoint(0.0, 0.0); - _coverage_by_altitude->addPoint(0.2, 1.0); - _coverage_by_altitude->addPoint(0.8, 1.0); - _coverage_by_altitude->addPoint(1.0, 0.0); - _shape_noise->addLevelsSimple(3, 1.0, 0.0, 1.0, 0.5); - _shape_noise->setFunctionParams(NOISE_FUNCTION_SIMPLEX, -0.3, 0.0); - _edge_noise->addLevelsSimple(4, 1.0, -0.5, 0.5, 0.5); - _edge_noise->setFunctionParams(NOISE_FUNCTION_SIMPLEX, -0.5, 0.0); - break; - default: - break; - } - - _coverage_noise->normalizeAmplitude(-1.0, 3.0, 0); - _shape_noise->normalizeAmplitude(-0.5, 0.5, 0); - _edge_noise->normalizeAmplitude(-0.5, 0.5, 0); - - materialValidate(material); -} - -void CloudLayerDefinition::applyPreset(CloudsLayerPreset preset) -{ - _coverage_noise->randomizeOffsets(); - _edge_noise->randomizeOffsets(); - _shape_noise->randomizeOffsets(); - - material->base = colorToHSL(colorFromValues(0.7, 0.7, 0.7, 1.0)); - - switch (preset) - { - case CLOUDS_LAYER_PRESET_CIRRUS: - type = CLOUDS_TYPE_CIRRUS; - lower_altitude = 25.0; - thickness = 2.0; - material->reflection = 0.4; - material->shininess = 0.5; - hardness = 0.0; - transparencydepth = 3.0; - lighttraversal = 10.0; - minimumlight = 0.6; - shape_scaling = 8.0; - edge_scaling = 2.0; - edge_length = 0.8; - base_coverage = 0.6; - break; - case CLOUDS_LAYER_PRESET_CUMULUS: - type = CLOUDS_TYPE_CUMULUS; - lower_altitude = 15.0; - thickness = 15.0; - material->reflection = 0.5; - material->shininess = 1.2; - hardness = 0.25; - transparencydepth = 1.5; - lighttraversal = 8.0; - minimumlight = 0.4; - shape_scaling = 20.0; - edge_scaling = 2.0; - edge_length = 0.0; - base_coverage = 0.7; - break; - case CLOUDS_LAYER_PRESET_STRATOCUMULUS: - type = CLOUDS_TYPE_STRATOCUMULUS; - lower_altitude = 5.0; - thickness = 6.0; - material->reflection = 0.3; - material->shininess = 0.8; - hardness = 0.25; - transparencydepth = 1.5; - lighttraversal = 7.0; - minimumlight = 0.4; - shape_scaling = 10.0; - edge_scaling = 0.8; - edge_length = 0.3; - base_coverage = 0.4; - break; - case CLOUDS_LAYER_PRESET_STRATUS: - type = CLOUDS_TYPE_STRATUS; - lower_altitude = 3.0; - thickness = 4.0; - material->reflection = 0.1; - material->shininess = 0.8; - hardness = 0.1; - transparencydepth = 3.0; - lighttraversal = 10.0; - minimumlight = 0.6; - shape_scaling = 8.0; - edge_scaling = 2.0; - edge_length = 1.0; - base_coverage = 0.4; - break; - default: - break; - } - - validate(); } diff --git a/src/definition/CloudLayerDefinition.h b/src/definition/CloudLayerDefinition.h index bf0b243..cae99f4 100644 --- a/src/definition/CloudLayerDefinition.h +++ b/src/definition/CloudLayerDefinition.h @@ -26,39 +26,23 @@ public: public: typedef enum { - CLOUDS_TYPE_CIRRUS, - CLOUDS_TYPE_CUMULUS, - CLOUDS_TYPE_STRATOCUMULUS, - CLOUDS_TYPE_STRATUS + STRATUS, + NIMBOSTRATUS, + CUMULUS, + STRATOCUMULUS, + ALTOCUMULUS, + ALTOSTRATUS, + CUMULONIMBUS, + CIRROCUMULUS, + CIRROSTRATUS, + CIRRUS } CloudsType; - typedef enum - { - CLOUDS_LAYER_PRESET_CIRRUS, - CLOUDS_LAYER_PRESET_CUMULUS, - CLOUDS_LAYER_PRESET_STRATOCUMULUS, - CLOUDS_LAYER_PRESET_STRATUS - } CloudsLayerPreset; - void applyPreset(CloudsLayerPreset preset); - public: CloudsType type; - double lower_altitude; - double thickness; - double base_coverage; - double shape_scaling; - double edge_scaling; - double edge_length; - SurfaceMaterial* material; - double hardness; - double transparencydepth; - double lighttraversal; - double minimumlight; - - Curve* _coverage_by_altitude; - NoiseGenerator* _coverage_noise; - NoiseGenerator* _shape_noise; - NoiseGenerator* _edge_noise; + double altitude; + double scaling; + double coverage; }; } diff --git a/src/definition/CloudsDefinition.cpp b/src/definition/CloudsDefinition.cpp index e176cb5..0608479 100644 --- a/src/definition/CloudsDefinition.cpp +++ b/src/definition/CloudsDefinition.cpp @@ -19,8 +19,8 @@ void CloudsDefinition::applyPreset(CloudsPreset preset) if (preset == CLOUDS_PRESET_PARTLY_CLOUDY) { CloudLayerDefinition* layer = new CloudLayerDefinition(this); - layer->applyPreset(CloudLayerDefinition::CLOUDS_LAYER_PRESET_CIRRUS); - layer->setName("Cirrus"); + layer->type = CloudLayerDefinition::STRATOCUMULUS; + layer->setName("Strato-cumulus"); addLayer(layer); } } diff --git a/src/interface/desktop/formclouds.cpp b/src/interface/desktop/formclouds.cpp index 4f4b9f6..627041e 100644 --- a/src/interface/desktop/formclouds.cpp +++ b/src/interface/desktop/formclouds.cpp @@ -14,11 +14,6 @@ FormClouds::FormClouds(QWidget *parent): BaseFormLayer(parent) { - addAutoPreset(tr("Cirrus")); - addAutoPreset(tr("Cumulus")); - addAutoPreset(tr("Stratocumulus")); - addAutoPreset(tr("Stratus")); - _definition = new CloudsDefinition(NULL); _layer = new CloudLayerDefinition(NULL); @@ -33,17 +28,9 @@ FormClouds::FormClouds(QWidget *parent): _previewColor->setRenderer(_previewColorRenderer); addInputEnum(tr("Clouds model"), (int*)&_layer->type, QStringList() << tr("Cirrus") << tr("Cumulus") << tr("Stratocumulus") << tr("Stratus")); - addInputDouble(tr("Lower altitude"), &_layer->lower_altitude, -10.0, 50.0, 0.5, 5.0); - addInputDouble(tr("Layer thickness"), &_layer->thickness, 0.0, 20.0, 0.1, 1.0); - addInputDouble(tr("Max coverage"), &_layer->base_coverage, 0.0, 1.0, 0.01, 0.1); - addInputDouble(tr("Shape scaling"), &_layer->shape_scaling, 3.0, 30.0, 0.3, 3.0); - addInputDouble(tr("Edge scaling"), &_layer->edge_scaling, 0.5, 5.0, 0.05, 0.5); - addInputDouble(tr("Edge length"), &_layer->edge_length, 0.0, 1.0, 0.01, 0.1); - addInputMaterial(tr("Material"), _layer->material); - addInputDouble(tr("Hardness to light"), &_layer->hardness, 0.0, 1.0, 0.01, 0.1); - addInputDouble(tr("Transparency depth"), &_layer->transparencydepth, 0.0, 10.0, 0.1, 1.0); - addInputDouble(tr("Light traversal depth"), &_layer->lighttraversal, 0.0, 10.0, 0.1, 1.0); - addInputDouble(tr("Minimum lighting"), &_layer->minimumlight, 0.0, 1.0, 0.01, 0.1); + addInputDouble(tr("Lower altitude"), &_layer->altitude, 0.0, 1.0, 0.01, 0.1); + addInputDouble(tr("Scaling"), &_layer->scaling, 0.0, 1.0, 0.01, 0.1); + addInputDouble(tr("Coverage"), &_layer->coverage, 0.0, 1.0, 0.01, 0.1); setLayers(_definition); } @@ -81,9 +68,3 @@ void FormClouds::layerWriteCurrentTo(void* layer_definition) { _layer->copy((CloudLayerDefinition*)layer_definition); } - -void FormClouds::autoPresetSelected(int preset) -{ - _layer->applyPreset((CloudLayerDefinition::CloudsLayerPreset)preset); - BaseForm::autoPresetSelected(preset); -} diff --git a/src/interface/desktop/formclouds.h b/src/interface/desktop/formclouds.h index de4118c..daebcd0 100644 --- a/src/interface/desktop/formclouds.h +++ b/src/interface/desktop/formclouds.h @@ -21,7 +21,6 @@ public slots: protected: virtual void layerReadCurrentFrom(void* layer_definition); virtual void layerWriteCurrentTo(void* layer_definition); - virtual void autoPresetSelected(int preset); private: CloudsDefinition* _definition; diff --git a/src/render/preview/CloudsAspectPreviewRenderer.cpp b/src/render/preview/CloudsAspectPreviewRenderer.cpp index 46fc362..3d460e5 100644 --- a/src/render/preview/CloudsAspectPreviewRenderer.cpp +++ b/src/render/preview/CloudsAspectPreviewRenderer.cpp @@ -30,7 +30,7 @@ static void _getLightingStatus(Renderer*, LightStatus* status, Vector3, int) static double _getDensity(Renderer*, CloudLayerDefinition* layer, Vector3 location) { - double distance = 2.0 * v3Norm(location) / layer->thickness; + double distance = 2.0 * v3Norm(location) / layer->scaling; if (distance > 1.0) { return 0.0; @@ -75,8 +75,7 @@ void CloudsAspectPreviewRenderer::updateEvent() CloudLayerDefinition* preview_layer = getScenery()->getClouds()->getCloudLayer(0); layer->copy(preview_layer); - preview_layer->thickness = preview_layer->shape_scaling; - preview_layer->lower_altitude = -preview_layer->thickness / 2.0; + preview_layer->altitude = -preview_layer->scaling / 2.0; preview_layer->validate(); prepare(); @@ -89,7 +88,7 @@ void CloudsAspectPreviewRenderer::updateEvent() Color CloudsAspectPreviewRenderer::getColor2D(double x, double y, double) { Vector3 start, end; - double thickness = layer->thickness; + double thickness = layer->scaling; start.x = x * thickness * 0.5; start.z = y * thickness * 0.5; diff --git a/src/render/software/BaseCloudLayerRenderer.cpp b/src/render/software/BaseCloudLayerRenderer.cpp index 8b79a66..05f28a3 100644 --- a/src/render/software/BaseCloudLayerRenderer.cpp +++ b/src/render/software/BaseCloudLayerRenderer.cpp @@ -1,6 +1,6 @@ #include "BaseCloudLayerRenderer.h" -#include "CloudLayerDefinition.h" +#include "clouds/BaseCloudsModel.h" BaseCloudLayerRenderer::BaseCloudLayerRenderer(SoftwareRenderer* parent): parent(parent) @@ -12,67 +12,65 @@ BaseCloudLayerRenderer::~BaseCloudLayerRenderer() } -double BaseCloudLayerRenderer::getDensity(CloudLayerDefinition *, const Vector3 &) -{ - return 0.0; -} - -Color BaseCloudLayerRenderer::getColor(CloudLayerDefinition *, const Vector3 &, const Vector3 &) +Color BaseCloudLayerRenderer::getColor(BaseCloudsModel *, const Vector3 &, const Vector3 &) { return COLOR_TRANSPARENT; } -bool BaseCloudLayerRenderer::alterLight(CloudLayerDefinition *, LightDefinition *, const Vector3 &, const Vector3 &) +bool BaseCloudLayerRenderer::alterLight(BaseCloudsModel *, LightDefinition *, const Vector3 &, const Vector3 &) { return false; } -bool BaseCloudLayerRenderer::optimizeSearchLimits(CloudLayerDefinition *layer, Vector3 *start, Vector3 *end) +bool BaseCloudLayerRenderer::optimizeSearchLimits(BaseCloudsModel *model, Vector3 *start, Vector3 *end) { Vector3 diff; + double min_altitude, max_altitude; - if (start->y > layer->lower_altitude + layer->thickness) + model->getAltitudeRange(&min_altitude, &max_altitude); + + if (start->y > max_altitude) { - if (end->y >= layer->lower_altitude + layer->thickness) + if (end->y >= max_altitude) { return false; } else { diff = v3Sub(*end, *start); - *start = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y)); - if (end->y < layer->lower_altitude) + *start = v3Add(*start, v3Scale(diff, (max_altitude - start->y) / diff.y)); + if (end->y < min_altitude) { - *end = v3Add(*end, v3Scale(diff, (layer->lower_altitude - end->y) / diff.y)); + *end = v3Add(*end, v3Scale(diff, (min_altitude - end->y) / diff.y)); } } } - else if (start->y < layer->lower_altitude) + else if (start->y < min_altitude) { - if (end->y <= layer->lower_altitude) + if (end->y <= min_altitude) { return false; } else { diff = v3Sub(*end, *start); - *start = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y)); - if (end->y >= layer->lower_altitude + layer->thickness) + *start = v3Add(*start, v3Scale(diff, (min_altitude - start->y) / diff.y)); + if (end->y >= max_altitude) { - *end = v3Add(*end, v3Scale(diff, (layer->lower_altitude + layer->thickness - end->y) / diff.y)); + *end = v3Add(*end, v3Scale(diff, (max_altitude - end->y) / diff.y)); } } } else /* start is inside layer */ { diff = v3Sub(*end, *start); - if (end->y > layer->lower_altitude + layer->thickness) + if (end->y > max_altitude) { - *end = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y)); + *end = v3Add(*start, v3Scale(diff, (max_altitude - start->y) / diff.y)); } - else if (end->y < layer->lower_altitude) + else if (end->y < min_altitude) { - *end = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y)); + *end = v3Add(*start, v3Scale(diff, (min_altitude - start->y) / diff.y)); } } diff --git a/src/render/software/BaseCloudLayerRenderer.h b/src/render/software/BaseCloudLayerRenderer.h index 44d250c..5b229bf 100644 --- a/src/render/software/BaseCloudLayerRenderer.h +++ b/src/render/software/BaseCloudLayerRenderer.h @@ -14,11 +14,10 @@ public: BaseCloudLayerRenderer(SoftwareRenderer* parent); virtual ~BaseCloudLayerRenderer(); - virtual bool optimizeSearchLimits(CloudLayerDefinition *layer, Vector3 *start, Vector3 *end); + virtual bool optimizeSearchLimits(BaseCloudsModel *model, Vector3 *start, Vector3 *end); - virtual double getDensity(CloudLayerDefinition* layer, const Vector3 &location); - virtual Color getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location); - virtual bool alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &eye, const Vector3 &location); + virtual Color getColor(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location); + virtual bool alterLight(BaseCloudsModel *model, LightDefinition* light, const Vector3 &eye, const Vector3 &location); protected: SoftwareRenderer* parent; diff --git a/src/render/software/CloudBasicLayerRenderer.cpp b/src/render/software/CloudBasicLayerRenderer.cpp index 5e2a56d..c2633a3 100644 --- a/src/render/software/CloudBasicLayerRenderer.cpp +++ b/src/render/software/CloudBasicLayerRenderer.cpp @@ -5,6 +5,8 @@ #include "NoiseGenerator.h" #include "Curve.h" #include "AtmosphereRenderer.h" +#include "clouds/BaseCloudsModel.h" +#include "SurfaceMaterial.h" typedef struct { @@ -18,67 +20,9 @@ CloudBasicLayerRenderer::CloudBasicLayerRenderer(SoftwareRenderer* parent): { } -static inline double _standardCoverageFunc(CloudLayerDefinition* layer, Vector3 position) +static inline double _getDistanceToBorder(BaseCloudsModel* model, Vector3 position) { - if (position.y < layer->lower_altitude || position.y > (layer->lower_altitude + layer->thickness)) - { - return 0.0; - } - else - { - return layer->base_coverage * layer->_coverage_by_altitude->getValue((position.y - layer->lower_altitude) / layer->thickness); - } -} - -static inline double _getDistanceToBorder(CloudLayerDefinition* layer, Vector3 position) -{ - double val; - double minval, maxval; - - layer->_shape_noise->getRange(&minval, &maxval); - - val = 0.5 * layer->_shape_noise->get3DTotal(position.x / layer->shape_scaling, position.y / layer->shape_scaling, position.z / layer->shape_scaling) / maxval; - - return (val - 0.5 + _standardCoverageFunc(layer, position)) * layer->shape_scaling; -} - -static inline Vector3 _getNormal(CloudLayerDefinition* layer, Vector3 position, double detail) -{ - Vector3 result = {0.0, 0.0, 0.0}; - Vector3 dposition; - double val, dval; - - val = _getDistanceToBorder(layer, position); - - dposition.x = position.x + detail; - dposition.y = position.y; - dposition.z = position.z; - dval = val - _getDistanceToBorder(layer, dposition); - result.x += dval; - - dposition.x = position.x - detail; - dval = val - _getDistanceToBorder(layer, dposition); - result.x -= dval; - - dposition.x = position.x; - dposition.y = position.y + detail; - dval = val - _getDistanceToBorder(layer, dposition); - result.y += dval; - - dposition.y = position.y - detail; - dval = val - _getDistanceToBorder(layer, dposition); - result.y -= dval; - - dposition.y = position.y; - dposition.z = position.z + detail; - dval = val - _getDistanceToBorder(layer, dposition); - result.z += dval; - - dposition.z = position.z - detail; - dval = val - _getDistanceToBorder(layer, dposition); - result.z -= dval; - - return v3Normalize(result); + return model->getDensity(position); } /** @@ -97,8 +41,9 @@ static inline Vector3 _getNormal(CloudLayerDefinition* layer, Vector3 position, * @param out_segments Allocated space to fill found segments * @return Number of segments found */ -static int _findSegments(CloudLayerDefinition* definition, SoftwareRenderer* renderer, Vector3 start, Vector3 direction, double, int max_segments, double max_inside_length, double max_total_length, double* inside_length, double* total_length, CloudSegment* out_segments) +static int _findSegments(BaseCloudsModel* model, SoftwareRenderer* renderer, Vector3 start, Vector3 direction, double, int max_segments, double max_inside_length, double max_total_length, double* inside_length, double* total_length, CloudSegment* out_segments) { + CloudLayerDefinition* layer = model->getLayer(); int inside, segment_count; double current_total_length, current_inside_length; double step_length, segment_length, remaining_length; @@ -112,7 +57,7 @@ static int _findSegments(CloudLayerDefinition* definition, SoftwareRenderer* ren } render_precision = 15.2 - 1.5 * (double)renderer->render_quality; - render_precision = render_precision * definition->shape_scaling / 50.0; + render_precision = render_precision * layer->scaling / 50.0; if (render_precision > max_total_length / 10.0) { render_precision = max_total_length / 10.0; @@ -127,7 +72,7 @@ static int _findSegments(CloudLayerDefinition* definition, SoftwareRenderer* ren current_inside_length = 0.0; segment_length = 0.0; walker = start; - noise_distance = _getDistanceToBorder(definition, start) * render_precision; + noise_distance = _getDistanceToBorder(model, start) * render_precision; inside = (noise_distance > 0.0) ? 1 : 0; step = v3Scale(direction, render_precision); @@ -136,7 +81,7 @@ static int _findSegments(CloudLayerDefinition* definition, SoftwareRenderer* ren walker = v3Add(walker, step); step_length = v3Norm(step); last_noise_distance = noise_distance; - noise_distance = _getDistanceToBorder(definition, walker) * render_precision; + noise_distance = _getDistanceToBorder(model, walker) * render_precision; current_total_length += step_length; if (noise_distance > 0.0) @@ -185,49 +130,16 @@ static int _findSegments(CloudLayerDefinition* definition, SoftwareRenderer* ren step = v3Scale(direction, (noise_distance > -render_precision) ? render_precision : -noise_distance); } } - } while (inside || (walker.y >= definition->lower_altitude - 0.001 && walker.y <= (definition->lower_altitude + definition->thickness) + 0.001 && current_total_length < max_total_length && current_inside_length < max_inside_length)); + } while (inside || (walker.y >= layer->altitude - 0.001 && walker.y <= (layer->altitude + layer->scaling) + 0.001 && current_total_length < max_total_length && current_inside_length < max_inside_length)); *total_length = current_total_length; *inside_length = current_inside_length; return segment_count; } -static Color _applyLayerLighting(CloudLayerDefinition* definition, SoftwareRenderer* renderer, Vector3 position, double) -{ - Vector3 normal; - Color col1, col2; - - normal = _getNormal(definition, position, 3.0); - if (renderer->render_quality > 5) - { - normal = v3Add(normal, _getNormal(definition, position, 2.0)); - normal = v3Add(normal, _getNormal(definition, position, 1.0)); - } - if (renderer->render_quality > 5) - { - normal = v3Add(normal, _getNormal(definition, position, 0.5)); - } - normal = v3Scale(v3Normalize(normal), definition->hardness); - - // TODO Compute light filter only once - col1 = renderer->applyLightingToSurface(renderer, position, normal, definition->material); - col2 = renderer->applyLightingToSurface(renderer, position, v3Scale(normal, -1.0), definition->material); - - col1.r = (col1.r + col2.r) / 2.0; - col1.g = (col1.g + col2.g) / 2.0; - col1.b = (col1.b + col2.b) / 2.0; - col1.a = (col1.a + col2.a) / 2.0; - - return col1; -} - -double CloudBasicLayerRenderer::getDensity(CloudLayerDefinition* layer, const Vector3 &location) -{ - return 0.0; -} - -Color CloudBasicLayerRenderer::getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location) +Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location) { + CloudLayerDefinition* layer = model->getLayer(); int i, segment_count; double max_length, detail, total_length, inside_length; Vector3 start, end, direction; @@ -236,7 +148,7 @@ Color CloudBasicLayerRenderer::getColor(CloudLayerDefinition* layer, const Vecto start = eye; end = location; - if (!optimizeSearchLimits(layer, &start, &end)) + if (!optimizeSearchLimits(model, &start, &end)) { return COLOR_TRANSPARENT; } @@ -246,16 +158,25 @@ Color CloudBasicLayerRenderer::getColor(CloudLayerDefinition* layer, const Vecto direction = direction.normalize(); result = COLOR_TRANSPARENT; - detail = parent->getPrecision(parent, start) / layer->shape_scaling; + detail = parent->getPrecision(parent, start) / layer->scaling; + double transparency_depth = layer->scaling * 0.5; - segment_count = _findSegments(layer, parent, start, direction, detail, 20, layer->transparencydepth, max_length, &inside_length, &total_length, segments); + segment_count = _findSegments(model, parent, start, direction, detail, 20, transparency_depth, max_length, &inside_length, &total_length, segments); for (i = segment_count - 1; i >= 0; i--) { - col = _applyLayerLighting(layer, parent, segments[i].start, detail); - col.a = (segments[i].length >= layer->transparencydepth) ? 1.0 : (segments[i].length / layer->transparencydepth); + SurfaceMaterial material; + material.base = colorToHSL(Color(0.7, 0.7, 0.7)); + material.hardness = 0.25; + material.reflection = 0.3; + material.shininess = 0.8; + materialValidate(&material); + + col = parent->applyLightingToSurface(parent, segments[i].start, parent->getAtmosphereRenderer()->getSunDirection(), &material); + + col.a = (segments[i].length >= transparency_depth) ? 1.0 : (segments[i].length / transparency_depth); colorMask(&result, &col); } - if (inside_length >= layer->transparencydepth) + if (inside_length >= transparency_depth) { result.a = 1.0; } @@ -267,7 +188,7 @@ Color CloudBasicLayerRenderer::getColor(CloudLayerDefinition* layer, const Vecto return result; } -bool CloudBasicLayerRenderer::alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &, const Vector3 &location) +bool CloudBasicLayerRenderer::alterLight(BaseCloudsModel *model, LightDefinition* light, const Vector3 &, const Vector3 &location) { Vector3 start, end; double inside_depth, total_depth, factor; @@ -275,27 +196,29 @@ bool CloudBasicLayerRenderer::alterLight(CloudLayerDefinition* layer, LightDefin start = location; end = location.add(light->direction.scale(10000.0)); - if (not optimizeSearchLimits(layer, &start, &end)) + if (not optimizeSearchLimits(model, &start, &end)) { return false; } - _findSegments(layer, parent, start, light->direction, 0.1, 20, layer->lighttraversal, end.sub(start).getNorm(), &inside_depth, &total_depth, segments); + double light_traversal = model->getLayer()->scaling * 8.0; + _findSegments(model, parent, start, light->direction, 0.1, 20, light_traversal, end.sub(start).getNorm(), &inside_depth, &total_depth, segments); - if (layer->lighttraversal < 0.0001) + if (light_traversal < 0.0001) { factor = 0.0; } else { - factor = inside_depth / layer->lighttraversal; + factor = inside_depth / light_traversal; if (factor > 1.0) { factor = 1.0; } } - factor = 1.0 - (1.0 - layer->minimumlight) * factor; + double miminum_light = 0.4; + factor = 1.0 - (1.0 - miminum_light) * factor; light->color.r *= factor; light->color.g *= factor; diff --git a/src/render/software/CloudBasicLayerRenderer.h b/src/render/software/CloudBasicLayerRenderer.h index ad840ae..4236191 100644 --- a/src/render/software/CloudBasicLayerRenderer.h +++ b/src/render/software/CloudBasicLayerRenderer.h @@ -10,14 +10,19 @@ namespace paysages { namespace software { +/*! + * \brief Basic cloud layer renderer. + * + * This renderer simply iters through the cloud layer, collecting cloud segments. + * It does not account for local density variations. + */ class SOFTWARESHARED_EXPORT CloudBasicLayerRenderer: public BaseCloudLayerRenderer { public: CloudBasicLayerRenderer(SoftwareRenderer* parent); - virtual double getDensity(CloudLayerDefinition* layer, const Vector3 &location) override; - virtual Color getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location) override; - virtual bool alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &eye, const Vector3 &location) override; + virtual Color getColor(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location) override; + virtual bool alterLight(BaseCloudsModel *model, LightDefinition* light, const Vector3 &eye, const Vector3 &location) override; }; } diff --git a/src/render/software/CloudsRenderer.cpp b/src/render/software/CloudsRenderer.cpp index 4f5fb99..04273d1 100644 --- a/src/render/software/CloudsRenderer.cpp +++ b/src/render/software/CloudsRenderer.cpp @@ -3,13 +3,20 @@ #include "SoftwareRenderer.h" #include "Scenery.h" #include "CloudsDefinition.h" +#include "CloudLayerDefinition.h" #include "BaseCloudLayerRenderer.h" #include "CloudBasicLayerRenderer.h" +#include "clouds/BaseCloudsModel.h" +#include "clouds/CloudModelStratoCumulus.h" + CloudsRenderer::CloudsRenderer(SoftwareRenderer* parent): parent(parent) { fake_renderer = new BaseCloudLayerRenderer(parent); + + CloudLayerDefinition* fake_layer = new CloudLayerDefinition(NULL); + fake_model = new BaseCloudsModel(fake_layer); } CloudsRenderer::~CloudsRenderer() @@ -19,6 +26,13 @@ CloudsRenderer::~CloudsRenderer() delete renderer; } delete fake_renderer; + + for (auto model : layer_models) + { + delete model; + } + delete fake_model->getLayer(); + delete fake_model; } void CloudsRenderer::update() @@ -29,11 +43,42 @@ void CloudsRenderer::update() } layer_renderers.clear(); + for (auto model : layer_models) + { + delete model; + } + layer_models.clear(); + CloudsDefinition* clouds = parent->getScenery()->getClouds(); int n = clouds->count(); for (int i = 0; i < n; i++) { layer_renderers.push_back(new CloudBasicLayerRenderer(parent)); + + CloudLayerDefinition* layer = clouds->getCloudLayer(i); + BaseCloudsModel* model; + switch (layer->type) + { + case CloudLayerDefinition::STRATUS: + case CloudLayerDefinition::NIMBOSTRATUS: + case CloudLayerDefinition::CUMULUS: + model = new BaseCloudsModel(layer); + break; + case CloudLayerDefinition::STRATOCUMULUS: + model = new CloudModelStratoCumulus(layer); + break; + case CloudLayerDefinition::ALTOCUMULUS: + case CloudLayerDefinition::ALTOSTRATUS: + case CloudLayerDefinition::CUMULONIMBUS: + case CloudLayerDefinition::CIRROCUMULUS: + case CloudLayerDefinition::CIRROSTRATUS: + case CloudLayerDefinition::CIRRUS: + model = new BaseCloudsModel(layer); + break; + } + + layer_models.push_back(model); + model->update(); } } @@ -49,6 +94,18 @@ BaseCloudLayerRenderer* CloudsRenderer::getLayerRenderer(unsigned int layer) } } +BaseCloudsModel* CloudsRenderer::getLayerModel(unsigned int layer) +{ + if (layer < layer_models.size()) + { + return layer_models[layer]; + } + else + { + return fake_model; + } +} + Color CloudsRenderer::getColor(const Vector3 &eye, const Vector3 &location, const Color &base) { CloudsDefinition* definition = parent->getScenery()->getClouds(); @@ -64,10 +121,10 @@ Color CloudsRenderer::getColor(const Vector3 &eye, const Vector3 &location, cons for (int i = 0; i < n; i++) { - CloudLayerDefinition* layer = definition->getCloudLayer(i); BaseCloudLayerRenderer* layer_renderer = getLayerRenderer(i); + BaseCloudsModel* layer_model = getLayerModel(i); - Color layer_color = layer_renderer->getColor(layer, eye, location); + Color layer_color = layer_renderer->getColor(layer_model, eye, location); colorMask(&cumul, &layer_color); } diff --git a/src/render/software/CloudsRenderer.h b/src/render/software/CloudsRenderer.h index f938660..891e3dd 100644 --- a/src/render/software/CloudsRenderer.h +++ b/src/render/software/CloudsRenderer.h @@ -18,32 +18,45 @@ public: virtual ~CloudsRenderer(); /*! - * Update the renderer with the bound scenery. + * \brief Update the renderer with the bound scenery. + * + * Don't call this if another thread is currently using this renderer. */ void update(); /*! - * Get the layer renderer for a given layer. + * \brief Get the layer renderer for a given layer. * * The returned renderer is managed by this object and should not be deleted. */ virtual BaseCloudLayerRenderer* getLayerRenderer(unsigned int layer); /*! - * Get the composited color, as applied on a base color and location. + * \brief Get the cloud model for a given layer. + * + * The returned model is managed by this object and should not be deleted. + */ + virtual BaseCloudsModel* getLayerModel(unsigned int layer); + + /*! + * \brief Get the composited color, as applied on a base color and location. */ virtual Color getColor(const Vector3 &eye, const Vector3 &location, const Color &base); /*! - * Alter a light, as if passed through all layers. + * \brief Alter a light, as if passed through all layers. * * Return true if the light was altered. */ virtual bool alterLight(LightDefinition* light, const Vector3 &eye, const Vector3 &location); private: SoftwareRenderer* parent; + std::vector layer_renderers; BaseCloudLayerRenderer* fake_renderer; + + std::vector layer_models; + BaseCloudsModel* fake_model; }; } diff --git a/src/render/software/clouds/BaseCloudsModel.cpp b/src/render/software/clouds/BaseCloudsModel.cpp new file mode 100644 index 0000000..7e943e5 --- /dev/null +++ b/src/render/software/clouds/BaseCloudsModel.cpp @@ -0,0 +1,49 @@ +#include "BaseCloudsModel.h" + +#include "CloudLayerDefinition.h" + +BaseCloudsModel::BaseCloudsModel(CloudLayerDefinition *layer): + layer(layer) +{ +} + +BaseCloudsModel::~BaseCloudsModel() +{ +} + +void BaseCloudsModel::update() +{ +} + +void BaseCloudsModel::getAltitudeRange(double *min_altitude, double *max_altitude) const +{ + *min_altitude = layer->altitude; + *max_altitude = layer->altitude * layer->scaling; +} + +void BaseCloudsModel::getDetailRange(double *min_step, double *max_step) const +{ + *min_step = 0.1; + *max_step = 1.0; +} + +double BaseCloudsModel::getProbability(const Vector3 &, double) const +{ + return 1.0; +} + +double BaseCloudsModel::getDensity(const Vector3 &) const +{ + return 0.0; +} + +Color BaseCloudsModel::filterLight(const Color &light, double, double) const +{ + return light; +} + +Color BaseCloudsModel::applyLightExit(const Color &light, const Vector3 &, const Vector3 &) const +{ + return light; +} + diff --git a/src/render/software/clouds/BaseCloudsModel.h b/src/render/software/clouds/BaseCloudsModel.h new file mode 100644 index 0000000..594ae04 --- /dev/null +++ b/src/render/software/clouds/BaseCloudsModel.h @@ -0,0 +1,38 @@ +#ifndef BASECLOUDSMODEL_H +#define BASECLOUDSMODEL_H + +#include "../software_global.h" + +#include "Color.h" + +namespace paysages { +namespace software { + +/*! + * \brief Abstract class for all cloud models (cirrus, cumulus...). + */ +class BaseCloudsModel +{ +public: + BaseCloudsModel(CloudLayerDefinition *layer); + virtual ~BaseCloudsModel(); + + 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) 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;} + +protected: + CloudLayerDefinition *layer; +}; + +} +} + +#endif // BASECLOUDSMODEL_H diff --git a/src/render/software/clouds/CloudModelStratoCumulus.cpp b/src/render/software/clouds/CloudModelStratoCumulus.cpp new file mode 100644 index 0000000..ca5fd57 --- /dev/null +++ b/src/render/software/clouds/CloudModelStratoCumulus.cpp @@ -0,0 +1,67 @@ +#include "CloudModelStratoCumulus.h" + +#include "NoiseGenerator.h" +#include "Vector3.h" +#include "CloudLayerDefinition.h" + +CloudModelStratoCumulus::CloudModelStratoCumulus(CloudLayerDefinition* layer): + BaseCloudsModel(layer) +{ + noise = new NoiseGenerator(); +} + +CloudModelStratoCumulus::~CloudModelStratoCumulus() +{ + delete noise; +} + +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); +} + +void CloudModelStratoCumulus::getAltitudeRange(double *min_altitude, double *max_altitude) const +{ + *min_altitude = 2.0 + 7.0 * layer->altitude; + *max_altitude = *min_altitude + 5.0 * layer->scaling; +} + +double CloudModelStratoCumulus::getDensity(const Vector3 &location) const +{ + double val; + double min_altitude, max_altitude; + + getAltitudeRange(&min_altitude, &max_altitude); + + if (location.y < min_altitude || location.y > max_altitude) + { + return 0.0; + } + else + { + double x = location.x / (5.0 * layer->scaling); + double y = (location.y - min_altitude) / (5.0 * layer->scaling); + double z = location.z / (5.0 * layer->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 - 0.5 + coverage; + } +} diff --git a/src/render/software/clouds/CloudModelStratoCumulus.h b/src/render/software/clouds/CloudModelStratoCumulus.h new file mode 100644 index 0000000..9bb039b --- /dev/null +++ b/src/render/software/clouds/CloudModelStratoCumulus.h @@ -0,0 +1,29 @@ +#ifndef CLOUDMODELSTRATOCUMULUS_H +#define CLOUDMODELSTRATOCUMULUS_H + +#include "../software_global.h" + +#include "BaseCloudsModel.h" + +namespace paysages { +namespace software { + +class CloudModelStratoCumulus : public BaseCloudsModel +{ +public: + CloudModelStratoCumulus(CloudLayerDefinition* layer); + virtual ~CloudModelStratoCumulus(); + + virtual void update() override; + + virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override; + virtual double getDensity(const Vector3 &location) const override; + +private: + NoiseGenerator* noise; +}; + +} +} + +#endif // CLOUDMODELSTRATOCUMULUS_H diff --git a/src/render/software/software.pro b/src/render/software/software.pro index 88ed67a..855fea7 100644 --- a/src/render/software/software.pro +++ b/src/render/software/software.pro @@ -20,7 +20,9 @@ SOURCES += SoftwareRenderer.cpp \ CloudsRenderer.cpp \ BaseCloudLayerRenderer.cpp \ SkyRasterizer.cpp \ - CloudBasicLayerRenderer.cpp + CloudBasicLayerRenderer.cpp \ + clouds/BaseCloudsModel.cpp \ + clouds/CloudModelStratoCumulus.cpp HEADERS += SoftwareRenderer.h\ software_global.h \ @@ -30,7 +32,9 @@ HEADERS += SoftwareRenderer.h\ CloudsRenderer.h \ BaseCloudLayerRenderer.h \ SkyRasterizer.h \ - CloudBasicLayerRenderer.h + CloudBasicLayerRenderer.h \ + clouds/BaseCloudsModel.h \ + clouds/CloudModelStratoCumulus.h unix:!symbian { maemo5 { diff --git a/src/render/software/software_global.h b/src/render/software/software_global.h index 1cb06aa..e361f99 100644 --- a/src/render/software/software_global.h +++ b/src/render/software/software_global.h @@ -24,6 +24,7 @@ namespace software { class CloudsRenderer; class BaseCloudLayerRenderer; + class BaseCloudsModel; } }