diff --git a/ChangeLog b/ChangeLog
index 9bb81b6..4d99d30 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,7 @@ Previews :
Scenery :
* Added clouds hardness to light.
* Added sun halo control.
+ * New cloud model with 2 noises : one for the global shape and one for edges.
Rendering :
* New texture model (perpendicular displacement and thickness).
diff --git a/TODO b/TODO
index 71ae6e5..e0aaa6b 100644
--- a/TODO
+++ b/TODO
@@ -3,6 +3,7 @@ Technology Preview 2 :
- Remove color gradations (replace with automatic boolean and simple colors).
- Replace zone ranges with curves (with curve input and curve dialog).
- Interface for textures thickness, slope_range and thickness_transparency (and correct slider ranges).
+- Add "hardness to light" and shadow control ("minimum lighting") to material.
- Render tab previews should not rerender when changing render options.
- Add layer sorting/naming.
- Disable specular lighting in explorer (and everything camera dependent).
@@ -14,6 +15,7 @@ Technology Preview 2 :
- Use the curve editor in noise editor
- Add a noise filler (and maybe noise intervals ?).
- Add a popup when rendering is complete (with stats), except for quick render.
+- Optimize the use of noiseGetMaxValue (limit its use or cache it).
- Fix the distorted sun appearance.
- Improve curve editor.
=> Add curve modes
diff --git a/gui_qt/formclouds.cpp b/gui_qt/formclouds.cpp
index ec568e1..12dead1 100644
--- a/gui_qt/formclouds.cpp
+++ b/gui_qt/formclouds.cpp
@@ -112,8 +112,8 @@ protected:
cloudsLayerCopyDefinition(&_layer, &_preview_layer);
_preview_layer.ymax = (_preview_layer.ymax - _preview_layer.ymin) / 2.0;
_preview_layer.ymin = -_preview_layer.ymin;
- curveClear(_preview_layer.density_altitude);
- _preview_layer.customcoverage = _coverageFunc;
+ curveClear(_preview_layer.coverage_by_altitude);
+ _preview_layer._custom_coverage = _coverageFunc;
}
private:
Renderer _renderer;
@@ -157,10 +157,13 @@ FormClouds::FormClouds(QWidget *parent):
addInputDouble(tr("Lower altitude"), &_layer.ymin, -10.0, 50.0, 0.5, 5.0);
addInputDouble(tr("Upper altitude"), &_layer.ymax, -10.0, 50.0, 0.5, 5.0);
- addInputCurve(tr("Density by altitude"), _layer.density_altitude, 0.0, 1.0, 0.0, 1.0);
- addInputNoise(tr("Noise"), _layer.noise);
- addInputDouble(tr("Coverage"), &_layer.coverage, 0.0, 1.0, 0.01, 0.1);
- addInputDouble(tr("Scaling"), &_layer.scaling, 1.0, 100.0, 0.5, 5.0);
+ addInputDouble(tr("Max coverage"), &_layer.base_coverage, 0.0, 1.0, 0.01, 0.1);
+ addInputCurve(tr("Coverage by altitude"), _layer.coverage_by_altitude, 0.0, 1.0, 0.0, 1.0);
+ addInputNoise(tr("Shape noise"), _layer.shape_noise);
+ addInputDouble(tr("Shape scaling"), &_layer.shape_scaling, 1.0, 10.0, 0.1, 1.0);
+ addInputNoise(tr("Edge noise"), _layer.edge_noise);
+ addInputDouble(tr("Edge scaling"), &_layer.edge_scaling, 0.02, 0.5, 0.01, 0.1);
+ 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, 100.0, 0.5, 5.0);
diff --git a/i18n/paysages_fr.ts b/i18n/paysages_fr.ts
index e9ba179..362cce1 100644
--- a/i18n/paysages_fr.ts
+++ b/i18n/paysages_fr.ts
@@ -374,27 +374,19 @@ Maintenir Ctrl : Plus rapide
-
-
-
-
-
-
- Bruit
+ Bruit
-
- Couverture
+ Couverture
-
- Echelle
+ Echelle
-
+
@@ -410,23 +402,58 @@ Maintenir Ctrl : Plus rapide
Concentration de la réflexion de lumière
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
Distance de transparence
-
+
Distance de traversée de la lumière
-
+
Eclairage minimal
diff --git a/lib_paysages/clouds.c b/lib_paysages/clouds.c
index 5232e30..fe97ab7 100644
--- a/lib_paysages/clouds.c
+++ b/lib_paysages/clouds.c
@@ -41,15 +41,18 @@ void cloudsSave(PackStream* stream, CloudsDefinition* definition)
packWriteDouble(stream, &layer->ymin);
packWriteDouble(stream, &layer->ymax);
- curveSave(stream, layer->density_altitude);
- noiseSaveGenerator(stream, layer->noise);
+ curveSave(stream, layer->coverage_by_altitude);
+ noiseSaveGenerator(stream, layer->shape_noise);
+ noiseSaveGenerator(stream, layer->edge_noise);
materialSave(stream, &layer->material);
packWriteDouble(stream, &layer->hardness);
packWriteDouble(stream, &layer->transparencydepth);
packWriteDouble(stream, &layer->lighttraversal);
packWriteDouble(stream, &layer->minimumlight);
- packWriteDouble(stream, &layer->scaling);
- packWriteDouble(stream, &layer->coverage);
+ packWriteDouble(stream, &layer->shape_scaling);
+ packWriteDouble(stream, &layer->edge_scaling);
+ packWriteDouble(stream, &layer->edge_length);
+ packWriteDouble(stream, &layer->base_coverage);
}
}
@@ -70,15 +73,18 @@ void cloudsLoad(PackStream* stream, CloudsDefinition* definition)
packReadDouble(stream, &layer->ymin);
packReadDouble(stream, &layer->ymax);
- curveLoad(stream, layer->density_altitude);
- noiseLoadGenerator(stream, layer->noise);
+ curveLoad(stream, layer->coverage_by_altitude);
+ noiseLoadGenerator(stream, layer->shape_noise);
+ noiseLoadGenerator(stream, layer->edge_noise);
materialLoad(stream, &layer->material);
packReadDouble(stream, &layer->hardness);
packReadDouble(stream, &layer->transparencydepth);
packReadDouble(stream, &layer->lighttraversal);
packReadDouble(stream, &layer->minimumlight);
- packReadDouble(stream, &layer->scaling);
- packReadDouble(stream, &layer->coverage);
+ packReadDouble(stream, &layer->shape_scaling);
+ packReadDouble(stream, &layer->edge_scaling);
+ packReadDouble(stream, &layer->edge_length);
+ packReadDouble(stream, &layer->base_coverage);
}
}
@@ -132,7 +138,7 @@ static double _standardCoverageFunc(CloudsLayerDefinition* layer, Vector3 positi
}
else
{
- return layer->coverage * curveGetValue(layer->density_altitude, (position.y - layer->ymin) / (layer->ymax - layer->ymin));
+ return layer->base_coverage * curveGetValue(layer->coverage_by_altitude, (position.y - layer->ymin) / (layer->ymax - layer->ymin));
}
}
@@ -142,11 +148,11 @@ CloudsLayerDefinition cloudsLayerCreateDefinition()
result.ymin = 4.0;
result.ymax = 10.0;
- result.density_altitude = curveCreate();
- curveQuickAddPoint(result.density_altitude, 0.0, 0.0);
- curveQuickAddPoint(result.density_altitude, 0.3, 1.0);
- curveQuickAddPoint(result.density_altitude, 0.5, 1.0);
- curveQuickAddPoint(result.density_altitude, 1.0, 0.0);
+ result.coverage_by_altitude = curveCreate();
+ curveQuickAddPoint(result.coverage_by_altitude, 0.0, 0.0);
+ curveQuickAddPoint(result.coverage_by_altitude, 0.3, 1.0);
+ curveQuickAddPoint(result.coverage_by_altitude, 0.5, 1.0);
+ curveQuickAddPoint(result.coverage_by_altitude, 1.0, 0.0);
result.material.base.r = 0.7;
result.material.base.g = 0.7;
result.material.base.b = 0.7;
@@ -157,33 +163,25 @@ CloudsLayerDefinition cloudsLayerCreateDefinition()
result.transparencydepth = 1.5;
result.lighttraversal = 7.0;
result.minimumlight = 0.4;
- result.scaling = 3.5;
- result.coverage = 0.45;
- result.noise = noiseCreateGenerator();
- noiseGenerateBaseNoise(result.noise, 262144);
- noiseAddLevelSimple(result.noise, 1.0, 1.0);
- noiseAddLevelSimple(result.noise, 1.0 / 2.0, 0.6);
- noiseAddLevelSimple(result.noise, 1.0 / 4.0, 0.3);
- noiseAddLevelSimple(result.noise, 1.0 / 10.0, 0.15);
- noiseAddLevelSimple(result.noise, 1.0 / 20.0, 0.09);
- noiseAddLevelSimple(result.noise, 1.0 / 40.0, 0.06);
- noiseAddLevelSimple(result.noise, 1.0 / 60.0, 0.03);
- noiseAddLevelSimple(result.noise, 1.0 / 80.0, 0.015);
- noiseAddLevelSimple(result.noise, 1.0 / 100.0, 0.06);
- noiseAddLevelSimple(result.noise, 1.0 / 150.0, 0.015);
- noiseAddLevelSimple(result.noise, 1.0 / 200.0, 0.009);
- noiseAddLevelSimple(result.noise, 1.0 / 400.0, 0.024);
- noiseAddLevelSimple(result.noise, 1.0 / 800.0, 0.003);
- noiseAddLevelSimple(result.noise, 1.0 / 1000.0, 0.0015);
+ result.shape_scaling = 3.5;
+ result.edge_scaling = 0.1;
+ result.edge_length = 0.25;
+ result.base_coverage = 0.35;
+ result.shape_noise = noiseCreateGenerator();
+ noiseGenerateBaseNoise(result.shape_noise, 20000);
+ noiseAddLevelsSimple(result.shape_noise, 4, 1.0, 1.0);
+ result.edge_noise = noiseCreateGenerator();
+ noiseGenerateBaseNoise(result.edge_noise, 20000);
+ noiseAddLevelsSimple(result.edge_noise, 8, 1.0, 1.0);
- result.customcoverage = _standardCoverageFunc;
+ result._custom_coverage = _standardCoverageFunc;
return result;
}
void cloudsLayerDeleteDefinition(CloudsLayerDefinition* definition)
{
- noiseDeleteGenerator(definition->noise);
+ noiseDeleteGenerator(definition->shape_noise);
}
void cloudsLayerCopyDefinition(CloudsLayerDefinition* source, CloudsLayerDefinition* destination)
@@ -198,22 +196,29 @@ void cloudsLayerCopyDefinition(CloudsLayerDefinition* source, CloudsLayerDefinit
temp = *destination;
*destination = *source;
- destination->noise = temp.noise;
- noiseCopy(source->noise, destination->noise);
-
- destination->density_altitude = temp.density_altitude;
- curveCopy(source->density_altitude, destination->density_altitude);
+ destination->shape_noise = temp.shape_noise;
+ noiseCopy(source->shape_noise, destination->shape_noise);
+
+ destination->edge_noise = temp.edge_noise;
+ noiseCopy(source->edge_noise, destination->edge_noise);
+
+ destination->coverage_by_altitude = temp.coverage_by_altitude;
+ curveCopy(source->coverage_by_altitude, destination->coverage_by_altitude);
}
void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition)
{
- if (definition->scaling < 0.0001)
+ if (definition->shape_scaling < 0.0001)
{
- definition->scaling = 0.00001;
+ definition->shape_scaling = 0.00001;
}
- if (definition->customcoverage == NULL)
+ if (definition->edge_scaling < 0.0001)
{
- definition->customcoverage = _standardCoverageFunc;
+ definition->edge_scaling = 0.00001;
+ }
+ if (definition->_custom_coverage == NULL)
+ {
+ definition->_custom_coverage = _standardCoverageFunc;
}
}
@@ -266,11 +271,33 @@ void cloudsDeleteLayer(CloudsDefinition* definition, int layer)
static inline double _getDistanceToBorder(CloudsLayerDefinition* layer, Vector3 position)
{
- double val;
+ double density, coverage, val;
- val = 0.5 * noiseGet3DTotal(layer->noise, position.x / layer->scaling, position.y / layer->scaling, position.z / layer->scaling) / noiseGetMaxValue(layer->noise);
+ val = noiseGet3DTotal(layer->shape_noise, position.x / layer->shape_scaling, position.y / layer->shape_scaling, position.z / layer->shape_scaling) / noiseGetMaxValue(layer->shape_noise);
+ coverage = layer->_custom_coverage(layer, position);
+ density = 0.5 * val - 0.5 + coverage;
+
+ if (density <= 0.0)
+ {
+ /* outside the main shape */
+ return density * layer->shape_scaling;
+ }
+ else
+ {
+ /* inside the main shape, using edge noise */
+ density /= coverage;
+ if (density < layer->edge_length)
+ {
+ val = 0.5 * noiseGet3DTotal(layer->edge_noise, position.x / layer->edge_scaling, position.y / layer->edge_scaling, position.z / layer->edge_scaling) / noiseGetMaxValue(layer->edge_noise);
+ val = (val - 0.5 + density / layer->edge_length) * layer->edge_scaling;
- return (val - 0.5 + layer->customcoverage(layer, position)) * layer->scaling;
+ return val;
+ }
+ else
+ {
+ return density * coverage * layer->shape_scaling;
+ }
+ }
}
static inline Vector3 _getNormal(CloudsLayerDefinition* layer, Vector3 position, double detail)
@@ -404,7 +431,7 @@ static int _findSegments(CloudsLayerDefinition* definition, Renderer* renderer,
}
render_precision = 15.2 - 1.5 * (double)renderer->render_quality;
- render_precision = render_precision * definition->scaling / 50.0;
+ render_precision = render_precision * definition->shape_scaling / 50.0;
if (render_precision > max_total_length / 10.0)
{
render_precision = max_total_length / 10.0;
@@ -532,7 +559,7 @@ Color cloudsGetLayerColor(CloudsLayerDefinition* definition, Renderer* renderer,
direction = v3Normalize(direction);
result = COLOR_TRANSPARENT;
- detail = renderer->getPrecision(renderer, start) / definition->scaling;
+ detail = renderer->getPrecision(renderer, start) / definition->shape_scaling;
segment_count = _findSegments(definition, renderer, start, direction, detail, 20, definition->transparencydepth, max_length, &inside_length, &total_length, segments);
for (i = segment_count - 1; i >= 0; i--)
diff --git a/lib_paysages/clouds.h b/lib_paysages/clouds.h
index 26d7da7..44c8b7f 100644
--- a/lib_paysages/clouds.h
+++ b/lib_paysages/clouds.h
@@ -20,16 +20,19 @@ struct CloudsLayerDefinition
{
double ymin;
double ymax;
- Curve* density_altitude;
- NoiseGenerator* noise;
+ double base_coverage;
+ Curve* coverage_by_altitude;
+ NoiseGenerator* shape_noise;
+ double shape_scaling;
+ NoiseGenerator* edge_noise;
+ double edge_scaling;
+ double edge_length;
SurfaceMaterial material;
double hardness;
double transparencydepth;
double lighttraversal;
double minimumlight;
- double scaling;
- double coverage;
- CloudCoverageFunc customcoverage;
+ CloudCoverageFunc _custom_coverage;
};
typedef struct