Fixed sun and moon radius being inconsistent

This commit is contained in:
Michaël Lemaire 2016-01-15 18:01:01 +01:00
parent 6b6710f15c
commit f4bc02c5ca
14 changed files with 84 additions and 33 deletions

View file

@ -102,8 +102,8 @@ void AtmosphereDefinition::applyPreset(AtmospherePreset preset, RandomGenerator
sun_color.g = 0.95; sun_color.g = 0.95;
sun_color.b = 0.9; sun_color.b = 0.9;
sun_color.a = 1.0; sun_color.a = 1.0;
sun->propRadius()->setValue(1.0);
sun->propDistance()->setValue(Scenery::SUN_DISTANCE_SCALED); sun->propDistance()->setValue(Scenery::SUN_DISTANCE_SCALED);
sun->propRadius()->setValue(Scenery::SUN_RADIUS_SCALED);
moon->propDistance()->setValue(384403.0 * Scenery::KM_TO_UNIT); moon->propDistance()->setValue(384403.0 * Scenery::KM_TO_UNIT);
moon->propRadius()->setValue(1737.4 * Scenery::KM_TO_UNIT); moon->propRadius()->setValue(1737.4 * Scenery::KM_TO_UNIT);
moon->propPhi()->setValue(0.5); moon->propPhi()->setValue(0.5);

View file

@ -1,5 +1,6 @@
#include "CelestialBodyDefinition.h" #include "CelestialBodyDefinition.h"
#include <cmath>
#include "Vector3.h" #include "Vector3.h"
#include "FloatNode.h" #include "FloatNode.h"
#include "Scenery.h" #include "Scenery.h"
@ -12,6 +13,11 @@ CelestialBodyDefinition::CelestialBodyDefinition(DefinitionNode *parent, const s
radius = new FloatNode(this, "radius"); 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 { Vector3 CelestialBodyDefinition::getLocation(bool over_water) const {
VectorSpherical spc = {distance->getValue(), theta->getValue(), -phi->getValue()}; VectorSpherical spc = {distance->getValue(), theta->getValue(), -phi->getValue()};
if (over_water) { if (over_water) {
@ -20,3 +26,7 @@ Vector3 CelestialBodyDefinition::getLocation(bool over_water) const {
return Vector3(spc); return Vector3(spc);
} }
} }
double CelestialBodyDefinition::getAngularRadius() const {
return 2.0 * atan(radius->getValue() / distance->getValue());
}

View file

@ -25,6 +25,11 @@ class DEFINITIONSHARED_EXPORT CelestialBodyDefinition : public DefinitionNode {
return radius; 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. * Get the location of the celestial body.
* *
@ -33,6 +38,11 @@ class DEFINITIONSHARED_EXPORT CelestialBodyDefinition : public DefinitionNode {
*/ */
Vector3 getLocation(bool over_water = true) const; Vector3 getLocation(bool over_water = true) const;
/**
* Get the angular radius, when viewed from earth.
*/
double getAngularRadius() const;
private: private:
FloatNode *distance; FloatNode *distance;
FloatNode *phi; FloatNode *phi;

View file

@ -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_DISTANCE_SCALED = SUN_DISTANCE * KM_TO_UNIT;
static constexpr double SUN_RADIUS = 6.955e5; 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; static constexpr double FAR_LIMIT_SCALED = 20000.0;

View file

@ -414,13 +414,12 @@ static void testTextures() {
} }
} }
static void testMoonRendering() { static void testCelestialBodies() {
Scenery scenery; Scenery scenery;
scenery.autoPreset(8); scenery.autoPreset(8);
scenery.getTerrain()->propHeightNoise()->setConfig(0.0);
scenery.getClouds()->clear(); scenery.getClouds()->clear();
scenery.getCamera()->setLocation(VECTOR_ZERO); scenery.getCamera()->setLocation(VECTOR_ZERO);
scenery.getCamera()->setTarget(scenery.getAtmosphere()->childMoon()->getLocation());
scenery.getCamera()->setFov(0.1);
SoftwareCanvasRenderer renderer(&scenery); SoftwareCanvasRenderer renderer(&scenery);
renderer.setSize(600, 600); renderer.setSize(600, 600);
@ -429,25 +428,40 @@ static void testMoonRendering() {
/*SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0); /*SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0);
renderer.setSoloRasterizer(&rasterizer);*/ renderer.setSoloRasterizer(&rasterizer);*/
// During the day scenery.getCamera()->setTarget(scenery.getAtmosphere()->childMoon()->getLocation());
scenery.getCamera()->setFov(0.02);
scenery.getAtmosphere()->setDayTime(17, 30); scenery.getAtmosphere()->setDayTime(17, 30);
startTestRender(&renderer, "moon", 0); startTestRender(&renderer, "celestial_bodies_moon_day");
// At night
scenery.getAtmosphere()->setDayTime(23); scenery.getAtmosphere()->setDayTime(23);
startTestRender(&renderer, "moon", 1); startTestRender(&renderer, "celestial_bodies_moon_night");
// Eclipse scenery.getCamera()->setFov(0.2);
scenery.getAtmosphere()->childSun()->propPhi()->setValue(scenery.getAtmosphere()->childMoon()->propPhi()->getValue());
scenery.getAtmosphere()->childSun()->propTheta()->setValue(scenery.getAtmosphere()->childMoon()->propTheta()->getValue()); scenery.getAtmosphere()->setDayTime(6);
startTestRender(&renderer, "moon", 2); 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() { void runTestSuite() {
testNoise(); testNoise();
testTextures(); testTextures();
testGodRays(); testGodRays();
testMoonRendering(); testCelestialBodies();
testNearFrustum(); testNearFrustum();
testCloudsNearGround(); testCloudsNearGround();
testVegetationModels(); testVegetationModels();

View file

@ -91,8 +91,7 @@ void ModelerCameras::timerEvent(QTimerEvent *) {
void ModelerCameras::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) { void ModelerCameras::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
if (node->getPath().find("/atmosphere/sun/") == 0 and tool_mode == TOOL_SUN) { if (node->getPath().find("/atmosphere/sun/") == 0 and tool_mode == TOOL_SUN) {
Vector3 direction = parent->getRenderer()->getAtmosphereRenderer()->getSunDirection(); tool->setTarget(parent->getRenderer()->getAtmosphereRenderer()->getSunLocation());
tool->setTarget(tool->getLocation().add(direction));
} }
} }

View file

@ -44,7 +44,7 @@ BaseSection {
id: panel_sun_radius id: panel_sun_radius
anchors.left: toolbar.right anchors.left: toolbar.right
minimumValue: 0 minimumValue: 0
maximumValue: 3 maximumValue: 30000000
enabled: false enabled: false
objectName: "atmosphere_sun_radius" objectName: "atmosphere_sun_radius"
} }

View file

@ -5,6 +5,7 @@
#include "OpenGLShaderProgram.h" #include "OpenGLShaderProgram.h"
#include "OpenGLSharedState.h" #include "OpenGLSharedState.h"
#include "OpenGLVertexArray.h" #include "OpenGLVertexArray.h"
#include "CelestialBodyDefinition.h"
#include "Scenery.h" #include "Scenery.h"
#include "AtmosphereDefinition.h" #include "AtmosphereDefinition.h"
#include "AtmosphereRenderer.h" #include "AtmosphereRenderer.h"
@ -82,7 +83,7 @@ void OpenGLSkybox::nodeChanged(const DefinitionNode *node, const DefinitionDiff
AtmosphereDefinition *newdef = renderer->getScenery()->getAtmosphere(); AtmosphereDefinition *newdef = renderer->getScenery()->getAtmosphere();
if (node->getPath() == path_sun_phi or node->getPath() == path_sun_theta) { 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); state->set("sunDirection", sun_direction);
Color sun_color = newdef->sun_color; Color sun_color = newdef->sun_color;
@ -100,6 +101,6 @@ void OpenGLSkybox::floatNodeChanged(const string &path, double new_value, double
if (path == path_humidity) { if (path == path_humidity) {
state->set("atmosphereHumidity", new_value); state->set("atmosphereHumidity", new_value);
} else if (path == path_sun_radius) { } else if (path == path_sun_radius) {
state->set("sunRadius", new_value); state->set("sunRadius", renderer->getScenery()->getAtmosphere()->childSun()->getAngularRadius());
} }
} }

View file

@ -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) */ vec4 transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : vec4(1.0); /* T(x,xo) */
float d = _limit(r, mu); float d = _limit(r, mu);
radius *= (1.0 + 15.0 * d / Rt); /* Inflating due to lens effect near horizon */ 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.r *= isun;
transmittance.g *= isun; transmittance.g *= isun;
transmittance.b *= isun; transmittance.b *= isun;

View file

@ -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) { 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) */ Color transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : COLOR_WHITE; /* T(x,xo) */
double d = _limit(r, mu); double d = _limit(r, mu);
radius *= (1.0 + 15.0 * d / Rt); /* Inflating due to lens effect near horizon */ 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 */ double isun = step(cos(radius), v.dotProduct(s)) * ISun; /* Lsun */
transmittance.r *= isun; transmittance.r *= isun;
transmittance.g *= isun; transmittance.g *= isun;
transmittance.b *= isun; transmittance.b *= isun;
@ -1063,6 +1063,7 @@ AtmosphereModelBruneton::~AtmosphereModelBruneton() {
AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3 &direction, AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3 &direction,
const Vector3 &sun_position, const Color &base) const { 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 x = {0.0, Rg + eye.y * Scenery::UNIT_TO_KM, 0.0};
Vector3 v = direction.normalize(); Vector3 v = direction.normalize();
Vector3 s = sun_position.sub(x).normalize(); Vector3 s = sun_position.sub(x).normalize();
@ -1073,8 +1074,7 @@ AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3
AtmosphereResult result; AtmosphereResult result;
Vector3 attenuation; Vector3 attenuation;
Color sunColor = Color sunColor = _sunColor(v, s, r, mu, definition->childSun()->getAngularRadius()); /* L0 */
_sunColor(v, s, r, mu, parent->getScenery()->getAtmosphere()->childSun()->propRadius()->getValue()); /* L0 */
/*result.base.r = base.r + sunColor.r; /*result.base.r = base.r + sunColor.r;
result.base.g = base.g + sunColor.g; 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 { AtmosphereResult AtmosphereModelBruneton::applyAerialPerspective(Vector3 location, const Color &base) const {
auto definition = parent->getScenery()->getAtmosphere();
Vector3 eye = parent->getCameraLocation(); Vector3 eye = parent->getCameraLocation();
eye.y = max(eye.y, 0.0); eye.y = max(eye.y, 0.0);
location.y = max(location.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); Vector3 direction = location.sub(eye).scale(Scenery::UNIT_TO_KM);
double t = direction.getNorm(); double t = direction.getNorm();
@ -1134,6 +1135,7 @@ AtmosphereResult AtmosphereModelBruneton::applyAerialPerspective(Vector3 locatio
} }
bool AtmosphereModelBruneton::getLightsAt(vector<LightComponent> &result, const Vector3 &location) const { bool AtmosphereModelBruneton::getLightsAt(vector<LightComponent> &result, const Vector3 &location) const {
auto definition = parent->getScenery()->getAtmosphere();
LightComponent sun, irradiance; LightComponent sun, irradiance;
double muS; double muS;
@ -1141,13 +1143,13 @@ bool AtmosphereModelBruneton::getLightsAt(vector<LightComponent> &result, const
double r0 = Rg + WORKAROUND_OFFSET + altitude; double r0 = Rg + WORKAROUND_OFFSET + altitude;
Vector3 up = {0.0, 1.0, 0.0}; 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 x = {0.0, r0, 0.0};
Vector3 s = sun_position.sub(x).normalize(); Vector3 s = sun_position.sub(x).normalize();
muS = up.dotProduct(s); muS = up.dotProduct(s);
if (altitude > RL) { if (altitude > RL) {
sun.color = parent->getScenery()->getAtmosphere()->sun_color; sun.color = definition->sun_color;
} else { } else {
sun.color = _transmittanceWithShadow(r0, muS); sun.color = _transmittanceWithShadow(r0, muS);
} }

View file

@ -80,6 +80,10 @@ AtmosphereResult BaseAtmosphereRenderer::getSkyColor(const Vector3 &) {
return result; return result;
} }
Vector3 BaseAtmosphereRenderer::getSunLocation() const {
return getDefinition()->childSun()->getLocation();
}
Vector3 BaseAtmosphereRenderer::getSunDirection() const { Vector3 BaseAtmosphereRenderer::getSunDirection() const {
auto sun_location = getDefinition()->childSun()->getLocation(); auto sun_location = getDefinition()->childSun()->getLocation();
return sun_location.sub(parent->getCameraLocation()).normalize(); return sun_location.sub(parent->getCameraLocation()).normalize();
@ -127,15 +131,14 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::applyAerialPerspective(cons
AtmosphereResult SoftwareBrunetonAtmosphereRenderer::getSkyColor(const Vector3 &direction) { AtmosphereResult SoftwareBrunetonAtmosphereRenderer::getSkyColor(const Vector3 &direction) {
AtmosphereDefinition *definition; AtmosphereDefinition *definition;
Vector3 sun_direction, sun_position, camera_location; Vector3 sun_position, camera_location;
Color base; Color base;
definition = getDefinition(); definition = getDefinition();
camera_location = parent->getCameraLocation(); camera_location = parent->getCameraLocation();
sun_direction = getSunDirection();
Vector3 direction_norm = direction.normalize(); Vector3 direction_norm = direction.normalize();
sun_position = sun_direction.scale(Scenery::SUN_DISTANCE_SCALED); sun_position = getSunLocation();
base = COLOR_BLACK; base = COLOR_BLACK;
@ -145,7 +148,7 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::getSkyColor(const Vector3 &
// Get sun shape // Get sun shape
/*if (v3Dot(sun_direction, direction) >= 0) /*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; Vector3 hit1, hit2;
int hits = euclidRayIntersectSphere(camera_location, direction, sun_position, sun_radius, &hit1, &hit2); int hits = euclidRayIntersectSphere(camera_location, direction, sun_position, sun_radius, &hit1, &hit2);
if (hits > 1) if (hits > 1)

View file

@ -17,6 +17,7 @@ class BaseAtmosphereRenderer : public LightSource {
virtual AtmosphereResult applyAerialPerspective(const Vector3 &location, const Color &base); virtual AtmosphereResult applyAerialPerspective(const Vector3 &location, const Color &base);
virtual AtmosphereResult getSkyColor(const Vector3 &direction); virtual AtmosphereResult getSkyColor(const Vector3 &direction);
virtual Vector3 getSunDirection() const; virtual Vector3 getSunDirection() const;
virtual Vector3 getSunLocation() const;
virtual bool getLightsAt(vector<LightComponent> &result, const Vector3 &location) const override; virtual bool getLightsAt(vector<LightComponent> &result, const Vector3 &location) const override;

View file

@ -55,8 +55,7 @@ const Color NightSky::getColor(double altitude, const Vector3 &direction) {
Vector3 moon_position = atmosphere->childMoon()->getLocation(); Vector3 moon_position = atmosphere->childMoon()->getLocation();
Vector3 moon_direction = moon_position.sub(renderer->getCameraLocation()).normalize(); Vector3 moon_direction = moon_position.sub(renderer->getCameraLocation()).normalize();
if (moon_direction.dotProduct(direction) >= 0) { if (moon_direction.dotProduct(direction) >= 0) {
// TODO Why need the multiplier ? double moon_radius = atmosphere->childMoon()->propRadius()->getValue();
double moon_radius = atmosphere->childMoon()->propRadius()->getValue() * 5.0;
Vector3 hit1, hit2; Vector3 hit1, hit2;
int hits = Geometry::rayIntersectSphere(location, direction, moon_position, moon_radius, &hit1, &hit2); int hits = Geometry::rayIntersectSphere(location, direction, moon_position, moon_radius, &hit1, &hit2);
if (hits > 1) { if (hits > 1) {

View file

@ -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());
}