From a54c8d521757c314a571e5e642dddfa5226db32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Mon, 1 Feb 2016 20:38:29 +0100 Subject: [PATCH] Improved clouds lighting --- src/basics/Maths.cpp | 9 ++ src/basics/Maths.h | 7 ++ src/basics/NoiseFunctionSimplex.cpp | 52 ++--------- src/definition/CloudLayerDefinition.h | 3 +- src/definition/SurfaceMaterial.cpp | 10 +- src/definition/SurfaceMaterial.h | 3 +- src/interface/commandline/main.cpp | 3 +- src/interface/commandline/tests.cpp | 51 ++++++++--- src/interface/modeler/MainModelerWindow.cpp | 3 +- src/interface/modeler/OpenGLView.h | 2 +- src/interface/modeler/PropertyBind.h | 2 +- src/interface/modeler/RenderProcess.cpp | 4 +- src/render/opengl/OpenGLRenderer.cpp | 2 +- .../software/AtmosphereModelBruneton.cpp | 4 +- src/render/software/AtmosphereRenderer.cpp | 3 +- .../software/CloudBasicLayerRenderer.cpp | 91 ++++++++++++------- src/render/software/CloudBasicLayerRenderer.h | 2 +- src/render/software/CloudsRenderer.cpp | 1 + src/render/software/GodRaysSampler.cpp | 11 ++- src/render/software/LightingManager.cpp | 18 ++-- .../software/SoftwareCanvasRenderer.cpp | 1 + .../software/clouds/BaseCloudsModel.cpp | 2 +- src/render/software/clouds/BaseCloudsModel.h | 2 +- .../software/clouds/CloudModelAltoCumulus.cpp | 2 +- .../software/clouds/CloudModelAltoCumulus.h | 2 +- .../software/clouds/CloudModelCirrus.cpp | 2 +- src/render/software/clouds/CloudModelCirrus.h | 2 +- .../clouds/CloudModelCumuloNimbus.cpp | 2 +- .../software/clouds/CloudModelCumuloNimbus.h | 2 +- .../clouds/CloudModelStratoCumulus.cpp | 4 +- .../software/clouds/CloudModelStratoCumulus.h | 2 +- src/tests/Maths_Test.cpp | 18 ++++ 32 files changed, 188 insertions(+), 134 deletions(-) diff --git a/src/basics/Maths.cpp b/src/basics/Maths.cpp index e053876..3bf6d9d 100644 --- a/src/basics/Maths.cpp +++ b/src/basics/Maths.cpp @@ -22,3 +22,12 @@ double Maths::smoothstep(double edge0, double edge1, double x) { x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); 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; + } +} diff --git a/src/basics/Maths.h b/src/basics/Maths.h index 2c73f4a..98cca49 100644 --- a/src/basics/Maths.h +++ b/src/basics/Maths.h @@ -26,6 +26,13 @@ class BASICSSHARED_EXPORT Maths { */ 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_2 = PI / 2.0; static constexpr double PI_4 = PI / 4.0; diff --git a/src/basics/NoiseFunctionSimplex.cpp b/src/basics/NoiseFunctionSimplex.cpp index 018cc53..d52c072 100644 --- a/src/basics/NoiseFunctionSimplex.cpp +++ b/src/basics/NoiseFunctionSimplex.cpp @@ -27,51 +27,15 @@ typedef struct { double w; } Grad4; -static Grad3 _grad3[] = {{1, 1, 0}, - {-1, 1, 0}, - {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 Grad3 _grad3[] = {{1, 1, 0}, {-1, 1, 0}, {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}, - {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, -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 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}, {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[] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, diff --git a/src/definition/CloudLayerDefinition.h b/src/definition/CloudLayerDefinition.h index 679b448..d0e3b52 100644 --- a/src/definition/CloudLayerDefinition.h +++ b/src/definition/CloudLayerDefinition.h @@ -45,7 +45,8 @@ class DEFINITIONSHARED_EXPORT CloudLayerDefinition : public DefinitionNode { CUMULONIMBUS, CIRROCUMULUS, CIRROSTRATUS, - CIRRUS + CIRRUS, + _COUNT } CloudsType; public: diff --git a/src/definition/SurfaceMaterial.cpp b/src/definition/SurfaceMaterial.cpp index 50afef2..306f4c1 100644 --- a/src/definition/SurfaceMaterial.cpp +++ b/src/definition/SurfaceMaterial.cpp @@ -10,10 +10,10 @@ SurfaceMaterial::SurfaceMaterial() : SurfaceMaterial(COLOR_BLACK) { SurfaceMaterial::SurfaceMaterial(const Color &color) { base = new Color(color); + ambient = 0.0; hardness = 0.5; reflection = 0.0; shininess = 0.0; - receive_shadows = 1.0; } 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 { base->save(stream); + stream->write(&ambient); stream->write(&hardness); stream->write(&reflection); stream->write(&shininess); - - stream->write(&receive_shadows); } void SurfaceMaterial::load(PackStream *stream) { base->load(stream); + stream->read(&ambient); stream->read(&hardness); stream->read(&reflection); stream->read(&shininess); - - stream->read(&receive_shadows); } void SurfaceMaterial::copy(SurfaceMaterial *destination) const { *destination->base = *base; + destination->ambient = ambient; destination->hardness = hardness; destination->reflection = reflection; destination->shininess = shininess; - destination->receive_shadows = receive_shadows; destination->validate(); } diff --git a/src/definition/SurfaceMaterial.h b/src/definition/SurfaceMaterial.h index a4d0e46..0b89557 100644 --- a/src/definition/SurfaceMaterial.h +++ b/src/definition/SurfaceMaterial.h @@ -25,11 +25,10 @@ class DEFINITIONSHARED_EXPORT SurfaceMaterial { public: Color *base; + double ambient; double hardness; double reflection; double shininess; - - double receive_shadows; }; } } diff --git a/src/interface/commandline/main.cpp b/src/interface/commandline/main.cpp index 294d7c4..7e6ca74 100644 --- a/src/interface/commandline/main.cpp +++ b/src/interface/commandline/main.cpp @@ -127,8 +127,7 @@ int main(int argc, char **argv) { scenery->autoPreset(); } - Logs::debug("CommandLine") << "Rendered scenery :" << endl - << scenery->toString() << endl; + Logs::debug("CommandLine") << "Rendered scenery :" << endl << scenery->toString() << endl; TimeManager time; time.setWind(conf_wind_x, conf_wind_z); diff --git a/src/interface/commandline/tests.cpp b/src/interface/commandline/tests.cpp index 7727c27..6c2d51f 100644 --- a/src/interface/commandline/tests.cpp +++ b/src/interface/commandline/tests.cpp @@ -152,6 +152,7 @@ static void testCloudQuality() { SoftwareCanvasRenderer renderer(&scenery); renderer.setSize(600, 800); + renderer.getGodRaysSampler()->setEnabled(false); SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0); renderer.setSoloRasterizer(&rasterizer); for (int i = 0; i < 6; i++) { @@ -463,14 +464,11 @@ static void testCloudsLighting() { FakeModel(CloudLayerDefinition *layer, double scale) : BaseCloudsModel(layer), scale(scale) { } virtual void getAltitudeRange(double *min_altitude, double *max_altitude) const override { - *min_altitude = -scale; - *max_altitude = scale; + *min_altitude = 10.0 - scale; + *max_altitude = 10.0 + scale; } - virtual void getDetailRange(double *min_step, double *max_step) const override { - *min_step = *max_step = scale * 0.01; - } - virtual double getDensity(const Vector3 &location) const override { - return Maths::smoothstep(0.0, 0.2, 1.0 - location.getNorm() / scale); + virtual double getDensity(const Vector3 &location, double) const override { + return 1.0 - location.sub(Vector3(0.0, 10.0, 0.0)).getNorm() / scale; } double scale; }; @@ -482,8 +480,8 @@ static void testCloudsLighting() { virtual Color processPixel(int, int, double relx, double rely) const override { auto cloud_renderer = renderer->getCloudsRenderer(); auto atmo_renderer = renderer->getAtmosphereRenderer(); - return cloud_renderer->getColor(Vector3(relx * scale * 1.2, rely * scale * 1.2, scale), - 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, 10.0 + rely * scale * 1.2, -scale), atmo_renderer->getSkyColor(Vector3(relx, rely, 1.0).normalize()).final); } virtual int prepareRasterization() override { @@ -500,15 +498,16 @@ static void testCloudsLighting() { Scenery scenery; scenery.autoPreset(1); + scenery.getTerrain()->propHeightNoise()->setConfig(0.0); 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"); scenery.getClouds()->clear(); scenery.getClouds()->addLayer(layer); SoftwareCanvasRenderer renderer(&scenery); - FakeRasterizer rasterizer(&renderer, 10.0); + FakeRasterizer rasterizer(&renderer, 5.0); renderer.setSize(800, 800); renderer.setSoloRasterizer(&rasterizer); renderer.getGodRaysSampler()->setEnabled(false); @@ -522,6 +521,36 @@ static void testCloudsLighting() { 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(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() { testNoise(); testTextures(); diff --git a/src/interface/modeler/MainModelerWindow.cpp b/src/interface/modeler/MainModelerWindow.cpp index 0854146..64adb6c 100644 --- a/src/interface/modeler/MainModelerWindow.cpp +++ b/src/interface/modeler/MainModelerWindow.cpp @@ -141,8 +141,7 @@ void MainModelerWindow::keyReleaseEvent(QKeyEvent *event) { } else if (event->key() == Qt::Key_F6) { render_process->showPreviousRender(); } else if (event->key() == Qt::Key_F12) { - Logs::warning("UI") << "Current scenery dump:" << endl - << scenery->toString() << endl; + Logs::warning("UI") << "Current scenery dump:" << endl << scenery->toString() << endl; } else if (event->key() == Qt::Key_N) { if (event->modifiers() & Qt::ControlModifier) { newFile(); diff --git a/src/interface/modeler/OpenGLView.h b/src/interface/modeler/OpenGLView.h index 605b030..4cd8eb3 100644 --- a/src/interface/modeler/OpenGLView.h +++ b/src/interface/modeler/OpenGLView.h @@ -19,7 +19,7 @@ class OpenGLView : public QQuickItem { void handleResize(); void handleSceneGraphReady(); -signals: + signals: void stopped(); protected: diff --git a/src/interface/modeler/PropertyBind.h b/src/interface/modeler/PropertyBind.h index 8ca02ac..9d0a10e 100644 --- a/src/interface/modeler/PropertyBind.h +++ b/src/interface/modeler/PropertyBind.h @@ -8,7 +8,7 @@ class PropertyBind : public QObject { public: explicit PropertyBind(QObject *parent = 0); -signals: + signals: public slots: }; diff --git a/src/interface/modeler/RenderProcess.cpp b/src/interface/modeler/RenderProcess.cpp index f2f7085..8576864 100644 --- a/src/interface/modeler/RenderProcess.cpp +++ b/src/interface/modeler/RenderProcess.cpp @@ -128,11 +128,11 @@ void RenderProcess::startQuickRender() { } void RenderProcess::startMediumRender() { - startRender(window->getScenery(), RenderConfig(800, 450, 1, 5)); + startRender(window->getScenery(), RenderConfig(800, 450, 1, 7)); } void RenderProcess::startFinalRender() { - startRender(window->getScenery(), RenderConfig(1920, 1080, 4, 8)); + startRender(window->getScenery(), RenderConfig(1920, 1080, 4, 10)); } void RenderProcess::showPreviousRender() { diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index f383873..17e7c8f 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -253,7 +253,7 @@ void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) { projection.perspective(perspective.yfov * 180.0 / Maths::PI, perspective.xratio, perspective.znear, perspective.zfar); - *view_matrix = projection *transform; + *view_matrix = projection * transform; // Set in shaders shared_state->set("cameraLocation", location); diff --git a/src/render/software/AtmosphereModelBruneton.cpp b/src/render/software/AtmosphereModelBruneton.cpp index 44aa60a..7a13507 100644 --- a/src/render/software/AtmosphereModelBruneton.cpp +++ b/src/render/software/AtmosphereModelBruneton.cpp @@ -266,8 +266,8 @@ static Color _transmittance3(double r, double mu, double d) { } static void _getIrradianceRMuS(double x, double y, double *r, double *muS) { - *r = Rg + y *(Rt - Rg); - *muS = -0.2 + x *(1.0 + 0.2); + *r = Rg + y * (Rt - Rg); + *muS = -0.2 + x * (1.0 + 0.2); } /* nearest intersection of ray r,mu with ground or top atmosphere boundary diff --git a/src/render/software/AtmosphereRenderer.cpp b/src/render/software/AtmosphereRenderer.cpp index a739ba9..5fc5ecc 100644 --- a/src/render/software/AtmosphereRenderer.cpp +++ b/src/render/software/AtmosphereRenderer.cpp @@ -117,8 +117,7 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::applyAerialPerspective(cons case AtmosphereDefinition::ATMOSPHERE_MODEL_BRUNETON: result = model->applyAerialPerspective(location, base); break; - default: - ; + default:; } // Apply god rays ponderation diff --git a/src/render/software/CloudBasicLayerRenderer.cpp b/src/render/software/CloudBasicLayerRenderer.cpp index f4131b7..2fb852a 100644 --- a/src/render/software/CloudBasicLayerRenderer.cpp +++ b/src/render/software/CloudBasicLayerRenderer.cpp @@ -13,6 +13,7 @@ #include "clouds/BaseCloudsModel.h" #include "SurfaceMaterial.h" #include "Logs.h" +#include "Maths.h" #include "FloatNode.h" struct CloudSegment { @@ -24,10 +25,6 @@ struct CloudSegment { 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). * @@ -47,13 +44,14 @@ static inline double _getDistanceToBorder(BaseCloudsModel *model, const Vector3 */ int CloudBasicLayerRenderer::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, CloudSegment *out_segments) { + double *inside_length, double *total_length, CloudSegment *out_segments, + double base_detail) { double ymin, ymax; int inside, segment_count; double current_total_length, current_inside_length; double step_length, segment_length; double min_step, max_step; - double noise_distance; + double noise_distance, previous_noise_distance; Vector3 walker, step, segment_start, offset; double render_precision; @@ -68,20 +66,30 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 double distance = parent->getCameraLocation().sub(start).getNorm(); 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; current_total_length = 0.0; current_inside_length = 0.0; segment_length = 0.0; walker = start; offset = Vector3(model->getLayer()->propXOffset()->getValue(), 0.0, model->getLayer()->propZOffset()->getValue()); - noise_distance = _getDistanceToBorder(model, start.add(offset)) * render_precision; - inside = 0; + noise_distance = model->getDensity(start.add(offset), base_detail); + previous_noise_distance = noise_distance; + inside = noise_distance > 0.0; + if (inside) { + segment_start = start; + } step = direction.scale(render_precision); + bool stop = false; do { walker = walker.add(step); 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; if (noise_distance > 0.0) { @@ -89,23 +97,26 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 // inside the cloud segment_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 { // entering the cloud inside = 1; - segment_length = 0.0; - segment_start = walker; + segment_length = step_length - Maths::zeroPoint(step_length, previous_noise_distance, noise_distance); + assert(segment_length >= 0.0 && segment_length <= step_length); + segment_start = walker.add(direction.scale(-segment_length)); current_inside_length += segment_length; step = direction.scale(render_precision); } } else { if (inside) { // exiting the cloud - segment_length += step_length; - current_inside_length += step_length; + double exit_length = Maths::zeroPoint(step_length, previous_noise_distance, noise_distance); + assert(exit_length >= 0.0); + segment_length += exit_length; + current_inside_length += exit_length; 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++; if (++segment_count >= max_segments) { @@ -116,19 +127,30 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3 step = direction.scale(render_precision); } else { // 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); - } while (inside || (walker.y >= ymin - 0.001 && walker.y <= ymax + 0.001 && - current_total_length < max_total_length && current_inside_length < max_inside_length)); + previous_noise_distance = noise_distance; + 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; *inside_length = current_inside_length; 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) { int i, segment_count; double max_length, total_length, inside_length; @@ -151,27 +173,32 @@ Color CloudBasicLayerRenderer::getColor(BaseCloudsModel *model, const Vector3 &e model->getAltitudeRange(&ymin, &ymax); double transparency_depth = (ymax - ymin); - SurfaceMaterial material(COLOR_WHITE.scaled(5.0)); - material.hardness = 1.0; - material.reflection = 0.0; - material.shininess = 0.0; + SurfaceMaterial material(COLOR_WHITE.scaled(8.0)); + material.ambient = 0.8; + material.hardness = 0.0; + material.reflection = 0.2; + material.shininess = 3.0; material.validate(); 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--) { - 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); result.mask(col); } - // Opacify when hitting inside_length limit - if (inside_length >= transparency_depth) { - 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)); - } + // Opacity + result.a = Maths::smoothstep(0.0, transparency_depth, inside_length); // Apply aerial perspective if (result.a > 0.00001) { @@ -196,14 +223,14 @@ bool CloudBasicLayerRenderer::alterLight(BaseCloudsModel *model, LightComponent direction = light->direction.scale(-1.0); end = location.add(direction.scale(10000.0)); if (not optimizeSearchLimits(model, &start, &end)) { - return false; + return true; } double ymin, ymax; model->getAltitudeRange(&ymin, &ymax); 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, - segments); + segments, 0.1); if (light_traversal < 0.0001) { factor = 0.0; diff --git a/src/render/software/CloudBasicLayerRenderer.h b/src/render/software/CloudBasicLayerRenderer.h index 4d50433..6d3cc78 100644 --- a/src/render/software/CloudBasicLayerRenderer.h +++ b/src/render/software/CloudBasicLayerRenderer.h @@ -27,7 +27,7 @@ class SOFTWARESHARED_EXPORT CloudBasicLayerRenderer : public BaseCloudLayerRende private: 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, - CloudSegment *out_segments); + CloudSegment *out_segments, double base_detail); }; } } diff --git a/src/render/software/CloudsRenderer.cpp b/src/render/software/CloudsRenderer.cpp index 0eab78e..a1e7d39 100644 --- a/src/render/software/CloudsRenderer.cpp +++ b/src/render/software/CloudsRenderer.cpp @@ -85,6 +85,7 @@ void CloudsRenderer::update() { case CloudLayerDefinition::ALTOSTRATUS: case CloudLayerDefinition::CIRROCUMULUS: case CloudLayerDefinition::CIRROSTRATUS: + case CloudLayerDefinition::_COUNT: model = new BaseCloudsModel(layer); break; } diff --git a/src/render/software/GodRaysSampler.cpp b/src/render/software/GodRaysSampler.cpp index cb11394..72f23ce 100644 --- a/src/render/software/GodRaysSampler.cpp +++ b/src/render/software/GodRaysSampler.cpp @@ -119,9 +119,14 @@ double GodRaysSampler::getCachedLight(const Vector3 &location) { } // Hit cache - double p[8] = {getCache(ix, iy, iz), getCache(ix + 1, iy, iz), 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)}; + double p[8] = {getCache(ix, iy, iz), + getCache(ix + 1, iy, iz), + 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, (y - sampling_step * double(iy)) / sampling_step, (z - sampling_step * double(iz)) / sampling_step); diff --git a/src/render/software/LightingManager.cpp b/src/render/software/LightingManager.cpp index 8ad0fe6..32de0d9 100644 --- a/src/render/software/LightingManager.cpp +++ b/src/render/software/LightingManager.cpp @@ -7,6 +7,7 @@ #include "LightSource.h" #include "Color.h" #include "SurfaceMaterial.h" +#include "Logs.h" LightingManager::LightingManager() { specularity = true; @@ -92,21 +93,16 @@ void LightingManager::setFiltering(bool enabled) { Color LightingManager::applyFinalComponent(const LightComponent &component, const Vector3 &eye, const Vector3 &location, const Vector3 &normal, const SurfaceMaterial &material) { Color result, light_color; - double normal_norm; Vector3 direction_inv; light_color = component.color; direction_inv = component.direction.normalize().scale(-1.0); - - normal_norm = normal.getNorm(); - if (normal_norm > 1.0) { - normal_norm = 1.0; - } + normal.normalize(); result = COLOR_BLACK; /* diffused light */ - double diffuse = direction_inv.dotProduct(normal.normalize()); + double diffuse = direction_inv.dotProduct(normal); double sign = (diffuse < 0.0) ? -1.0 : 1.0; if (material.hardness <= 0.5) { 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; 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) { result.r += diffuse * material.base->r * light_color.r; result.g += diffuse * material.base->g * light_color.g; @@ -123,12 +121,12 @@ Color LightingManager::applyFinalComponent(const LightComponent &component, cons } /* 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 reflect = direction_inv.sub(normal.scale(2.0 * direction_inv.dotProduct(normal))); double specular = reflect.dotProduct(view); 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) { result.r += specular * light_color.r; result.g += specular * light_color.g; diff --git a/src/render/software/SoftwareCanvasRenderer.cpp b/src/render/software/SoftwareCanvasRenderer.cpp index c2e448d..4c14d09 100644 --- a/src/render/software/SoftwareCanvasRenderer.cpp +++ b/src/render/software/SoftwareCanvasRenderer.cpp @@ -33,6 +33,7 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery) : SoftwareRende new VegetationRasterizer(this, progress, RASTERIZER_CLIENT_VEGETATION)); current_work = NULL; + setQuality(0.5); } SoftwareCanvasRenderer::~SoftwareCanvasRenderer() { diff --git a/src/render/software/clouds/BaseCloudsModel.cpp b/src/render/software/clouds/BaseCloudsModel.cpp index 5a2173d..6e56873 100644 --- a/src/render/software/clouds/BaseCloudsModel.cpp +++ b/src/render/software/clouds/BaseCloudsModel.cpp @@ -29,7 +29,7 @@ double BaseCloudsModel::getProbability(const Vector3 &, double) const { return 1.0; } -double BaseCloudsModel::getDensity(const Vector3 &) const { +double BaseCloudsModel::getDensity(const Vector3 &, double) const { return 0.0; } diff --git a/src/render/software/clouds/BaseCloudsModel.h b/src/render/software/clouds/BaseCloudsModel.h index 4991a8c..efa36ab 100644 --- a/src/render/software/clouds/BaseCloudsModel.h +++ b/src/render/software/clouds/BaseCloudsModel.h @@ -21,7 +21,7 @@ class SOFTWARESHARED_EXPORT BaseCloudsModel { 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 double getDensity(const Vector3 &location, double precision) const; virtual Color filterLight(const Color &light, double length, double density) const; virtual Color applyLightExit(const Color &light, const Vector3 &light_direction, const Vector3 &direction_to_eye) const; diff --git a/src/render/software/clouds/CloudModelAltoCumulus.cpp b/src/render/software/clouds/CloudModelAltoCumulus.cpp index 692e586..f8df3e8 100644 --- a/src/render/software/clouds/CloudModelAltoCumulus.cpp +++ b/src/render/software/clouds/CloudModelAltoCumulus.cpp @@ -32,7 +32,7 @@ void CloudModelAltoCumulus::getAltitudeRange(double *min_altitude, double *max_a *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 min_altitude, max_altitude; double noise_scaling = 18.0 * layer->scaling; diff --git a/src/render/software/clouds/CloudModelAltoCumulus.h b/src/render/software/clouds/CloudModelAltoCumulus.h index 4884ede..306c8cb 100644 --- a/src/render/software/clouds/CloudModelAltoCumulus.h +++ b/src/render/software/clouds/CloudModelAltoCumulus.h @@ -16,7 +16,7 @@ class CloudModelAltoCumulus : public BaseCloudsModel { virtual void update() 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: NoiseGenerator *noise; diff --git a/src/render/software/clouds/CloudModelCirrus.cpp b/src/render/software/clouds/CloudModelCirrus.cpp index 8040b7b..1fcdb45 100644 --- a/src/render/software/clouds/CloudModelCirrus.cpp +++ b/src/render/software/clouds/CloudModelCirrus.cpp @@ -30,7 +30,7 @@ void CloudModelCirrus::getAltitudeRange(double *min_altitude, double *max_altitu *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 min_altitude, max_altitude; double noise_scaling = 30.0 * layer->scaling; diff --git a/src/render/software/clouds/CloudModelCirrus.h b/src/render/software/clouds/CloudModelCirrus.h index 6572d24..7b2b56b 100644 --- a/src/render/software/clouds/CloudModelCirrus.h +++ b/src/render/software/clouds/CloudModelCirrus.h @@ -16,7 +16,7 @@ class CloudModelCirrus : public BaseCloudsModel { virtual void update() 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: NoiseGenerator *noise; diff --git a/src/render/software/clouds/CloudModelCumuloNimbus.cpp b/src/render/software/clouds/CloudModelCumuloNimbus.cpp index af77379..dfa0337 100644 --- a/src/render/software/clouds/CloudModelCumuloNimbus.cpp +++ b/src/render/software/clouds/CloudModelCumuloNimbus.cpp @@ -37,7 +37,7 @@ void CloudModelCumuloNimbus::getAltitudeRange(double *min_altitude, double *max_ *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 min_altitude, max_altitude; double noise_scaling = 60.0 * layer->scaling; diff --git a/src/render/software/clouds/CloudModelCumuloNimbus.h b/src/render/software/clouds/CloudModelCumuloNimbus.h index d2dd7f0..6d329bc 100644 --- a/src/render/software/clouds/CloudModelCumuloNimbus.h +++ b/src/render/software/clouds/CloudModelCumuloNimbus.h @@ -16,7 +16,7 @@ class CloudModelCumuloNimbus : public BaseCloudsModel { virtual void update() 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: NoiseGenerator *noise; diff --git a/src/render/software/clouds/CloudModelStratoCumulus.cpp b/src/render/software/clouds/CloudModelStratoCumulus.cpp index 0c0cc0a..f2b83a6 100644 --- a/src/render/software/clouds/CloudModelStratoCumulus.cpp +++ b/src/render/software/clouds/CloudModelStratoCumulus.cpp @@ -37,7 +37,7 @@ void CloudModelStratoCumulus::getAltitudeRange(double *min_altitude, double *max *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 min_altitude, max_altitude; double noise_scaling = 30.0 * layer->scaling; @@ -55,7 +55,7 @@ double CloudModelStratoCumulus::getDensity(const Vector3 &location) const { // layer->scaling); 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; } } diff --git a/src/render/software/clouds/CloudModelStratoCumulus.h b/src/render/software/clouds/CloudModelStratoCumulus.h index 482d144..027535f 100644 --- a/src/render/software/clouds/CloudModelStratoCumulus.h +++ b/src/render/software/clouds/CloudModelStratoCumulus.h @@ -16,7 +16,7 @@ class CloudModelStratoCumulus : public BaseCloudsModel { virtual void update() 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: NoiseGenerator *noise; diff --git a/src/tests/Maths_Test.cpp b/src/tests/Maths_Test.cpp index 7298ba2..b9db56e 100644 --- a/src/tests/Maths_Test.cpp +++ b/src/tests/Maths_Test.cpp @@ -11,3 +11,21 @@ TEST(Maths, modInRange) { 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)); } + +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)); +}