diff --git a/src/definition/AtmosphereDefinition.cpp b/src/definition/AtmosphereDefinition.cpp index 8a1b4f5..fff300b 100644 --- a/src/definition/AtmosphereDefinition.cpp +++ b/src/definition/AtmosphereDefinition.cpp @@ -102,8 +102,8 @@ void AtmosphereDefinition::applyPreset(AtmospherePreset preset, RandomGenerator sun_color.g = 0.95; sun_color.b = 0.9; sun_color.a = 1.0; - sun->propRadius()->setValue(1.0); sun->propDistance()->setValue(Scenery::SUN_DISTANCE_SCALED); + sun->propRadius()->setValue(Scenery::SUN_RADIUS_SCALED); moon->propDistance()->setValue(384403.0 * Scenery::KM_TO_UNIT); moon->propRadius()->setValue(1737.4 * Scenery::KM_TO_UNIT); moon->propPhi()->setValue(0.5); diff --git a/src/definition/CelestialBodyDefinition.cpp b/src/definition/CelestialBodyDefinition.cpp index f045f03..d67a091 100644 --- a/src/definition/CelestialBodyDefinition.cpp +++ b/src/definition/CelestialBodyDefinition.cpp @@ -1,5 +1,6 @@ #include "CelestialBodyDefinition.h" +#include #include "Vector3.h" #include "FloatNode.h" #include "Scenery.h" @@ -12,6 +13,11 @@ CelestialBodyDefinition::CelestialBodyDefinition(DefinitionNode *parent, const s radius = new FloatNode(this, "radius"); } +Vector3 CelestialBodyDefinition::getGlobalDirection() const { + VectorSpherical spc = {1.0, theta->getValue(), -phi->getValue()}; + return Vector3(spc); +} + Vector3 CelestialBodyDefinition::getLocation(bool over_water) const { VectorSpherical spc = {distance->getValue(), theta->getValue(), -phi->getValue()}; if (over_water) { @@ -20,3 +26,7 @@ Vector3 CelestialBodyDefinition::getLocation(bool over_water) const { return Vector3(spc); } } + +double CelestialBodyDefinition::getAngularRadius() const { + return 2.0 * atan(radius->getValue() / distance->getValue()); +} diff --git a/src/definition/CelestialBodyDefinition.h b/src/definition/CelestialBodyDefinition.h index a65207b..8a4bd7e 100644 --- a/src/definition/CelestialBodyDefinition.h +++ b/src/definition/CelestialBodyDefinition.h @@ -25,6 +25,11 @@ class DEFINITIONSHARED_EXPORT CelestialBodyDefinition : public DefinitionNode { return radius; } + /** + * Get the normalized direction of the celestial body, from the center of the earth. + */ + Vector3 getGlobalDirection() const; + /** * Get the location of the celestial body. * @@ -33,6 +38,11 @@ class DEFINITIONSHARED_EXPORT CelestialBodyDefinition : public DefinitionNode { */ Vector3 getLocation(bool over_water = true) const; + /** + * Get the angular radius, when viewed from earth. + */ + double getAngularRadius() const; + private: FloatNode *distance; FloatNode *phi; diff --git a/src/definition/Scenery.h b/src/definition/Scenery.h index 6ef31b0..d132961 100644 --- a/src/definition/Scenery.h +++ b/src/definition/Scenery.h @@ -39,7 +39,7 @@ class DEFINITIONSHARED_EXPORT Scenery : public DefinitionNode { static constexpr double SUN_DISTANCE_SCALED = SUN_DISTANCE * KM_TO_UNIT; static constexpr double SUN_RADIUS = 6.955e5; - static constexpr double SUN_RADIUS_SCALED = EARTH_RADIUS * KM_TO_UNIT; + static constexpr double SUN_RADIUS_SCALED = SUN_RADIUS * KM_TO_UNIT; static constexpr double FAR_LIMIT_SCALED = 20000.0; diff --git a/src/interface/commandline/tests.cpp b/src/interface/commandline/tests.cpp index bf09a53..51280e7 100644 --- a/src/interface/commandline/tests.cpp +++ b/src/interface/commandline/tests.cpp @@ -414,13 +414,12 @@ static void testTextures() { } } -static void testMoonRendering() { +static void testCelestialBodies() { Scenery scenery; scenery.autoPreset(8); + scenery.getTerrain()->propHeightNoise()->setConfig(0.0); scenery.getClouds()->clear(); scenery.getCamera()->setLocation(VECTOR_ZERO); - scenery.getCamera()->setTarget(scenery.getAtmosphere()->childMoon()->getLocation()); - scenery.getCamera()->setFov(0.1); SoftwareCanvasRenderer renderer(&scenery); renderer.setSize(600, 600); @@ -429,25 +428,40 @@ static void testMoonRendering() { /*SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0); renderer.setSoloRasterizer(&rasterizer);*/ - // During the day + scenery.getCamera()->setTarget(scenery.getAtmosphere()->childMoon()->getLocation()); + scenery.getCamera()->setFov(0.02); + scenery.getAtmosphere()->setDayTime(17, 30); - startTestRender(&renderer, "moon", 0); + startTestRender(&renderer, "celestial_bodies_moon_day"); - // At night scenery.getAtmosphere()->setDayTime(23); - startTestRender(&renderer, "moon", 1); + startTestRender(&renderer, "celestial_bodies_moon_night"); - // Eclipse - scenery.getAtmosphere()->childSun()->propPhi()->setValue(scenery.getAtmosphere()->childMoon()->propPhi()->getValue()); - scenery.getAtmosphere()->childSun()->propTheta()->setValue(scenery.getAtmosphere()->childMoon()->propTheta()->getValue()); - startTestRender(&renderer, "moon", 2); + scenery.getCamera()->setFov(0.2); + + scenery.getAtmosphere()->setDayTime(6); + scenery.getCamera()->setTarget(scenery.getAtmosphere()->childSun()->getLocation()); + startTestRender(&renderer, "celestial_bodies_sun_horizon"); + + scenery.getAtmosphere()->setDayTime(6, 30); + scenery.getCamera()->setTarget(scenery.getAtmosphere()->childSun()->getLocation()); + startTestRender(&renderer, "celestial_bodies_sun_rising"); + + scenery.getAtmosphere()->setDayTime(11); + scenery.getCamera()->setFov(0.1); + + scenery.getAtmosphere()->childSun()->propPhi()->setValue( + scenery.getAtmosphere()->childMoon()->propPhi()->getValue()); + scenery.getAtmosphere()->childSun()->propTheta()->setValue( + scenery.getAtmosphere()->childMoon()->propTheta()->getValue()); + startTestRender(&renderer, "celestial_bodies_solar_eclipse"); } void runTestSuite() { testNoise(); testTextures(); testGodRays(); - testMoonRendering(); + testCelestialBodies(); testNearFrustum(); testCloudsNearGround(); testVegetationModels(); diff --git a/src/interface/modeler/ModelerCameras.cpp b/src/interface/modeler/ModelerCameras.cpp index f7f5dad..25c8078 100644 --- a/src/interface/modeler/ModelerCameras.cpp +++ b/src/interface/modeler/ModelerCameras.cpp @@ -91,8 +91,7 @@ void ModelerCameras::timerEvent(QTimerEvent *) { void ModelerCameras::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) { if (node->getPath().find("/atmosphere/sun/") == 0 and tool_mode == TOOL_SUN) { - Vector3 direction = parent->getRenderer()->getAtmosphereRenderer()->getSunDirection(); - tool->setTarget(tool->getLocation().add(direction)); + tool->setTarget(parent->getRenderer()->getAtmosphereRenderer()->getSunLocation()); } } diff --git a/src/interface/modeler/qml/AtmosphereSection.qml b/src/interface/modeler/qml/AtmosphereSection.qml index 3401c35..8606f44 100644 --- a/src/interface/modeler/qml/AtmosphereSection.qml +++ b/src/interface/modeler/qml/AtmosphereSection.qml @@ -44,7 +44,7 @@ BaseSection { id: panel_sun_radius anchors.left: toolbar.right minimumValue: 0 - maximumValue: 3 + maximumValue: 30000000 enabled: false objectName: "atmosphere_sun_radius" } diff --git a/src/render/opengl/OpenGLSkybox.cpp b/src/render/opengl/OpenGLSkybox.cpp index cec51f3..a17a822 100644 --- a/src/render/opengl/OpenGLSkybox.cpp +++ b/src/render/opengl/OpenGLSkybox.cpp @@ -5,6 +5,7 @@ #include "OpenGLShaderProgram.h" #include "OpenGLSharedState.h" #include "OpenGLVertexArray.h" +#include "CelestialBodyDefinition.h" #include "Scenery.h" #include "AtmosphereDefinition.h" #include "AtmosphereRenderer.h" @@ -82,7 +83,7 @@ void OpenGLSkybox::nodeChanged(const DefinitionNode *node, const DefinitionDiff AtmosphereDefinition *newdef = renderer->getScenery()->getAtmosphere(); if (node->getPath() == path_sun_phi or node->getPath() == path_sun_theta) { - Vector3 sun_direction = renderer->getAtmosphereRenderer()->getSunDirection(); + Vector3 sun_direction = newdef->childSun()->getGlobalDirection(); state->set("sunDirection", sun_direction); Color sun_color = newdef->sun_color; @@ -100,6 +101,6 @@ void OpenGLSkybox::floatNodeChanged(const string &path, double new_value, double if (path == path_humidity) { state->set("atmosphereHumidity", new_value); } else if (path == path_sun_radius) { - state->set("sunRadius", new_value); + state->set("sunRadius", renderer->getScenery()->getAtmosphere()->childSun()->getAngularRadius()); } } diff --git a/src/render/opengl/shaders/atmosphere.frag b/src/render/opengl/shaders/atmosphere.frag index bb26ca8..4e78922 100644 --- a/src/render/opengl/shaders/atmosphere.frag +++ b/src/render/opengl/shaders/atmosphere.frag @@ -92,7 +92,7 @@ vec4 _sunTransmittance(vec3 v, vec3 s, float r, float mu, float radius) vec4 transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : vec4(1.0); /* T(x,xo) */ float d = _limit(r, mu); radius *= (1.0 + 15.0 * d / Rt); /* Inflating due to lens effect near horizon */ - float isun = step(cos(radius * M_PI / 180.0), dot(v, s)) * ISun; /* Lsun */ + float isun = step(cos(radius), dot(v, s)) * ISun; /* Lsun */ transmittance.r *= isun; transmittance.g *= isun; transmittance.b *= isun; diff --git a/src/render/software/AtmosphereModelBruneton.cpp b/src/render/software/AtmosphereModelBruneton.cpp index 0fb2a18..d670010 100644 --- a/src/render/software/AtmosphereModelBruneton.cpp +++ b/src/render/software/AtmosphereModelBruneton.cpp @@ -861,8 +861,8 @@ static Color _getInscatterColor(Vector3 *_x, double *_t, Vector3 v, Vector3 s, d static Color _sunColor(Vector3 v, Vector3 s, double r, double mu, double radius) { Color transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : COLOR_WHITE; /* T(x,xo) */ double d = _limit(r, mu); - radius *= (1.0 + 15.0 * d / Rt); /* Inflating due to lens effect near horizon */ - double isun = step(cos(radius * Maths::PI / 180.0), v.dotProduct(s)) * ISun; /* Lsun */ + radius *= (1.0 + 15.0 * d / Rt); /* Inflating due to lens effect near horizon */ + double isun = step(cos(radius), v.dotProduct(s)) * ISun; /* Lsun */ transmittance.r *= isun; transmittance.g *= isun; transmittance.b *= isun; @@ -1063,6 +1063,7 @@ AtmosphereModelBruneton::~AtmosphereModelBruneton() { AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3 &direction, const Vector3 &sun_position, const Color &base) const { + auto definition = parent->getScenery()->getAtmosphere(); Vector3 x = {0.0, Rg + eye.y * Scenery::UNIT_TO_KM, 0.0}; Vector3 v = direction.normalize(); Vector3 s = sun_position.sub(x).normalize(); @@ -1073,8 +1074,7 @@ AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3 AtmosphereResult result; Vector3 attenuation; - Color sunColor = - _sunColor(v, s, r, mu, parent->getScenery()->getAtmosphere()->childSun()->propRadius()->getValue()); /* L0 */ + Color sunColor = _sunColor(v, s, r, mu, definition->childSun()->getAngularRadius()); /* L0 */ /*result.base.r = base.r + sunColor.r; result.base.g = base.g + sunColor.g; @@ -1090,10 +1090,11 @@ AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3 } AtmosphereResult AtmosphereModelBruneton::applyAerialPerspective(Vector3 location, const Color &base) const { + auto definition = parent->getScenery()->getAtmosphere(); Vector3 eye = parent->getCameraLocation(); eye.y = max(eye.y, 0.0); location.y = max(location.y, 0.0); - Vector3 sun_position = parent->getAtmosphereRenderer()->getSunDirection().scale(Scenery::SUN_DISTANCE); + Vector3 sun_position = definition->childSun()->getLocation(false).scale(Scenery::UNIT_TO_KM); Vector3 direction = location.sub(eye).scale(Scenery::UNIT_TO_KM); double t = direction.getNorm(); @@ -1134,6 +1135,7 @@ AtmosphereResult AtmosphereModelBruneton::applyAerialPerspective(Vector3 locatio } bool AtmosphereModelBruneton::getLightsAt(vector &result, const Vector3 &location) const { + auto definition = parent->getScenery()->getAtmosphere(); LightComponent sun, irradiance; double muS; @@ -1141,13 +1143,13 @@ bool AtmosphereModelBruneton::getLightsAt(vector &result, const double r0 = Rg + WORKAROUND_OFFSET + altitude; Vector3 up = {0.0, 1.0, 0.0}; - Vector3 sun_position = parent->getAtmosphereRenderer()->getSunDirection().scale(Scenery::SUN_DISTANCE); + Vector3 sun_position = definition->childSun()->getLocation(false).scale(Scenery::UNIT_TO_KM); Vector3 x = {0.0, r0, 0.0}; Vector3 s = sun_position.sub(x).normalize(); muS = up.dotProduct(s); if (altitude > RL) { - sun.color = parent->getScenery()->getAtmosphere()->sun_color; + sun.color = definition->sun_color; } else { sun.color = _transmittanceWithShadow(r0, muS); } diff --git a/src/render/software/AtmosphereRenderer.cpp b/src/render/software/AtmosphereRenderer.cpp index 1e1d9de..988dd21 100644 --- a/src/render/software/AtmosphereRenderer.cpp +++ b/src/render/software/AtmosphereRenderer.cpp @@ -80,6 +80,10 @@ AtmosphereResult BaseAtmosphereRenderer::getSkyColor(const Vector3 &) { return result; } +Vector3 BaseAtmosphereRenderer::getSunLocation() const { + return getDefinition()->childSun()->getLocation(); +} + Vector3 BaseAtmosphereRenderer::getSunDirection() const { auto sun_location = getDefinition()->childSun()->getLocation(); return sun_location.sub(parent->getCameraLocation()).normalize(); @@ -127,15 +131,14 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::applyAerialPerspective(cons AtmosphereResult SoftwareBrunetonAtmosphereRenderer::getSkyColor(const Vector3 &direction) { AtmosphereDefinition *definition; - Vector3 sun_direction, sun_position, camera_location; + Vector3 sun_position, camera_location; Color base; definition = getDefinition(); camera_location = parent->getCameraLocation(); - sun_direction = getSunDirection(); Vector3 direction_norm = direction.normalize(); - sun_position = sun_direction.scale(Scenery::SUN_DISTANCE_SCALED); + sun_position = getSunLocation(); base = COLOR_BLACK; @@ -145,7 +148,7 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::getSkyColor(const Vector3 & // Get sun shape /*if (v3Dot(sun_direction, direction) >= 0) { - double sun_radius = definition->sun_radius * SUN_RADIUS_SCALED * 5.0; // FIXME Why should we multiply by 5 ? + double sun_radius = definition->sun_radius * SUN_RADIUS_SCALED; Vector3 hit1, hit2; int hits = euclidRayIntersectSphere(camera_location, direction, sun_position, sun_radius, &hit1, &hit2); if (hits > 1) diff --git a/src/render/software/AtmosphereRenderer.h b/src/render/software/AtmosphereRenderer.h index d043778..b9920e0 100644 --- a/src/render/software/AtmosphereRenderer.h +++ b/src/render/software/AtmosphereRenderer.h @@ -17,6 +17,7 @@ class BaseAtmosphereRenderer : public LightSource { virtual AtmosphereResult applyAerialPerspective(const Vector3 &location, const Color &base); virtual AtmosphereResult getSkyColor(const Vector3 &direction); virtual Vector3 getSunDirection() const; + virtual Vector3 getSunLocation() const; virtual bool getLightsAt(vector &result, const Vector3 &location) const override; diff --git a/src/render/software/NightSky.cpp b/src/render/software/NightSky.cpp index b67fdcc..70c570e 100644 --- a/src/render/software/NightSky.cpp +++ b/src/render/software/NightSky.cpp @@ -55,8 +55,7 @@ const Color NightSky::getColor(double altitude, const Vector3 &direction) { Vector3 moon_position = atmosphere->childMoon()->getLocation(); Vector3 moon_direction = moon_position.sub(renderer->getCameraLocation()).normalize(); if (moon_direction.dotProduct(direction) >= 0) { - // TODO Why need the multiplier ? - double moon_radius = atmosphere->childMoon()->propRadius()->getValue() * 5.0; + double moon_radius = atmosphere->childMoon()->propRadius()->getValue(); Vector3 hit1, hit2; int hits = Geometry::rayIntersectSphere(location, direction, moon_position, moon_radius, &hit1, &hit2); if (hits > 1) { diff --git a/src/tests/CelestialBodyDefinition_Test.cpp b/src/tests/CelestialBodyDefinition_Test.cpp new file mode 100644 index 0000000..1a070a9 --- /dev/null +++ b/src/tests/CelestialBodyDefinition_Test.cpp @@ -0,0 +1,12 @@ +#include "BaseTestCase.h" +#include "CelestialBodyDefinition.h" + +#include "FloatNode.h" + +TEST(CelestialBodyDefinition, getAngularRadius) { + CelestialBodyDefinition moon(NULL, "moon"); + moon.propDistance()->setValue(384403.0); + moon.propRadius()->setValue(1737.4); + + EXPECT_DOUBLE_EQ(0.0090394100441593961, moon.getAngularRadius()); +}