Improved clouds lighting
This commit is contained in:
parent
2878f1f157
commit
a54c8d5217
32 changed files with 188 additions and 134 deletions
|
@ -22,3 +22,12 @@ double Maths::smoothstep(double edge0, double edge1, double x) {
|
||||||
x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
|
x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
|
||||||
return x * x * (3.0 - 2.0 * x);
|
return x * x * (3.0 - 2.0 * x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Maths::zeroPoint(double segment_length, double edge0, double edge1) {
|
||||||
|
double diff = edge1 - edge0;
|
||||||
|
if (diff == 0.0) {
|
||||||
|
return 0.0;
|
||||||
|
} else {
|
||||||
|
return -edge0 * segment_length / diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,13 @@ class BASICSSHARED_EXPORT Maths {
|
||||||
*/
|
*/
|
||||||
static double smoothstep(double edge0, double edge1, double x);
|
static double smoothstep(double edge0, double edge1, double x);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the length in a segment (with border values "edge0" and "edge1"), at which the value crosses 0.
|
||||||
|
*
|
||||||
|
* The length is not normalized (the middle of a segment of length 0.2 is 0.1).
|
||||||
|
*/
|
||||||
|
static double zeroPoint(double segment_length, double edge0, double edge1);
|
||||||
|
|
||||||
static constexpr double PI = 3.141592653589793238462643383279;
|
static constexpr double PI = 3.141592653589793238462643383279;
|
||||||
static constexpr double PI_2 = PI / 2.0;
|
static constexpr double PI_2 = PI / 2.0;
|
||||||
static constexpr double PI_4 = PI / 4.0;
|
static constexpr double PI_4 = PI / 4.0;
|
||||||
|
|
|
@ -27,51 +27,15 @@ typedef struct {
|
||||||
double w;
|
double w;
|
||||||
} Grad4;
|
} Grad4;
|
||||||
|
|
||||||
static Grad3 _grad3[] = {{1, 1, 0},
|
static Grad3 _grad3[] = {{1, 1, 0}, {-1, 1, 0}, {1, -1, 0}, {-1, -1, 0}, {1, 0, 1}, {-1, 0, 1},
|
||||||
{-1, 1, 0},
|
{1, 0, -1}, {-1, 0, -1}, {0, 1, 1}, {0, -1, 1}, {0, 1, -1}, {0, -1, -1}};
|
||||||
{1, -1, 0},
|
|
||||||
{-1, -1, 0},
|
|
||||||
{1, 0, 1},
|
|
||||||
{-1, 0, 1},
|
|
||||||
{1, 0, -1},
|
|
||||||
{-1, 0, -1},
|
|
||||||
{0, 1, 1},
|
|
||||||
{0, -1, 1},
|
|
||||||
{0, 1, -1},
|
|
||||||
{0, -1, -1}};
|
|
||||||
|
|
||||||
static Grad4 _grad4[] = {{0, 1, 1, 1},
|
static Grad4 _grad4[] = {
|
||||||
{0, 1, 1, -1},
|
{0, 1, 1, 1}, {0, 1, 1, -1}, {0, 1, -1, 1}, {0, 1, -1, -1}, {0, -1, 1, 1}, {0, -1, 1, -1}, {0, -1, -1, 1},
|
||||||
{0, 1, -1, 1},
|
{0, -1, -1, -1}, {1, 0, 1, 1}, {1, 0, 1, -1}, {1, 0, -1, 1}, {1, 0, -1, -1}, {-1, 0, 1, 1}, {-1, 0, 1, -1},
|
||||||
{0, 1, -1, -1},
|
{-1, 0, -1, 1}, {-1, 0, -1, -1}, {1, 1, 0, 1}, {1, 1, 0, -1}, {1, -1, 0, 1}, {1, -1, 0, -1}, {-1, 1, 0, 1},
|
||||||
{0, -1, 1, 1},
|
{-1, 1, 0, -1}, {-1, -1, 0, 1}, {-1, -1, 0, -1}, {1, 1, 1, 0}, {1, 1, -1, 0}, {1, -1, 1, 0}, {1, -1, -1, 0},
|
||||||
{0, -1, 1, -1},
|
{-1, 1, 1, 0}, {-1, 1, -1, 0}, {-1, -1, 1, 0}, {-1, -1, -1, 0}};
|
||||||
{0, -1, -1, 1},
|
|
||||||
{0, -1, -1, -1},
|
|
||||||
{1, 0, 1, 1},
|
|
||||||
{1, 0, 1, -1},
|
|
||||||
{1, 0, -1, 1},
|
|
||||||
{1, 0, -1, -1},
|
|
||||||
{-1, 0, 1, 1},
|
|
||||||
{-1, 0, 1, -1},
|
|
||||||
{-1, 0, -1, 1},
|
|
||||||
{-1, 0, -1, -1},
|
|
||||||
{1, 1, 0, 1},
|
|
||||||
{1, 1, 0, -1},
|
|
||||||
{1, -1, 0, 1},
|
|
||||||
{1, -1, 0, -1},
|
|
||||||
{-1, 1, 0, 1},
|
|
||||||
{-1, 1, 0, -1},
|
|
||||||
{-1, -1, 0, 1},
|
|
||||||
{-1, -1, 0, -1},
|
|
||||||
{1, 1, 1, 0},
|
|
||||||
{1, 1, -1, 0},
|
|
||||||
{1, -1, 1, 0},
|
|
||||||
{1, -1, -1, 0},
|
|
||||||
{-1, 1, 1, 0},
|
|
||||||
{-1, 1, -1, 0},
|
|
||||||
{-1, -1, 1, 0},
|
|
||||||
{-1, -1, -1, 0}};
|
|
||||||
|
|
||||||
static short _permutations[] = {
|
static short _permutations[] = {
|
||||||
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142,
|
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142,
|
||||||
|
|
|
@ -45,7 +45,8 @@ class DEFINITIONSHARED_EXPORT CloudLayerDefinition : public DefinitionNode {
|
||||||
CUMULONIMBUS,
|
CUMULONIMBUS,
|
||||||
CIRROCUMULUS,
|
CIRROCUMULUS,
|
||||||
CIRROSTRATUS,
|
CIRROSTRATUS,
|
||||||
CIRRUS
|
CIRRUS,
|
||||||
|
_COUNT
|
||||||
} CloudsType;
|
} CloudsType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -10,10 +10,10 @@ SurfaceMaterial::SurfaceMaterial() : SurfaceMaterial(COLOR_BLACK) {
|
||||||
|
|
||||||
SurfaceMaterial::SurfaceMaterial(const Color &color) {
|
SurfaceMaterial::SurfaceMaterial(const Color &color) {
|
||||||
base = new Color(color);
|
base = new Color(color);
|
||||||
|
ambient = 0.0;
|
||||||
hardness = 0.5;
|
hardness = 0.5;
|
||||||
reflection = 0.0;
|
reflection = 0.0;
|
||||||
shininess = 0.0;
|
shininess = 0.0;
|
||||||
receive_shadows = 1.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceMaterial::SurfaceMaterial(const SurfaceMaterial &other) : SurfaceMaterial(COLOR_BLACK) {
|
SurfaceMaterial::SurfaceMaterial(const SurfaceMaterial &other) : SurfaceMaterial(COLOR_BLACK) {
|
||||||
|
@ -38,29 +38,27 @@ void SurfaceMaterial::setColor(double r, double g, double b, double a) {
|
||||||
void SurfaceMaterial::save(PackStream *stream) const {
|
void SurfaceMaterial::save(PackStream *stream) const {
|
||||||
base->save(stream);
|
base->save(stream);
|
||||||
|
|
||||||
|
stream->write(&ambient);
|
||||||
stream->write(&hardness);
|
stream->write(&hardness);
|
||||||
stream->write(&reflection);
|
stream->write(&reflection);
|
||||||
stream->write(&shininess);
|
stream->write(&shininess);
|
||||||
|
|
||||||
stream->write(&receive_shadows);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceMaterial::load(PackStream *stream) {
|
void SurfaceMaterial::load(PackStream *stream) {
|
||||||
base->load(stream);
|
base->load(stream);
|
||||||
|
|
||||||
|
stream->read(&ambient);
|
||||||
stream->read(&hardness);
|
stream->read(&hardness);
|
||||||
stream->read(&reflection);
|
stream->read(&reflection);
|
||||||
stream->read(&shininess);
|
stream->read(&shininess);
|
||||||
|
|
||||||
stream->read(&receive_shadows);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceMaterial::copy(SurfaceMaterial *destination) const {
|
void SurfaceMaterial::copy(SurfaceMaterial *destination) const {
|
||||||
*destination->base = *base;
|
*destination->base = *base;
|
||||||
|
destination->ambient = ambient;
|
||||||
destination->hardness = hardness;
|
destination->hardness = hardness;
|
||||||
destination->reflection = reflection;
|
destination->reflection = reflection;
|
||||||
destination->shininess = shininess;
|
destination->shininess = shininess;
|
||||||
destination->receive_shadows = receive_shadows;
|
|
||||||
destination->validate();
|
destination->validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,10 @@ class DEFINITIONSHARED_EXPORT SurfaceMaterial {
|
||||||
public:
|
public:
|
||||||
Color *base;
|
Color *base;
|
||||||
|
|
||||||
|
double ambient;
|
||||||
double hardness;
|
double hardness;
|
||||||
double reflection;
|
double reflection;
|
||||||
double shininess;
|
double shininess;
|
||||||
|
|
||||||
double receive_shadows;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,8 +127,7 @@ int main(int argc, char **argv) {
|
||||||
scenery->autoPreset();
|
scenery->autoPreset();
|
||||||
}
|
}
|
||||||
|
|
||||||
Logs::debug("CommandLine") << "Rendered scenery :" << endl
|
Logs::debug("CommandLine") << "Rendered scenery :" << endl << scenery->toString() << endl;
|
||||||
<< scenery->toString() << endl;
|
|
||||||
|
|
||||||
TimeManager time;
|
TimeManager time;
|
||||||
time.setWind(conf_wind_x, conf_wind_z);
|
time.setWind(conf_wind_x, conf_wind_z);
|
||||||
|
|
|
@ -152,6 +152,7 @@ static void testCloudQuality() {
|
||||||
|
|
||||||
SoftwareCanvasRenderer renderer(&scenery);
|
SoftwareCanvasRenderer renderer(&scenery);
|
||||||
renderer.setSize(600, 800);
|
renderer.setSize(600, 800);
|
||||||
|
renderer.getGodRaysSampler()->setEnabled(false);
|
||||||
SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0);
|
SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0);
|
||||||
renderer.setSoloRasterizer(&rasterizer);
|
renderer.setSoloRasterizer(&rasterizer);
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
|
@ -463,14 +464,11 @@ static void testCloudsLighting() {
|
||||||
FakeModel(CloudLayerDefinition *layer, double scale) : BaseCloudsModel(layer), scale(scale) {
|
FakeModel(CloudLayerDefinition *layer, double scale) : BaseCloudsModel(layer), scale(scale) {
|
||||||
}
|
}
|
||||||
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override {
|
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override {
|
||||||
*min_altitude = -scale;
|
*min_altitude = 10.0 - scale;
|
||||||
*max_altitude = scale;
|
*max_altitude = 10.0 + scale;
|
||||||
}
|
}
|
||||||
virtual void getDetailRange(double *min_step, double *max_step) const override {
|
virtual double getDensity(const Vector3 &location, double) const override {
|
||||||
*min_step = *max_step = scale * 0.01;
|
return 1.0 - location.sub(Vector3(0.0, 10.0, 0.0)).getNorm() / scale;
|
||||||
}
|
|
||||||
virtual double getDensity(const Vector3 &location) const override {
|
|
||||||
return Maths::smoothstep(0.0, 0.2, 1.0 - location.getNorm() / scale);
|
|
||||||
}
|
}
|
||||||
double scale;
|
double scale;
|
||||||
};
|
};
|
||||||
|
@ -482,8 +480,8 @@ static void testCloudsLighting() {
|
||||||
virtual Color processPixel(int, int, double relx, double rely) const override {
|
virtual Color processPixel(int, int, double relx, double rely) const override {
|
||||||
auto cloud_renderer = renderer->getCloudsRenderer();
|
auto cloud_renderer = renderer->getCloudsRenderer();
|
||||||
auto atmo_renderer = renderer->getAtmosphereRenderer();
|
auto atmo_renderer = renderer->getAtmosphereRenderer();
|
||||||
return cloud_renderer->getColor(Vector3(relx * scale * 1.2, rely * scale * 1.2, scale),
|
return cloud_renderer->getColor(Vector3(relx * scale * 1.2, 10.0 + rely * scale * 1.2, scale),
|
||||||
Vector3(relx * scale * 1.2, rely * scale * 1.2, -scale),
|
Vector3(relx * scale * 1.2, 10.0 + rely * scale * 1.2, -scale),
|
||||||
atmo_renderer->getSkyColor(Vector3(relx, rely, 1.0).normalize()).final);
|
atmo_renderer->getSkyColor(Vector3(relx, rely, 1.0).normalize()).final);
|
||||||
}
|
}
|
||||||
virtual int prepareRasterization() override {
|
virtual int prepareRasterization() override {
|
||||||
|
@ -500,15 +498,16 @@ static void testCloudsLighting() {
|
||||||
|
|
||||||
Scenery scenery;
|
Scenery scenery;
|
||||||
scenery.autoPreset(1);
|
scenery.autoPreset(1);
|
||||||
|
scenery.getTerrain()->propHeightNoise()->setConfig(0.0);
|
||||||
scenery.getCamera()->setTarget(VECTOR_ZERO);
|
scenery.getCamera()->setTarget(VECTOR_ZERO);
|
||||||
scenery.getCamera()->setLocation(Vector3(0.0, 0.0, 5.0));
|
scenery.getCamera()->setLocation(Vector3(0.0, 10.0, 11.0));
|
||||||
|
|
||||||
CloudLayerDefinition layer(NULL, "test");
|
CloudLayerDefinition layer(NULL, "test");
|
||||||
scenery.getClouds()->clear();
|
scenery.getClouds()->clear();
|
||||||
scenery.getClouds()->addLayer(layer);
|
scenery.getClouds()->addLayer(layer);
|
||||||
|
|
||||||
SoftwareCanvasRenderer renderer(&scenery);
|
SoftwareCanvasRenderer renderer(&scenery);
|
||||||
FakeRasterizer rasterizer(&renderer, 10.0);
|
FakeRasterizer rasterizer(&renderer, 5.0);
|
||||||
renderer.setSize(800, 800);
|
renderer.setSize(800, 800);
|
||||||
renderer.setSoloRasterizer(&rasterizer);
|
renderer.setSoloRasterizer(&rasterizer);
|
||||||
renderer.getGodRaysSampler()->setEnabled(false);
|
renderer.getGodRaysSampler()->setEnabled(false);
|
||||||
|
@ -522,6 +521,36 @@ static void testCloudsLighting() {
|
||||||
startTestRender(&renderer, "clouds_lighting_night");
|
startTestRender(&renderer, "clouds_lighting_night");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void testCloudModels() {
|
||||||
|
Scenery scenery;
|
||||||
|
scenery.autoPreset(1);
|
||||||
|
scenery.getTerrain()->propHeightNoise()->setConfig(0.0);
|
||||||
|
|
||||||
|
CloudLayerDefinition layer(NULL, "test");
|
||||||
|
layer.altitude = 1.0;
|
||||||
|
scenery.getClouds()->clear();
|
||||||
|
scenery.getClouds()->addLayer(layer);
|
||||||
|
|
||||||
|
SoftwareCanvasRenderer renderer(&scenery);
|
||||||
|
renderer.setSize(800, 600);
|
||||||
|
renderer.getGodRaysSampler()->setEnabled(false);
|
||||||
|
|
||||||
|
for (int i = CloudLayerDefinition::STRATOCUMULUS; i < CloudLayerDefinition::_COUNT; i++) {
|
||||||
|
// FIXME Test all
|
||||||
|
layer.type = static_cast<CloudLayerDefinition::CloudsType>(i);
|
||||||
|
layer.validate();
|
||||||
|
renderer.getCloudsRenderer()->update();
|
||||||
|
auto model = renderer.getCloudsRenderer()->getLayerModel(0);
|
||||||
|
double minalt, maxalt;
|
||||||
|
model->getAltitudeRange(&minalt, &maxalt);
|
||||||
|
double offset = 8.0;
|
||||||
|
scenery.getCamera()->setLocation(Vector3(0.0, minalt - offset, 0.0));
|
||||||
|
scenery.getCamera()->setTarget(Vector3(0.0, minalt, offset));
|
||||||
|
|
||||||
|
startTestRender(&renderer, "clouds_model", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void runTestSuite() {
|
void runTestSuite() {
|
||||||
testNoise();
|
testNoise();
|
||||||
testTextures();
|
testTextures();
|
||||||
|
|
|
@ -141,8 +141,7 @@ void MainModelerWindow::keyReleaseEvent(QKeyEvent *event) {
|
||||||
} else if (event->key() == Qt::Key_F6) {
|
} else if (event->key() == Qt::Key_F6) {
|
||||||
render_process->showPreviousRender();
|
render_process->showPreviousRender();
|
||||||
} else if (event->key() == Qt::Key_F12) {
|
} else if (event->key() == Qt::Key_F12) {
|
||||||
Logs::warning("UI") << "Current scenery dump:" << endl
|
Logs::warning("UI") << "Current scenery dump:" << endl << scenery->toString() << endl;
|
||||||
<< scenery->toString() << endl;
|
|
||||||
} else if (event->key() == Qt::Key_N) {
|
} else if (event->key() == Qt::Key_N) {
|
||||||
if (event->modifiers() & Qt::ControlModifier) {
|
if (event->modifiers() & Qt::ControlModifier) {
|
||||||
newFile();
|
newFile();
|
||||||
|
|
|
@ -19,7 +19,7 @@ class OpenGLView : public QQuickItem {
|
||||||
void handleResize();
|
void handleResize();
|
||||||
void handleSceneGraphReady();
|
void handleSceneGraphReady();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void stopped();
|
void stopped();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -8,7 +8,7 @@ class PropertyBind : public QObject {
|
||||||
public:
|
public:
|
||||||
explicit PropertyBind(QObject *parent = 0);
|
explicit PropertyBind(QObject *parent = 0);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
};
|
};
|
||||||
|
|
|
@ -128,11 +128,11 @@ void RenderProcess::startQuickRender() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderProcess::startMediumRender() {
|
void RenderProcess::startMediumRender() {
|
||||||
startRender(window->getScenery(), RenderConfig(800, 450, 1, 5));
|
startRender(window->getScenery(), RenderConfig(800, 450, 1, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderProcess::startFinalRender() {
|
void RenderProcess::startFinalRender() {
|
||||||
startRender(window->getScenery(), RenderConfig(1920, 1080, 4, 8));
|
startRender(window->getScenery(), RenderConfig(1920, 1080, 4, 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderProcess::showPreviousRender() {
|
void RenderProcess::showPreviousRender() {
|
||||||
|
|
|
@ -253,7 +253,7 @@ void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) {
|
||||||
projection.perspective(perspective.yfov * 180.0 / Maths::PI, perspective.xratio, perspective.znear,
|
projection.perspective(perspective.yfov * 180.0 / Maths::PI, perspective.xratio, perspective.znear,
|
||||||
perspective.zfar);
|
perspective.zfar);
|
||||||
|
|
||||||
*view_matrix = projection *transform;
|
*view_matrix = projection * transform;
|
||||||
|
|
||||||
// Set in shaders
|
// Set in shaders
|
||||||
shared_state->set("cameraLocation", location);
|
shared_state->set("cameraLocation", location);
|
||||||
|
|
|
@ -266,8 +266,8 @@ static Color _transmittance3(double r, double mu, double d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _getIrradianceRMuS(double x, double y, double *r, double *muS) {
|
static void _getIrradianceRMuS(double x, double y, double *r, double *muS) {
|
||||||
*r = Rg + y *(Rt - Rg);
|
*r = Rg + y * (Rt - Rg);
|
||||||
*muS = -0.2 + x *(1.0 + 0.2);
|
*muS = -0.2 + x * (1.0 + 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* nearest intersection of ray r,mu with ground or top atmosphere boundary
|
/* nearest intersection of ray r,mu with ground or top atmosphere boundary
|
||||||
|
|
|
@ -117,8 +117,7 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::applyAerialPerspective(cons
|
||||||
case AtmosphereDefinition::ATMOSPHERE_MODEL_BRUNETON:
|
case AtmosphereDefinition::ATMOSPHERE_MODEL_BRUNETON:
|
||||||
result = model->applyAerialPerspective(location, base);
|
result = model->applyAerialPerspective(location, base);
|
||||||
break;
|
break;
|
||||||
default:
|
default:;
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply god rays ponderation
|
// Apply god rays ponderation
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "clouds/BaseCloudsModel.h"
|
#include "clouds/BaseCloudsModel.h"
|
||||||
#include "SurfaceMaterial.h"
|
#include "SurfaceMaterial.h"
|
||||||
#include "Logs.h"
|
#include "Logs.h"
|
||||||
|
#include "Maths.h"
|
||||||
#include "FloatNode.h"
|
#include "FloatNode.h"
|
||||||
|
|
||||||
struct CloudSegment {
|
struct CloudSegment {
|
||||||
|
@ -24,10 +25,6 @@ struct CloudSegment {
|
||||||
CloudBasicLayerRenderer::CloudBasicLayerRenderer(SoftwareRenderer *parent) : BaseCloudLayerRenderer(parent) {
|
CloudBasicLayerRenderer::CloudBasicLayerRenderer(SoftwareRenderer *parent) : BaseCloudLayerRenderer(parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline double _getDistanceToBorder(BaseCloudsModel *model, const Vector3 &position) {
|
|
||||||
return model->getDensity(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go through the cloud layer to find segments (parts of the lookup that are inside the cloud).
|
* Go through the cloud layer to find segments (parts of the lookup that are inside the cloud).
|
||||||
*
|
*
|
||||||
|
@ -47,13 +44,14 @@ static inline double _getDistanceToBorder(BaseCloudsModel *model, const Vector3
|
||||||
*/
|
*/
|
||||||
int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 &start, const Vector3 &direction,
|
int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 &start, const Vector3 &direction,
|
||||||
int max_segments, double max_inside_length, double max_total_length,
|
int max_segments, double max_inside_length, double max_total_length,
|
||||||
double *inside_length, double *total_length, CloudSegment *out_segments) {
|
double *inside_length, double *total_length, CloudSegment *out_segments,
|
||||||
|
double base_detail) {
|
||||||
double ymin, ymax;
|
double ymin, ymax;
|
||||||
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;
|
double step_length, segment_length;
|
||||||
double min_step, max_step;
|
double min_step, max_step;
|
||||||
double noise_distance;
|
double noise_distance, previous_noise_distance;
|
||||||
Vector3 walker, step, segment_start, offset;
|
Vector3 walker, step, segment_start, offset;
|
||||||
double render_precision;
|
double render_precision;
|
||||||
|
|
||||||
|
@ -68,20 +66,30 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
||||||
double distance = parent->getCameraLocation().sub(start).getNorm();
|
double distance = parent->getCameraLocation().sub(start).getNorm();
|
||||||
render_precision = min_step + (max_step - min_step) * min(distance / (quality + 0.1), 100.0) * 0.01;
|
render_precision = min_step + (max_step - min_step) * min(distance / (quality + 0.1), 100.0) * 0.01;
|
||||||
|
|
||||||
|
/*double verticality = fabs(direction.y);
|
||||||
|
if (verticality > 0.5) {
|
||||||
|
render_precision *= 1.0 - 1.8 * (verticality - 0.5);
|
||||||
|
}*/
|
||||||
|
|
||||||
segment_count = 0;
|
segment_count = 0;
|
||||||
current_total_length = 0.0;
|
current_total_length = 0.0;
|
||||||
current_inside_length = 0.0;
|
current_inside_length = 0.0;
|
||||||
segment_length = 0.0;
|
segment_length = 0.0;
|
||||||
walker = start;
|
walker = start;
|
||||||
offset = Vector3(model->getLayer()->propXOffset()->getValue(), 0.0, model->getLayer()->propZOffset()->getValue());
|
offset = Vector3(model->getLayer()->propXOffset()->getValue(), 0.0, model->getLayer()->propZOffset()->getValue());
|
||||||
noise_distance = _getDistanceToBorder(model, start.add(offset)) * render_precision;
|
noise_distance = model->getDensity(start.add(offset), base_detail);
|
||||||
inside = 0;
|
previous_noise_distance = noise_distance;
|
||||||
|
inside = noise_distance > 0.0;
|
||||||
|
if (inside) {
|
||||||
|
segment_start = start;
|
||||||
|
}
|
||||||
step = direction.scale(render_precision);
|
step = direction.scale(render_precision);
|
||||||
|
bool stop = false;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
walker = walker.add(step);
|
walker = walker.add(step);
|
||||||
step_length = step.getNorm();
|
step_length = step.getNorm();
|
||||||
noise_distance = _getDistanceToBorder(model, walker.add(offset)) * render_precision;
|
noise_distance = stop ? 0.0 : model->getDensity(walker.add(offset), base_detail);
|
||||||
current_total_length += step_length;
|
current_total_length += step_length;
|
||||||
|
|
||||||
if (noise_distance > 0.0) {
|
if (noise_distance > 0.0) {
|
||||||
|
@ -89,23 +97,26 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
||||||
// inside the cloud
|
// inside the cloud
|
||||||
segment_length += step_length;
|
segment_length += step_length;
|
||||||
current_inside_length += step_length;
|
current_inside_length += step_length;
|
||||||
step = direction.scale((noise_distance < render_precision) ? render_precision : noise_distance);
|
step = direction.scale((noise_distance < 1.0) ? render_precision : (noise_distance * render_precision));
|
||||||
} else {
|
} else {
|
||||||
// entering the cloud
|
// entering the cloud
|
||||||
inside = 1;
|
inside = 1;
|
||||||
segment_length = 0.0;
|
segment_length = step_length - Maths::zeroPoint(step_length, previous_noise_distance, noise_distance);
|
||||||
segment_start = walker;
|
assert(segment_length >= 0.0 && segment_length <= step_length);
|
||||||
|
segment_start = walker.add(direction.scale(-segment_length));
|
||||||
current_inside_length += segment_length;
|
current_inside_length += segment_length;
|
||||||
step = direction.scale(render_precision);
|
step = direction.scale(render_precision);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (inside) {
|
if (inside) {
|
||||||
// exiting the cloud
|
// exiting the cloud
|
||||||
segment_length += step_length;
|
double exit_length = Maths::zeroPoint(step_length, previous_noise_distance, noise_distance);
|
||||||
current_inside_length += step_length;
|
assert(exit_length >= 0.0);
|
||||||
|
segment_length += exit_length;
|
||||||
|
current_inside_length += exit_length;
|
||||||
|
|
||||||
out_segments->start = segment_start;
|
out_segments->start = segment_start;
|
||||||
out_segments->end = walker;
|
out_segments->end = walker.add(direction.scale(exit_length - step_length));
|
||||||
out_segments->length = segment_length;
|
out_segments->length = segment_length;
|
||||||
out_segments++;
|
out_segments++;
|
||||||
if (++segment_count >= max_segments) {
|
if (++segment_count >= max_segments) {
|
||||||
|
@ -116,19 +127,30 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
||||||
step = direction.scale(render_precision);
|
step = direction.scale(render_precision);
|
||||||
} else {
|
} else {
|
||||||
// searching for a cloud
|
// searching for a cloud
|
||||||
step = direction.scale((noise_distance > -render_precision) ? render_precision : -noise_distance);
|
step =
|
||||||
|
direction.scale((noise_distance > -1.0) ? render_precision : (-noise_distance * render_precision));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_precision *= 1.0 + 0.001 / (quality + 0.1);
|
render_precision *= 1.0 + 0.001 / (quality + 0.1);
|
||||||
} while (inside || (walker.y >= ymin - 0.001 && walker.y <= ymax + 0.001 &&
|
previous_noise_distance = noise_distance;
|
||||||
current_total_length < max_total_length && current_inside_length < max_inside_length));
|
stop = not(walker.y >= ymin - 0.001 && walker.y <= ymax + 0.001 && current_total_length < max_total_length &&
|
||||||
|
current_inside_length < max_inside_length);
|
||||||
|
} while (inside or not stop);
|
||||||
|
|
||||||
*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 inline Vector3 _getPseudoNormal(const BaseCloudsModel *model, const Vector3 &base, const Vector3 &direction) {
|
||||||
|
double precision = 0.3;
|
||||||
|
double base_density = model->getDensity(base, precision); // TODO keep
|
||||||
|
double density = model->getDensity(base.add(direction.scale(precision * 10.0)), precision);
|
||||||
|
double diff = base_density - density;
|
||||||
|
return direction.scale(diff > 0.0 ? diff : 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location) {
|
Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &eye, const Vector3 &location) {
|
||||||
int i, segment_count;
|
int i, segment_count;
|
||||||
double max_length, total_length, inside_length;
|
double max_length, total_length, inside_length;
|
||||||
|
@ -151,27 +173,32 @@ Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &e
|
||||||
model->getAltitudeRange(&ymin, &ymax);
|
model->getAltitudeRange(&ymin, &ymax);
|
||||||
double transparency_depth = (ymax - ymin);
|
double transparency_depth = (ymax - ymin);
|
||||||
|
|
||||||
SurfaceMaterial material(COLOR_WHITE.scaled(5.0));
|
SurfaceMaterial material(COLOR_WHITE.scaled(8.0));
|
||||||
material.hardness = 1.0;
|
material.ambient = 0.8;
|
||||||
material.reflection = 0.0;
|
material.hardness = 0.0;
|
||||||
material.shininess = 0.0;
|
material.reflection = 0.2;
|
||||||
|
material.shininess = 3.0;
|
||||||
material.validate();
|
material.validate();
|
||||||
|
|
||||||
segment_count = findSegments(model, start, direction, 30, transparency_depth, max_length, &inside_length,
|
segment_count = findSegments(model, start, direction, 30, transparency_depth, max_length, &inside_length,
|
||||||
&total_length, segments);
|
&total_length, segments, 0.001);
|
||||||
for (i = segment_count - 1; i >= 0; i--) {
|
for (i = segment_count - 1; i >= 0; i--) {
|
||||||
col = parent->applyLightingToSurface(segments[i].start, VECTOR_UP, material);
|
Vector3 normal = VECTOR_ZERO;
|
||||||
|
const Vector3 &location = segments[i].start;
|
||||||
|
normal = normal.add(_getPseudoNormal(model, location, VECTOR_UP));
|
||||||
|
normal = normal.add(_getPseudoNormal(model, location, VECTOR_DOWN));
|
||||||
|
normal = normal.add(_getPseudoNormal(model, location, VECTOR_EAST));
|
||||||
|
normal = normal.add(_getPseudoNormal(model, location, VECTOR_WEST));
|
||||||
|
normal = normal.add(_getPseudoNormal(model, location, VECTOR_NORTH));
|
||||||
|
normal = normal.add(_getPseudoNormal(model, location, VECTOR_SOUTH));
|
||||||
|
col = parent->applyLightingToSurface(location, normal.normalize(), material);
|
||||||
|
|
||||||
col.a = (segments[i].length >= transparency_depth) ? 1.0 : (segments[i].length / transparency_depth);
|
col.a = (segments[i].length >= transparency_depth) ? 1.0 : (segments[i].length / transparency_depth);
|
||||||
result.mask(col);
|
result.mask(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opacify when hitting inside_length limit
|
// Opacity
|
||||||
if (inside_length >= transparency_depth) {
|
result.a = Maths::smoothstep(0.0, transparency_depth, inside_length);
|
||||||
result.a = 1.0;
|
|
||||||
} else if (inside_length >= transparency_depth * 0.8) {
|
|
||||||
result.a += (1.0 - result.a) * ((inside_length - transparency_depth * 0.8) / (transparency_depth * 0.2));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply aerial perspective
|
// Apply aerial perspective
|
||||||
if (result.a > 0.00001) {
|
if (result.a > 0.00001) {
|
||||||
|
@ -196,14 +223,14 @@ bool CloudBasicLayerRenderer::alterLight(BaseCloudsModel *model, LightComponent
|
||||||
direction = light->direction.scale(-1.0);
|
direction = light->direction.scale(-1.0);
|
||||||
end = location.add(direction.scale(10000.0));
|
end = location.add(direction.scale(10000.0));
|
||||||
if (not optimizeSearchLimits(model, &start, &end)) {
|
if (not optimizeSearchLimits(model, &start, &end)) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double ymin, ymax;
|
double ymin, ymax;
|
||||||
model->getAltitudeRange(&ymin, &ymax);
|
model->getAltitudeRange(&ymin, &ymax);
|
||||||
double light_traversal = (ymax - ymin) * 0.8 * light->color.getPower();
|
double light_traversal = (ymax - ymin) * 0.8 * light->color.getPower();
|
||||||
findSegments(model, start, direction, 30, light_traversal, end.sub(start).getNorm(), &inside_depth, &total_depth,
|
findSegments(model, start, direction, 30, light_traversal, end.sub(start).getNorm(), &inside_depth, &total_depth,
|
||||||
segments);
|
segments, 0.1);
|
||||||
|
|
||||||
if (light_traversal < 0.0001) {
|
if (light_traversal < 0.0001) {
|
||||||
factor = 0.0;
|
factor = 0.0;
|
||||||
|
|
|
@ -27,7 +27,7 @@ class SOFTWARESHARED_EXPORT CloudBasicLayerRenderer : public BaseCloudLayerRende
|
||||||
private:
|
private:
|
||||||
int findSegments(BaseCloudsModel *model, const Vector3 &start, const Vector3 &direction, int max_segments,
|
int findSegments(BaseCloudsModel *model, const Vector3 &start, const Vector3 &direction, int max_segments,
|
||||||
double max_inside_length, double max_total_length, double *inside_length, double *total_length,
|
double max_inside_length, double max_total_length, double *inside_length, double *total_length,
|
||||||
CloudSegment *out_segments);
|
CloudSegment *out_segments, double base_detail);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ void CloudsRenderer::update() {
|
||||||
case CloudLayerDefinition::ALTOSTRATUS:
|
case CloudLayerDefinition::ALTOSTRATUS:
|
||||||
case CloudLayerDefinition::CIRROCUMULUS:
|
case CloudLayerDefinition::CIRROCUMULUS:
|
||||||
case CloudLayerDefinition::CIRROSTRATUS:
|
case CloudLayerDefinition::CIRROSTRATUS:
|
||||||
|
case CloudLayerDefinition::_COUNT:
|
||||||
model = new BaseCloudsModel(layer);
|
model = new BaseCloudsModel(layer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,9 +119,14 @@ double GodRaysSampler::getCachedLight(const Vector3 &location) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hit cache
|
// Hit cache
|
||||||
double p[8] = {getCache(ix, iy, iz), getCache(ix + 1, iy, iz), getCache(ix + 1, iy + 1, iz),
|
double p[8] = {getCache(ix, iy, iz),
|
||||||
getCache(ix, iy + 1, iz), getCache(ix, iy, iz + 1), getCache(ix + 1, iy, iz + 1),
|
getCache(ix + 1, iy, iz),
|
||||||
getCache(ix + 1, iy + 1, iz + 1), getCache(ix, iy + 1, iz + 1)};
|
getCache(ix + 1, iy + 1, iz),
|
||||||
|
getCache(ix, iy + 1, iz),
|
||||||
|
getCache(ix, iy, iz + 1),
|
||||||
|
getCache(ix + 1, iy, iz + 1),
|
||||||
|
getCache(ix + 1, iy + 1, iz + 1),
|
||||||
|
getCache(ix, iy + 1, iz + 1)};
|
||||||
return Interpolation::trilinear(p, (x - sampling_step * double(ix)) / sampling_step,
|
return Interpolation::trilinear(p, (x - sampling_step * double(ix)) / sampling_step,
|
||||||
(y - sampling_step * double(iy)) / sampling_step,
|
(y - sampling_step * double(iy)) / sampling_step,
|
||||||
(z - sampling_step * double(iz)) / sampling_step);
|
(z - sampling_step * double(iz)) / sampling_step);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "LightSource.h"
|
#include "LightSource.h"
|
||||||
#include "Color.h"
|
#include "Color.h"
|
||||||
#include "SurfaceMaterial.h"
|
#include "SurfaceMaterial.h"
|
||||||
|
#include "Logs.h"
|
||||||
|
|
||||||
LightingManager::LightingManager() {
|
LightingManager::LightingManager() {
|
||||||
specularity = true;
|
specularity = true;
|
||||||
|
@ -92,21 +93,16 @@ void LightingManager::setFiltering(bool enabled) {
|
||||||
Color LightingManager::applyFinalComponent(const LightComponent &component, const Vector3 &eye, const Vector3 &location,
|
Color LightingManager::applyFinalComponent(const LightComponent &component, const Vector3 &eye, const Vector3 &location,
|
||||||
const Vector3 &normal, const SurfaceMaterial &material) {
|
const Vector3 &normal, const SurfaceMaterial &material) {
|
||||||
Color result, light_color;
|
Color result, light_color;
|
||||||
double normal_norm;
|
|
||||||
Vector3 direction_inv;
|
Vector3 direction_inv;
|
||||||
|
|
||||||
light_color = component.color;
|
light_color = component.color;
|
||||||
direction_inv = component.direction.normalize().scale(-1.0);
|
direction_inv = component.direction.normalize().scale(-1.0);
|
||||||
|
normal.normalize();
|
||||||
normal_norm = normal.getNorm();
|
|
||||||
if (normal_norm > 1.0) {
|
|
||||||
normal_norm = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = COLOR_BLACK;
|
result = COLOR_BLACK;
|
||||||
|
|
||||||
/* diffused light */
|
/* diffused light */
|
||||||
double diffuse = direction_inv.dotProduct(normal.normalize());
|
double diffuse = direction_inv.dotProduct(normal);
|
||||||
double sign = (diffuse < 0.0) ? -1.0 : 1.0;
|
double sign = (diffuse < 0.0) ? -1.0 : 1.0;
|
||||||
if (material.hardness <= 0.5) {
|
if (material.hardness <= 0.5) {
|
||||||
double hardness = material.hardness * 2.0;
|
double hardness = material.hardness * 2.0;
|
||||||
|
@ -115,7 +111,9 @@ Color LightingManager::applyFinalComponent(const LightComponent &component, cons
|
||||||
double hardness = (material.hardness - 0.5) * 2.0;
|
double hardness = (material.hardness - 0.5) * 2.0;
|
||||||
diffuse = (1.0 - hardness) * diffuse + hardness * sign * sqrt(fabs(diffuse));
|
diffuse = (1.0 - hardness) * diffuse + hardness * sign * sqrt(fabs(diffuse));
|
||||||
}
|
}
|
||||||
diffuse = (diffuse + (1.0 - normal_norm)) / (1.0 + (1.0 - normal_norm));
|
if (material.ambient > 0.0) {
|
||||||
|
diffuse = material.ambient + (1.0 - material.ambient) * diffuse;
|
||||||
|
}
|
||||||
if (diffuse > 0.0) {
|
if (diffuse > 0.0) {
|
||||||
result.r += diffuse * material.base->r * light_color.r;
|
result.r += diffuse * material.base->r * light_color.r;
|
||||||
result.g += diffuse * material.base->g * light_color.g;
|
result.g += diffuse * material.base->g * light_color.g;
|
||||||
|
@ -123,12 +121,12 @@ Color LightingManager::applyFinalComponent(const LightComponent &component, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
/* specular reflection */
|
/* specular reflection */
|
||||||
if (material.shininess > 0.0 && material.reflection > 0.0 && component.reflection > 0.0) {
|
if (sign > 0.0 && material.shininess > 0.0 && material.reflection > 0.0 && component.reflection > 0.0) {
|
||||||
Vector3 view = location.sub(eye).normalize();
|
Vector3 view = location.sub(eye).normalize();
|
||||||
Vector3 reflect = direction_inv.sub(normal.scale(2.0 * direction_inv.dotProduct(normal)));
|
Vector3 reflect = direction_inv.sub(normal.scale(2.0 * direction_inv.dotProduct(normal)));
|
||||||
double specular = reflect.dotProduct(view);
|
double specular = reflect.dotProduct(view);
|
||||||
if (specular > 0.0) {
|
if (specular > 0.0) {
|
||||||
specular = pow(specular, material.shininess) * material.reflection * component.reflection * normal_norm;
|
specular = pow(specular, material.shininess) * material.reflection * component.reflection;
|
||||||
if (specular > 0.0) {
|
if (specular > 0.0) {
|
||||||
result.r += specular * light_color.r;
|
result.r += specular * light_color.r;
|
||||||
result.g += specular * light_color.g;
|
result.g += specular * light_color.g;
|
||||||
|
|
|
@ -33,6 +33,7 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery) : SoftwareRende
|
||||||
new VegetationRasterizer(this, progress, RASTERIZER_CLIENT_VEGETATION));
|
new VegetationRasterizer(this, progress, RASTERIZER_CLIENT_VEGETATION));
|
||||||
|
|
||||||
current_work = NULL;
|
current_work = NULL;
|
||||||
|
setQuality(0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
SoftwareCanvasRenderer::~SoftwareCanvasRenderer() {
|
SoftwareCanvasRenderer::~SoftwareCanvasRenderer() {
|
||||||
|
|
|
@ -29,7 +29,7 @@ double BaseCloudsModel::getProbability(const Vector3 &, double) const {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double BaseCloudsModel::getDensity(const Vector3 &) const {
|
double BaseCloudsModel::getDensity(const Vector3 &, double) const {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ class SOFTWARESHARED_EXPORT BaseCloudsModel {
|
||||||
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const;
|
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const;
|
||||||
virtual void getDetailRange(double *min_step, double *max_step) const;
|
virtual void getDetailRange(double *min_step, double *max_step) const;
|
||||||
virtual double getProbability(const Vector3 &location, double radius) const;
|
virtual double getProbability(const Vector3 &location, double radius) const;
|
||||||
virtual double getDensity(const Vector3 &location) const;
|
virtual double getDensity(const Vector3 &location, double precision) const;
|
||||||
virtual Color filterLight(const Color &light, double length, double density) const;
|
virtual Color filterLight(const Color &light, double length, double density) const;
|
||||||
virtual Color applyLightExit(const Color &light, const Vector3 &light_direction,
|
virtual Color applyLightExit(const Color &light, const Vector3 &light_direction,
|
||||||
const Vector3 &direction_to_eye) const;
|
const Vector3 &direction_to_eye) const;
|
||||||
|
|
|
@ -32,7 +32,7 @@ void CloudModelAltoCumulus::getAltitudeRange(double *min_altitude, double *max_a
|
||||||
*max_altitude = *min_altitude + 18.0 * layer->scaling;
|
*max_altitude = *min_altitude + 18.0 * layer->scaling;
|
||||||
}
|
}
|
||||||
|
|
||||||
double CloudModelAltoCumulus::getDensity(const Vector3 &location) const {
|
double CloudModelAltoCumulus::getDensity(const Vector3 &location, double) const {
|
||||||
double val;
|
double val;
|
||||||
double min_altitude, max_altitude;
|
double min_altitude, max_altitude;
|
||||||
double noise_scaling = 18.0 * layer->scaling;
|
double noise_scaling = 18.0 * layer->scaling;
|
||||||
|
|
|
@ -16,7 +16,7 @@ class CloudModelAltoCumulus : public BaseCloudsModel {
|
||||||
virtual void update() override;
|
virtual void update() override;
|
||||||
|
|
||||||
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
|
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
|
||||||
virtual double getDensity(const Vector3 &location) const override;
|
virtual double getDensity(const Vector3 &location, double precision) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NoiseGenerator *noise;
|
NoiseGenerator *noise;
|
||||||
|
|
|
@ -30,7 +30,7 @@ void CloudModelCirrus::getAltitudeRange(double *min_altitude, double *max_altitu
|
||||||
*max_altitude = *min_altitude + 20.0 * layer->scaling;
|
*max_altitude = *min_altitude + 20.0 * layer->scaling;
|
||||||
}
|
}
|
||||||
|
|
||||||
double CloudModelCirrus::getDensity(const Vector3 &location) const {
|
double CloudModelCirrus::getDensity(const Vector3 &location, double) const {
|
||||||
double val;
|
double val;
|
||||||
double min_altitude, max_altitude;
|
double min_altitude, max_altitude;
|
||||||
double noise_scaling = 30.0 * layer->scaling;
|
double noise_scaling = 30.0 * layer->scaling;
|
||||||
|
|
|
@ -16,7 +16,7 @@ class CloudModelCirrus : public BaseCloudsModel {
|
||||||
virtual void update() override;
|
virtual void update() override;
|
||||||
|
|
||||||
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
|
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
|
||||||
virtual double getDensity(const Vector3 &location) const override;
|
virtual double getDensity(const Vector3 &location, double precision) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NoiseGenerator *noise;
|
NoiseGenerator *noise;
|
||||||
|
|
|
@ -37,7 +37,7 @@ void CloudModelCumuloNimbus::getAltitudeRange(double *min_altitude, double *max_
|
||||||
*max_altitude = *min_altitude + 50.0 + 50.0 * layer->scaling;
|
*max_altitude = *min_altitude + 50.0 + 50.0 * layer->scaling;
|
||||||
}
|
}
|
||||||
|
|
||||||
double CloudModelCumuloNimbus::getDensity(const Vector3 &location) const {
|
double CloudModelCumuloNimbus::getDensity(const Vector3 &location, double) const {
|
||||||
double val;
|
double val;
|
||||||
double min_altitude, max_altitude;
|
double min_altitude, max_altitude;
|
||||||
double noise_scaling = 60.0 * layer->scaling;
|
double noise_scaling = 60.0 * layer->scaling;
|
||||||
|
|
|
@ -16,7 +16,7 @@ class CloudModelCumuloNimbus : public BaseCloudsModel {
|
||||||
virtual void update() override;
|
virtual void update() override;
|
||||||
|
|
||||||
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
|
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
|
||||||
virtual double getDensity(const Vector3 &location) const override;
|
virtual double getDensity(const Vector3 &location, double precision) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NoiseGenerator *noise;
|
NoiseGenerator *noise;
|
||||||
|
|
|
@ -37,7 +37,7 @@ void CloudModelStratoCumulus::getAltitudeRange(double *min_altitude, double *max
|
||||||
*max_altitude = *min_altitude + 11.0 * layer->scaling;
|
*max_altitude = *min_altitude + 11.0 * layer->scaling;
|
||||||
}
|
}
|
||||||
|
|
||||||
double CloudModelStratoCumulus::getDensity(const Vector3 &location) const {
|
double CloudModelStratoCumulus::getDensity(const Vector3 &location, double precision) const {
|
||||||
double val;
|
double val;
|
||||||
double min_altitude, max_altitude;
|
double min_altitude, max_altitude;
|
||||||
double noise_scaling = 30.0 * layer->scaling;
|
double noise_scaling = 30.0 * layer->scaling;
|
||||||
|
@ -55,7 +55,7 @@ double CloudModelStratoCumulus::getDensity(const Vector3 &location) const {
|
||||||
// layer->scaling);
|
// layer->scaling);
|
||||||
double coverage = layer->coverage;
|
double coverage = layer->coverage;
|
||||||
|
|
||||||
val = 0.5 * noise->get3DTotal(x, y, z);
|
val = 0.5 * noise->get3DDetail(x, y, z, precision);
|
||||||
return val - 0.9 + coverage;
|
return val - 0.9 + coverage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ class CloudModelStratoCumulus : public BaseCloudsModel {
|
||||||
virtual void update() override;
|
virtual void update() override;
|
||||||
|
|
||||||
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
|
virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override;
|
||||||
virtual double getDensity(const Vector3 &location) const override;
|
virtual double getDensity(const Vector3 &location, double precision) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NoiseGenerator *noise;
|
NoiseGenerator *noise;
|
||||||
|
|
|
@ -11,3 +11,21 @@ TEST(Maths, modInRange) {
|
||||||
EXPECT_DOUBLE_EQ(5.2831853071795862, Maths::modInRange(-1.0, 0, Maths::TWOPI));
|
EXPECT_DOUBLE_EQ(5.2831853071795862, Maths::modInRange(-1.0, 0, Maths::TWOPI));
|
||||||
EXPECT_DOUBLE_EQ(-1.183185307179586, Maths::modInRange(5.1, -Maths::PI, Maths::PI));
|
EXPECT_DOUBLE_EQ(-1.183185307179586, Maths::modInRange(5.1, -Maths::PI, Maths::PI));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Maths, zeroPoint) {
|
||||||
|
EXPECT_DOUBLE_EQ(0.5, Maths::zeroPoint(1.0, 1.0, -1.0));
|
||||||
|
EXPECT_DOUBLE_EQ(4.0, Maths::zeroPoint(2.0, 1.0, 0.5));
|
||||||
|
EXPECT_DOUBLE_EQ(-1.5, Maths::zeroPoint(1.5, -1.0, -2.0));
|
||||||
|
EXPECT_DOUBLE_EQ(0.0, Maths::zeroPoint(0.0, 1.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Maths, smoothstep) {
|
||||||
|
EXPECT_DOUBLE_EQ(0.0, Maths::smoothstep(2.0, 5.0, -1.0));
|
||||||
|
EXPECT_DOUBLE_EQ(0.0, Maths::smoothstep(2.0, 5.0, 1.0));
|
||||||
|
EXPECT_DOUBLE_EQ(0.0, Maths::smoothstep(2.0, 5.0, 2.0));
|
||||||
|
EXPECT_DOUBLE_EQ(0.07407407407407407, Maths::smoothstep(2.0, 5.0, 2.5));
|
||||||
|
EXPECT_DOUBLE_EQ(0.25925925925925924, Maths::smoothstep(2.0, 5.0, 3.0));
|
||||||
|
EXPECT_DOUBLE_EQ(0.5, Maths::smoothstep(2.0, 5.0, 3.5));
|
||||||
|
EXPECT_DOUBLE_EQ(1.0, Maths::smoothstep(2.0, 5.0, 5.0));
|
||||||
|
EXPECT_DOUBLE_EQ(1.0, Maths::smoothstep(2.0, 5.0, 10.0));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue