WIP on new clouds renderer
This commit is contained in:
parent
ff27afe675
commit
9be090b1ff
20 changed files with 371 additions and 407 deletions
1
TODO
1
TODO
|
@ -1,5 +1,6 @@
|
||||||
Technology Preview 2 :
|
Technology Preview 2 :
|
||||||
- Add initial terrain offset so that the (0,0) coordinates are above water.
|
- 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
|
- Finalize lighting/clouds refactoring
|
||||||
=> Restore cloud lighting
|
=> Restore cloud lighting
|
||||||
=> Improve cloud rendering precision (and beware of precision discontinuity when rendering clouds in front of ground (shorter distance)).
|
=> Improve cloud rendering precision (and beware of precision discontinuity when rendering clouds in front of ground (shorter distance)).
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Color
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Color();
|
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 save(PackStream* stream) const;
|
||||||
void load(PackStream* stream);
|
void load(PackStream* stream);
|
||||||
|
|
|
@ -8,20 +8,14 @@
|
||||||
CloudLayerDefinition::CloudLayerDefinition(BaseDefinition* parent):
|
CloudLayerDefinition::CloudLayerDefinition(BaseDefinition* parent):
|
||||||
BaseDefinition(parent)
|
BaseDefinition(parent)
|
||||||
{
|
{
|
||||||
_coverage_by_altitude = new Curve;
|
type = CIRRUS;
|
||||||
_coverage_noise = new NoiseGenerator();
|
altitude = 0.5;
|
||||||
_shape_noise = new NoiseGenerator();
|
scaling = 0.5;
|
||||||
_edge_noise = new NoiseGenerator();
|
coverage = 0.5;
|
||||||
material = new SurfaceMaterial;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CloudLayerDefinition::~CloudLayerDefinition()
|
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)
|
CloudLayerDefinition* CloudLayerDefinition::newCopy(const CloudLayerDefinition& other, BaseDefinition* parent)
|
||||||
|
@ -45,21 +39,9 @@ void CloudLayerDefinition::save(PackStream* stream) const
|
||||||
int clouds_type = (int)type;
|
int clouds_type = (int)type;
|
||||||
|
|
||||||
stream->write(&clouds_type);
|
stream->write(&clouds_type);
|
||||||
stream->write(&lower_altitude);
|
stream->write(&altitude);
|
||||||
stream->write(&thickness);
|
stream->write(&scaling);
|
||||||
_coverage_by_altitude->save(stream);
|
stream->write(&coverage);
|
||||||
_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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloudLayerDefinition::load(PackStream* stream)
|
void CloudLayerDefinition::load(PackStream* stream)
|
||||||
|
@ -70,21 +52,9 @@ void CloudLayerDefinition::load(PackStream* stream)
|
||||||
|
|
||||||
stream->read(&clouds_type);
|
stream->read(&clouds_type);
|
||||||
type = (CloudsType)clouds_type;
|
type = (CloudsType)clouds_type;
|
||||||
stream->read(&lower_altitude);
|
stream->read(&altitude);
|
||||||
stream->read(&thickness);
|
stream->read(&scaling);
|
||||||
_coverage_by_altitude->load(stream);
|
stream->read(&coverage);
|
||||||
_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);
|
|
||||||
|
|
||||||
validate();
|
validate();
|
||||||
}
|
}
|
||||||
|
@ -96,168 +66,15 @@ void CloudLayerDefinition::copy(BaseDefinition* _destination) const
|
||||||
CloudLayerDefinition* destination = (CloudLayerDefinition*)_destination;
|
CloudLayerDefinition* destination = (CloudLayerDefinition*)_destination;
|
||||||
|
|
||||||
destination->type = type;
|
destination->type = type;
|
||||||
destination->lower_altitude = lower_altitude;
|
destination->altitude = altitude;
|
||||||
destination->thickness = thickness;
|
destination->scaling = scaling;
|
||||||
_coverage_by_altitude->copy(destination->_coverage_by_altitude);
|
destination->coverage = coverage;
|
||||||
_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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloudLayerDefinition::validate()
|
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();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,39 +26,23 @@ public:
|
||||||
public:
|
public:
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
CLOUDS_TYPE_CIRRUS,
|
STRATUS,
|
||||||
CLOUDS_TYPE_CUMULUS,
|
NIMBOSTRATUS,
|
||||||
CLOUDS_TYPE_STRATOCUMULUS,
|
CUMULUS,
|
||||||
CLOUDS_TYPE_STRATUS
|
STRATOCUMULUS,
|
||||||
|
ALTOCUMULUS,
|
||||||
|
ALTOSTRATUS,
|
||||||
|
CUMULONIMBUS,
|
||||||
|
CIRROCUMULUS,
|
||||||
|
CIRROSTRATUS,
|
||||||
|
CIRRUS
|
||||||
} CloudsType;
|
} 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:
|
public:
|
||||||
CloudsType type;
|
CloudsType type;
|
||||||
double lower_altitude;
|
double altitude;
|
||||||
double thickness;
|
double scaling;
|
||||||
double base_coverage;
|
double 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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,8 @@ void CloudsDefinition::applyPreset(CloudsPreset preset)
|
||||||
if (preset == CLOUDS_PRESET_PARTLY_CLOUDY)
|
if (preset == CLOUDS_PRESET_PARTLY_CLOUDY)
|
||||||
{
|
{
|
||||||
CloudLayerDefinition* layer = new CloudLayerDefinition(this);
|
CloudLayerDefinition* layer = new CloudLayerDefinition(this);
|
||||||
layer->applyPreset(CloudLayerDefinition::CLOUDS_LAYER_PRESET_CIRRUS);
|
layer->type = CloudLayerDefinition::STRATOCUMULUS;
|
||||||
layer->setName("Cirrus");
|
layer->setName("Strato-cumulus");
|
||||||
addLayer(layer);
|
addLayer(layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,6 @@
|
||||||
FormClouds::FormClouds(QWidget *parent):
|
FormClouds::FormClouds(QWidget *parent):
|
||||||
BaseFormLayer(parent)
|
BaseFormLayer(parent)
|
||||||
{
|
{
|
||||||
addAutoPreset(tr("Cirrus"));
|
|
||||||
addAutoPreset(tr("Cumulus"));
|
|
||||||
addAutoPreset(tr("Stratocumulus"));
|
|
||||||
addAutoPreset(tr("Stratus"));
|
|
||||||
|
|
||||||
_definition = new CloudsDefinition(NULL);
|
_definition = new CloudsDefinition(NULL);
|
||||||
_layer = new CloudLayerDefinition(NULL);
|
_layer = new CloudLayerDefinition(NULL);
|
||||||
|
|
||||||
|
@ -33,17 +28,9 @@ FormClouds::FormClouds(QWidget *parent):
|
||||||
_previewColor->setRenderer(_previewColorRenderer);
|
_previewColor->setRenderer(_previewColorRenderer);
|
||||||
|
|
||||||
addInputEnum(tr("Clouds model"), (int*)&_layer->type, QStringList() << tr("Cirrus") << tr("Cumulus") << tr("Stratocumulus") << tr("Stratus"));
|
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("Lower altitude"), &_layer->altitude, 0.0, 1.0, 0.01, 0.1);
|
||||||
addInputDouble(tr("Layer thickness"), &_layer->thickness, 0.0, 20.0, 0.1, 1.0);
|
addInputDouble(tr("Scaling"), &_layer->scaling, 0.0, 1.0, 0.01, 0.1);
|
||||||
addInputDouble(tr("Max coverage"), &_layer->base_coverage, 0.0, 1.0, 0.01, 0.1);
|
addInputDouble(tr("Coverage"), &_layer->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);
|
|
||||||
|
|
||||||
setLayers(_definition);
|
setLayers(_definition);
|
||||||
}
|
}
|
||||||
|
@ -81,9 +68,3 @@ void FormClouds::layerWriteCurrentTo(void* layer_definition)
|
||||||
{
|
{
|
||||||
_layer->copy((CloudLayerDefinition*)layer_definition);
|
_layer->copy((CloudLayerDefinition*)layer_definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormClouds::autoPresetSelected(int preset)
|
|
||||||
{
|
|
||||||
_layer->applyPreset((CloudLayerDefinition::CloudsLayerPreset)preset);
|
|
||||||
BaseForm::autoPresetSelected(preset);
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ public slots:
|
||||||
protected:
|
protected:
|
||||||
virtual void layerReadCurrentFrom(void* layer_definition);
|
virtual void layerReadCurrentFrom(void* layer_definition);
|
||||||
virtual void layerWriteCurrentTo(void* layer_definition);
|
virtual void layerWriteCurrentTo(void* layer_definition);
|
||||||
virtual void autoPresetSelected(int preset);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CloudsDefinition* _definition;
|
CloudsDefinition* _definition;
|
||||||
|
|
|
@ -30,7 +30,7 @@ static void _getLightingStatus(Renderer*, LightStatus* status, Vector3, int)
|
||||||
|
|
||||||
static double _getDensity(Renderer*, CloudLayerDefinition* layer, Vector3 location)
|
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)
|
if (distance > 1.0)
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
@ -75,8 +75,7 @@ void CloudsAspectPreviewRenderer::updateEvent()
|
||||||
CloudLayerDefinition* preview_layer = getScenery()->getClouds()->getCloudLayer(0);
|
CloudLayerDefinition* preview_layer = getScenery()->getClouds()->getCloudLayer(0);
|
||||||
layer->copy(preview_layer);
|
layer->copy(preview_layer);
|
||||||
|
|
||||||
preview_layer->thickness = preview_layer->shape_scaling;
|
preview_layer->altitude = -preview_layer->scaling / 2.0;
|
||||||
preview_layer->lower_altitude = -preview_layer->thickness / 2.0;
|
|
||||||
preview_layer->validate();
|
preview_layer->validate();
|
||||||
|
|
||||||
prepare();
|
prepare();
|
||||||
|
@ -89,7 +88,7 @@ void CloudsAspectPreviewRenderer::updateEvent()
|
||||||
Color CloudsAspectPreviewRenderer::getColor2D(double x, double y, double)
|
Color CloudsAspectPreviewRenderer::getColor2D(double x, double y, double)
|
||||||
{
|
{
|
||||||
Vector3 start, end;
|
Vector3 start, end;
|
||||||
double thickness = layer->thickness;
|
double thickness = layer->scaling;
|
||||||
|
|
||||||
start.x = x * thickness * 0.5;
|
start.x = x * thickness * 0.5;
|
||||||
start.z = y * thickness * 0.5;
|
start.z = y * thickness * 0.5;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "BaseCloudLayerRenderer.h"
|
#include "BaseCloudLayerRenderer.h"
|
||||||
|
|
||||||
#include "CloudLayerDefinition.h"
|
#include "clouds/BaseCloudsModel.h"
|
||||||
|
|
||||||
BaseCloudLayerRenderer::BaseCloudLayerRenderer(SoftwareRenderer* parent):
|
BaseCloudLayerRenderer::BaseCloudLayerRenderer(SoftwareRenderer* parent):
|
||||||
parent(parent)
|
parent(parent)
|
||||||
|
@ -12,67 +12,65 @@ BaseCloudLayerRenderer::~BaseCloudLayerRenderer()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double BaseCloudLayerRenderer::getDensity(CloudLayerDefinition *, const Vector3 &)
|
Color BaseCloudLayerRenderer::getColor(BaseCloudsModel *, const Vector3 &, const Vector3 &)
|
||||||
{
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color BaseCloudLayerRenderer::getColor(CloudLayerDefinition *, const Vector3 &, const Vector3 &)
|
|
||||||
{
|
{
|
||||||
return COLOR_TRANSPARENT;
|
return COLOR_TRANSPARENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseCloudLayerRenderer::alterLight(CloudLayerDefinition *, LightDefinition *, const Vector3 &, const Vector3 &)
|
bool BaseCloudLayerRenderer::alterLight(BaseCloudsModel *, LightDefinition *, const Vector3 &, const Vector3 &)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseCloudLayerRenderer::optimizeSearchLimits(CloudLayerDefinition *layer, Vector3 *start, Vector3 *end)
|
bool BaseCloudLayerRenderer::optimizeSearchLimits(BaseCloudsModel *model, Vector3 *start, Vector3 *end)
|
||||||
{
|
{
|
||||||
Vector3 diff;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
diff = v3Sub(*end, *start);
|
diff = v3Sub(*end, *start);
|
||||||
*start = v3Add(*start, v3Scale(diff, (layer->lower_altitude + layer->thickness - start->y) / diff.y));
|
*start = v3Add(*start, v3Scale(diff, (max_altitude - start->y) / diff.y));
|
||||||
if (end->y < layer->lower_altitude)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
diff = v3Sub(*end, *start);
|
diff = v3Sub(*end, *start);
|
||||||
*start = v3Add(*start, v3Scale(diff, (layer->lower_altitude - start->y) / diff.y));
|
*start = v3Add(*start, v3Scale(diff, (min_altitude - start->y) / diff.y));
|
||||||
if (end->y >= layer->lower_altitude + layer->thickness)
|
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 */
|
else /* start is inside layer */
|
||||||
{
|
{
|
||||||
diff = v3Sub(*end, *start);
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,10 @@ public:
|
||||||
BaseCloudLayerRenderer(SoftwareRenderer* parent);
|
BaseCloudLayerRenderer(SoftwareRenderer* parent);
|
||||||
virtual ~BaseCloudLayerRenderer();
|
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(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location);
|
||||||
virtual Color getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location);
|
virtual bool alterLight(BaseCloudsModel *model, LightDefinition* light, const Vector3 &eye, const Vector3 &location);
|
||||||
virtual bool alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &eye, const Vector3 &location);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SoftwareRenderer* parent;
|
SoftwareRenderer* parent;
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include "NoiseGenerator.h"
|
#include "NoiseGenerator.h"
|
||||||
#include "Curve.h"
|
#include "Curve.h"
|
||||||
#include "AtmosphereRenderer.h"
|
#include "AtmosphereRenderer.h"
|
||||||
|
#include "clouds/BaseCloudsModel.h"
|
||||||
|
#include "SurfaceMaterial.h"
|
||||||
|
|
||||||
typedef struct
|
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 model->getDensity(position);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,8 +41,9 @@ static inline Vector3 _getNormal(CloudLayerDefinition* layer, Vector3 position,
|
||||||
* @param out_segments Allocated space to fill found segments
|
* @param out_segments Allocated space to fill found segments
|
||||||
* @return Number of segments found
|
* @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;
|
int inside, segment_count;
|
||||||
double current_total_length, current_inside_length;
|
double current_total_length, current_inside_length;
|
||||||
double step_length, segment_length, remaining_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 = 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)
|
if (render_precision > max_total_length / 10.0)
|
||||||
{
|
{
|
||||||
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;
|
current_inside_length = 0.0;
|
||||||
segment_length = 0.0;
|
segment_length = 0.0;
|
||||||
walker = start;
|
walker = start;
|
||||||
noise_distance = _getDistanceToBorder(definition, start) * render_precision;
|
noise_distance = _getDistanceToBorder(model, start) * render_precision;
|
||||||
inside = (noise_distance > 0.0) ? 1 : 0;
|
inside = (noise_distance > 0.0) ? 1 : 0;
|
||||||
step = v3Scale(direction, render_precision);
|
step = v3Scale(direction, render_precision);
|
||||||
|
|
||||||
|
@ -136,7 +81,7 @@ static int _findSegments(CloudLayerDefinition* definition, SoftwareRenderer* ren
|
||||||
walker = v3Add(walker, step);
|
walker = v3Add(walker, step);
|
||||||
step_length = v3Norm(step);
|
step_length = v3Norm(step);
|
||||||
last_noise_distance = noise_distance;
|
last_noise_distance = noise_distance;
|
||||||
noise_distance = _getDistanceToBorder(definition, walker) * render_precision;
|
noise_distance = _getDistanceToBorder(model, walker) * render_precision;
|
||||||
current_total_length += step_length;
|
current_total_length += step_length;
|
||||||
|
|
||||||
if (noise_distance > 0.0)
|
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);
|
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;
|
*total_length = current_total_length;
|
||||||
*inside_length = current_inside_length;
|
*inside_length = current_inside_length;
|
||||||
return segment_count;
|
return segment_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Color _applyLayerLighting(CloudLayerDefinition* definition, SoftwareRenderer* renderer, Vector3 position, double)
|
Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
CloudLayerDefinition* layer = model->getLayer();
|
||||||
int i, segment_count;
|
int i, segment_count;
|
||||||
double max_length, detail, total_length, inside_length;
|
double max_length, detail, total_length, inside_length;
|
||||||
Vector3 start, end, direction;
|
Vector3 start, end, direction;
|
||||||
|
@ -236,7 +148,7 @@ Color CloudBasicLayerRenderer::getColor(CloudLayerDefinition* layer, const Vecto
|
||||||
|
|
||||||
start = eye;
|
start = eye;
|
||||||
end = location;
|
end = location;
|
||||||
if (!optimizeSearchLimits(layer, &start, &end))
|
if (!optimizeSearchLimits(model, &start, &end))
|
||||||
{
|
{
|
||||||
return COLOR_TRANSPARENT;
|
return COLOR_TRANSPARENT;
|
||||||
}
|
}
|
||||||
|
@ -246,16 +158,25 @@ Color CloudBasicLayerRenderer::getColor(CloudLayerDefinition* layer, const Vecto
|
||||||
direction = direction.normalize();
|
direction = direction.normalize();
|
||||||
result = COLOR_TRANSPARENT;
|
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--)
|
for (i = segment_count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
col = _applyLayerLighting(layer, parent, segments[i].start, detail);
|
SurfaceMaterial material;
|
||||||
col.a = (segments[i].length >= layer->transparencydepth) ? 1.0 : (segments[i].length / layer->transparencydepth);
|
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);
|
colorMask(&result, &col);
|
||||||
}
|
}
|
||||||
if (inside_length >= layer->transparencydepth)
|
if (inside_length >= transparency_depth)
|
||||||
{
|
{
|
||||||
result.a = 1.0;
|
result.a = 1.0;
|
||||||
}
|
}
|
||||||
|
@ -267,7 +188,7 @@ Color CloudBasicLayerRenderer::getColor(CloudLayerDefinition* layer, const Vecto
|
||||||
return result;
|
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;
|
Vector3 start, end;
|
||||||
double inside_depth, total_depth, factor;
|
double inside_depth, total_depth, factor;
|
||||||
|
@ -275,27 +196,29 @@ bool CloudBasicLayerRenderer::alterLight(CloudLayerDefinition* layer, LightDefin
|
||||||
|
|
||||||
start = location;
|
start = location;
|
||||||
end = location.add(light->direction.scale(10000.0));
|
end = location.add(light->direction.scale(10000.0));
|
||||||
if (not optimizeSearchLimits(layer, &start, &end))
|
if (not optimizeSearchLimits(model, &start, &end))
|
||||||
{
|
{
|
||||||
return false;
|
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;
|
factor = 0.0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
factor = inside_depth / layer->lighttraversal;
|
factor = inside_depth / light_traversal;
|
||||||
if (factor > 1.0)
|
if (factor > 1.0)
|
||||||
{
|
{
|
||||||
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.r *= factor;
|
||||||
light->color.g *= factor;
|
light->color.g *= factor;
|
||||||
|
|
|
@ -10,14 +10,19 @@
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace software {
|
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
|
class SOFTWARESHARED_EXPORT CloudBasicLayerRenderer: public BaseCloudLayerRenderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CloudBasicLayerRenderer(SoftwareRenderer* parent);
|
CloudBasicLayerRenderer(SoftwareRenderer* parent);
|
||||||
|
|
||||||
virtual double getDensity(CloudLayerDefinition* layer, const Vector3 &location) override;
|
virtual Color getColor(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location) override;
|
||||||
virtual Color getColor(CloudLayerDefinition* layer, const Vector3 &eye, const Vector3 &location) override;
|
virtual bool alterLight(BaseCloudsModel *model, LightDefinition* light, const Vector3 &eye, const Vector3 &location) override;
|
||||||
virtual bool alterLight(CloudLayerDefinition* layer, LightDefinition* light, const Vector3 &eye, const Vector3 &location) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,20 @@
|
||||||
#include "SoftwareRenderer.h"
|
#include "SoftwareRenderer.h"
|
||||||
#include "Scenery.h"
|
#include "Scenery.h"
|
||||||
#include "CloudsDefinition.h"
|
#include "CloudsDefinition.h"
|
||||||
|
#include "CloudLayerDefinition.h"
|
||||||
#include "BaseCloudLayerRenderer.h"
|
#include "BaseCloudLayerRenderer.h"
|
||||||
#include "CloudBasicLayerRenderer.h"
|
#include "CloudBasicLayerRenderer.h"
|
||||||
|
|
||||||
|
#include "clouds/BaseCloudsModel.h"
|
||||||
|
#include "clouds/CloudModelStratoCumulus.h"
|
||||||
|
|
||||||
CloudsRenderer::CloudsRenderer(SoftwareRenderer* parent):
|
CloudsRenderer::CloudsRenderer(SoftwareRenderer* parent):
|
||||||
parent(parent)
|
parent(parent)
|
||||||
{
|
{
|
||||||
fake_renderer = new BaseCloudLayerRenderer(parent);
|
fake_renderer = new BaseCloudLayerRenderer(parent);
|
||||||
|
|
||||||
|
CloudLayerDefinition* fake_layer = new CloudLayerDefinition(NULL);
|
||||||
|
fake_model = new BaseCloudsModel(fake_layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
CloudsRenderer::~CloudsRenderer()
|
CloudsRenderer::~CloudsRenderer()
|
||||||
|
@ -19,6 +26,13 @@ CloudsRenderer::~CloudsRenderer()
|
||||||
delete renderer;
|
delete renderer;
|
||||||
}
|
}
|
||||||
delete fake_renderer;
|
delete fake_renderer;
|
||||||
|
|
||||||
|
for (auto model : layer_models)
|
||||||
|
{
|
||||||
|
delete model;
|
||||||
|
}
|
||||||
|
delete fake_model->getLayer();
|
||||||
|
delete fake_model;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloudsRenderer::update()
|
void CloudsRenderer::update()
|
||||||
|
@ -29,11 +43,42 @@ void CloudsRenderer::update()
|
||||||
}
|
}
|
||||||
layer_renderers.clear();
|
layer_renderers.clear();
|
||||||
|
|
||||||
|
for (auto model : layer_models)
|
||||||
|
{
|
||||||
|
delete model;
|
||||||
|
}
|
||||||
|
layer_models.clear();
|
||||||
|
|
||||||
CloudsDefinition* clouds = parent->getScenery()->getClouds();
|
CloudsDefinition* clouds = parent->getScenery()->getClouds();
|
||||||
int n = clouds->count();
|
int n = clouds->count();
|
||||||
for (int i = 0; i < n; i++)
|
for (int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
layer_renderers.push_back(new CloudBasicLayerRenderer(parent));
|
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)
|
Color CloudsRenderer::getColor(const Vector3 &eye, const Vector3 &location, const Color &base)
|
||||||
{
|
{
|
||||||
CloudsDefinition* definition = parent->getScenery()->getClouds();
|
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++)
|
for (int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
CloudLayerDefinition* layer = definition->getCloudLayer(i);
|
|
||||||
BaseCloudLayerRenderer* layer_renderer = getLayerRenderer(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);
|
colorMask(&cumul, &layer_color);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,32 +18,45 @@ public:
|
||||||
virtual ~CloudsRenderer();
|
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();
|
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.
|
* The returned renderer is managed by this object and should not be deleted.
|
||||||
*/
|
*/
|
||||||
virtual BaseCloudLayerRenderer* getLayerRenderer(unsigned int layer);
|
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);
|
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.
|
* Return true if the light was altered.
|
||||||
*/
|
*/
|
||||||
virtual bool alterLight(LightDefinition* light, const Vector3 &eye, const Vector3 &location);
|
virtual bool alterLight(LightDefinition* light, const Vector3 &eye, const Vector3 &location);
|
||||||
private:
|
private:
|
||||||
SoftwareRenderer* parent;
|
SoftwareRenderer* parent;
|
||||||
|
|
||||||
std::vector<BaseCloudLayerRenderer*> layer_renderers;
|
std::vector<BaseCloudLayerRenderer*> layer_renderers;
|
||||||
BaseCloudLayerRenderer* fake_renderer;
|
BaseCloudLayerRenderer* fake_renderer;
|
||||||
|
|
||||||
|
std::vector<BaseCloudsModel*> layer_models;
|
||||||
|
BaseCloudsModel* fake_model;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
49
src/render/software/clouds/BaseCloudsModel.cpp
Normal file
49
src/render/software/clouds/BaseCloudsModel.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
38
src/render/software/clouds/BaseCloudsModel.h
Normal file
38
src/render/software/clouds/BaseCloudsModel.h
Normal file
|
@ -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
|
67
src/render/software/clouds/CloudModelStratoCumulus.cpp
Normal file
67
src/render/software/clouds/CloudModelStratoCumulus.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
29
src/render/software/clouds/CloudModelStratoCumulus.h
Normal file
29
src/render/software/clouds/CloudModelStratoCumulus.h
Normal file
|
@ -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
|
|
@ -20,7 +20,9 @@ SOURCES += SoftwareRenderer.cpp \
|
||||||
CloudsRenderer.cpp \
|
CloudsRenderer.cpp \
|
||||||
BaseCloudLayerRenderer.cpp \
|
BaseCloudLayerRenderer.cpp \
|
||||||
SkyRasterizer.cpp \
|
SkyRasterizer.cpp \
|
||||||
CloudBasicLayerRenderer.cpp
|
CloudBasicLayerRenderer.cpp \
|
||||||
|
clouds/BaseCloudsModel.cpp \
|
||||||
|
clouds/CloudModelStratoCumulus.cpp
|
||||||
|
|
||||||
HEADERS += SoftwareRenderer.h\
|
HEADERS += SoftwareRenderer.h\
|
||||||
software_global.h \
|
software_global.h \
|
||||||
|
@ -30,7 +32,9 @@ HEADERS += SoftwareRenderer.h\
|
||||||
CloudsRenderer.h \
|
CloudsRenderer.h \
|
||||||
BaseCloudLayerRenderer.h \
|
BaseCloudLayerRenderer.h \
|
||||||
SkyRasterizer.h \
|
SkyRasterizer.h \
|
||||||
CloudBasicLayerRenderer.h
|
CloudBasicLayerRenderer.h \
|
||||||
|
clouds/BaseCloudsModel.h \
|
||||||
|
clouds/CloudModelStratoCumulus.h
|
||||||
|
|
||||||
unix:!symbian {
|
unix:!symbian {
|
||||||
maemo5 {
|
maemo5 {
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace software {
|
||||||
|
|
||||||
class CloudsRenderer;
|
class CloudsRenderer;
|
||||||
class BaseCloudLayerRenderer;
|
class BaseCloudLayerRenderer;
|
||||||
|
class BaseCloudsModel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue