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.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);

View file

@ -1,5 +1,6 @@
#include "CelestialBodyDefinition.h"
#include <cmath>
#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());
}

View file

@ -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;

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_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;

View file

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

View file

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

View file

@ -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"
}

View file

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

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) */
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;

View file

@ -862,7 +862,7 @@ 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 */
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<LightComponent> &result, const Vector3 &location) const {
auto definition = parent->getScenery()->getAtmosphere();
LightComponent sun, irradiance;
double muS;
@ -1141,13 +1143,13 @@ bool AtmosphereModelBruneton::getLightsAt(vector<LightComponent> &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);
}

View file

@ -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)

View file

@ -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<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_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) {

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