MR104: Added the Milky Way onto the night sky
From Chris RINGEVAL Squashed commit of the following: commit ee2ec625ef10ab372a99397a82d1272670d767ec Author: Chris Ringeval <eatdirt@protonmail.com> Date: Mon Jan 31 00:01:39 2022 +0100 Replace galaxy texture by our own and update galactic coordinates commit 26f3d80df6385913668635013912f1c4fef50e60 Author: Chris Ringeval <eatdirt@protonmail.com> Date: Tue Dec 7 22:02:10 2021 +0100 Cleanup white lines and comments commit 55e9f9b4bcbe21a34be7be874b120bda73c49cb8 Author: Chris Ringeval <eatdirt@protonmail.com> Date: Sun Dec 5 15:53:15 2021 +0100 Cleanup cxx parts to the minimal required, moving all rendering to the shaders commit 0cff2827bb3c18f85780cce5c0178ee37c590fe5 Author: Chris Ringeval <eatdirt@protonmail.com> Date: Wed Dec 1 22:55:41 2021 +0100 Adding moon direction uniform vector used in the Milky Way shader commit 24485079673c299bad95fc1f800542a6d73e8e95 Author: Chris Ringeval <eatdirt@protonmail.com> Date: Wed Dec 1 22:54:54 2021 +0100 Adding Milky Way texturing and dark sky brightness effects
This commit is contained in:
parent
a6624b8c89
commit
28e2ccda01
@ -11,6 +11,7 @@ set(HEADERS
|
||||
sky.hxx
|
||||
sphere.hxx
|
||||
stars.hxx
|
||||
galaxy.hxx
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
@ -24,6 +25,7 @@ set(SOURCES
|
||||
sky.cxx
|
||||
sphere.cxx
|
||||
stars.cxx
|
||||
galaxy.cxx
|
||||
)
|
||||
|
||||
simgear_scene_component(sky scene/sky "${SOURCES}" "${HEADERS}")
|
||||
|
225
simgear/scene/sky/galaxy.cxx
Normal file
225
simgear/scene/sky/galaxy.cxx
Normal file
@ -0,0 +1,225 @@
|
||||
// galaxy.cxx -- model the celestial sphere brightness by unresolved
|
||||
// sources, i.e. the milky way and its nebulae: our Galaxy
|
||||
//
|
||||
// Started November 2021 (Chris Ringeval)
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
// 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <osg/Array>
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/CullFace>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Node>
|
||||
#include <osg/ShadeModel>
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/screen/colors.hxx>
|
||||
#include <simgear/scene/model/model.hxx>
|
||||
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
|
||||
#include <simgear/scene/material/Effect.hxx>
|
||||
#include <simgear/scene/material/EffectGeode.hxx>
|
||||
|
||||
#include "sphere.hxx"
|
||||
#include "galaxy.hxx"
|
||||
|
||||
using namespace simgear;
|
||||
|
||||
// Constructor
|
||||
SGGalaxy::SGGalaxy( SGPropertyNode* props )
|
||||
{
|
||||
if (props) {
|
||||
_magDarkSkyProperty = props->getNode("darksky-brightness-magnitude");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Destructor
|
||||
SGGalaxy::~SGGalaxy( void ) {
|
||||
}
|
||||
|
||||
|
||||
// build the galaxy sphere object
|
||||
osg::Node*
|
||||
SGGalaxy::build( SGPath path, double galaxy_size, simgear::SGReaderWriterOptions *options ) {
|
||||
|
||||
simgear::EffectGeode* orb = SGMakeSphere(galaxy_size, 64, 32);
|
||||
|
||||
Effect *effect = makeEffect("Effects/galaxy", true, options);
|
||||
if (effect) {
|
||||
orb->setEffect(effect);
|
||||
}
|
||||
|
||||
// set up the orb state
|
||||
osg::StateSet* stateSet = orb->getOrCreateStateSet();
|
||||
stateSet->setRenderBinDetails(-9, "RenderBin");
|
||||
|
||||
osg::ref_ptr<SGReaderWriterOptions> poptions;
|
||||
poptions = SGReaderWriterOptions::fromPath(path);
|
||||
|
||||
osg::Texture2D* texture = SGLoadTexture2D("allsky_brightness_magten.png", poptions.get(),true,true);
|
||||
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||
|
||||
stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
|
||||
|
||||
osg::TexEnv* texEnv = new osg::TexEnv;
|
||||
texEnv->setMode(osg::TexEnv::MODULATE);
|
||||
stateSet->setTextureAttribute(0, texEnv, osg::StateAttribute::ON);
|
||||
|
||||
osg::ShadeModel* shadeModel = new osg::ShadeModel;
|
||||
shadeModel->setMode(osg::ShadeModel::SMOOTH);
|
||||
stateSet->setAttributeAndModes(shadeModel);
|
||||
|
||||
osg::BlendFunc* blendFunc = new osg::BlendFunc;
|
||||
blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE);
|
||||
stateSet->setAttributeAndModes(blendFunc);
|
||||
|
||||
// needed shader side
|
||||
zenith_brightness_magnitude = new osg::Uniform("fg_ZenithSkyBrightness", 0.0f);
|
||||
stateSet->addUniform(zenith_brightness_magnitude);
|
||||
|
||||
// force a repaint of the galaxy colors with arbitrary defaults
|
||||
repaint( 0.0, 0.0 );
|
||||
|
||||
// build the scene graph sub tree for the Galaxy
|
||||
galaxy_transform = new osg::MatrixTransform;
|
||||
galaxy_transform->addChild( orb );
|
||||
|
||||
// reposition the Galaxy's texture, which is in galactic
|
||||
// coordinates, into the "fake" geocentric frame (which is carried
|
||||
// along our current position (p))
|
||||
//
|
||||
// Coordinates of the galactic north pole used with Gaia data (from
|
||||
// which our Milky Way Texture is built).
|
||||
//
|
||||
// https://www.cosmos.esa.int/web/gaia-users/archive/gedr3-documentation-pdf
|
||||
// Section 4.1.7.1 page 198
|
||||
|
||||
const double galactic_north_pole_RA = 192.85948;
|
||||
const double galactic_north_pole_DEC = 27.12825;
|
||||
const double equatorial_north_pole_THETA = 122.93192;
|
||||
|
||||
osg::Matrix RA, DEC, THETA;
|
||||
|
||||
// RA origin at 90 degrees
|
||||
RA.makeRotate((galactic_north_pole_RA-90.0)*SGD_DEGREES_TO_RADIANS, osg::Vec3(0, 0, 1));
|
||||
// Rotate along rotated x-axis by -(90-DEC)
|
||||
DEC.makeRotate((galactic_north_pole_DEC-90.0)*SGD_DEGREES_TO_RADIANS, osg::Vec3(1, 0, 0));
|
||||
// Set the origin of the galactic longitude in Sagittarius, rotate
|
||||
// along rotated z-axis by -theta
|
||||
THETA.makeRotate(-equatorial_north_pole_THETA*SGD_DEGREES_TO_RADIANS, osg::Vec3(0, 0, 1));
|
||||
|
||||
galaxy_transform->setMatrix(THETA*DEC*RA);
|
||||
|
||||
return galaxy_transform.get();
|
||||
}
|
||||
|
||||
|
||||
// Basic evaluation of the dark sky brightness magnitude at zenith,
|
||||
// according to the sun angles above the horizon. The actual painting
|
||||
// and coloring of the Galaxy is done within the shaders using this
|
||||
// value as a starting point, and adding angular dependent scattering
|
||||
// and Moon illumation effects when relevant. The idea being that the
|
||||
// intrinsic Galaxy brightness is eventually masked by the brightness
|
||||
// of the atmosphere and we do see their relative contrast
|
||||
bool SGGalaxy::repaint( double sun_angle, double altitude_m ) {
|
||||
|
||||
osg::Vec4 rhodcolor;
|
||||
|
||||
double sundeg;
|
||||
double mindeg;
|
||||
|
||||
double mudarksky;
|
||||
double musky;
|
||||
|
||||
// same as moon.cxx
|
||||
const double earth_radius_in_meters = 6371000.0;
|
||||
|
||||
//sundeg is elevation above the horizon
|
||||
sundeg = 90.0 - sun_angle * SGD_RADIANS_TO_DEGREES;
|
||||
|
||||
// mindeg is the elevation above the horizon at which the sun is
|
||||
// no longer obstructed by the Earth (mindeg <= 0)
|
||||
mindeg = 0.0;
|
||||
if (altitude_m >=0) {
|
||||
mindeg = -90.0 + SGD_RADIANS_TO_DEGREES * asin(earth_radius_in_meters/(altitude_m + earth_radius_in_meters));
|
||||
}
|
||||
|
||||
// the darkest possible value of the sky brightness at zenith
|
||||
// (darker = larger number). If a prop is defined, we use it, or we
|
||||
// default to the one coded here (should be 22 for the darkest skies
|
||||
// on Earth)
|
||||
if (_magDarkSkyProperty) {
|
||||
mudarksky = _magDarkSkyProperty->getDoubleValue();
|
||||
}
|
||||
else {
|
||||
mudarksky = _magDarkSkyDefault;
|
||||
}
|
||||
|
||||
// initializing sky brightness to a lot
|
||||
musky = 0.0;
|
||||
|
||||
// in space, we either have sun in the face or not. If sundeg >=
|
||||
// mindeg, the sun is visible, we see nothing, then we do
|
||||
// nothing. Otherwise, we have
|
||||
if (sundeg <= mindeg) {
|
||||
|
||||
// sun illumination of the atmosphere at zenith (fit to SQM zenital measurements)
|
||||
// from http://www.hnsky.org/sqm_twilight.htm, slightly modified
|
||||
// to be continuous at 0deg, -12deg and -18deg
|
||||
// musky is in magV / arcsec^2
|
||||
if ( (sundeg >= -12.0) && (sundeg < 0.0) ) {
|
||||
musky = - 1.057*sundeg + mudarksky - 14.7528;
|
||||
}
|
||||
|
||||
if ( (sundeg >= -18.0 ) && (sundeg < -12.0) ) {
|
||||
musky = -0.0744*sundeg*sundeg - 2.5768*sundeg + mudarksky - 22.2768;
|
||||
musky = min(musky,mudarksky);
|
||||
}
|
||||
|
||||
if ( sundeg < -18.0) {
|
||||
musky = mudarksky;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//cout << "sundeg= " << sundeg << endl;
|
||||
//cout << "mindeg= " << mindeg << endl;
|
||||
//cout << "altitude= " << altitude_m << endl;
|
||||
//cout << "musky= mudarksky= " << musky <<" "<<mudarksky << endl;
|
||||
|
||||
//the uniform feeding the shaders
|
||||
zenith_brightness_magnitude->set((float)musky);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
65
simgear/scene/sky/galaxy.hxx
Normal file
65
simgear/scene/sky/galaxy.hxx
Normal file
@ -0,0 +1,65 @@
|
||||
// galaxy.cxx -- model the celestial sphere brightness by unresolved
|
||||
// sources, i.e. the milky way and its nebulae: our Galaxy
|
||||
//
|
||||
// Started November 2021 (Chris Ringeval)
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
|
||||
#ifndef _SG_GALAXY_HXX_
|
||||
#define _SG_GALAXY_HXX_
|
||||
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/Material>
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
|
||||
class SGGalaxy : public SGReferenced {
|
||||
|
||||
osg::ref_ptr<osg::MatrixTransform> galaxy_transform;
|
||||
osg::ref_ptr<osg::Uniform> zenith_brightness_magnitude;
|
||||
|
||||
SGPropertyNode_ptr _magDarkSkyProperty;
|
||||
|
||||
// the darkest sky at zenith has a brightness equals to (in
|
||||
// magnitude per arcsec^2 for the V band)
|
||||
const double _magDarkSkyDefault = 22.0;
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
SGGalaxy( SGPropertyNode* props = nullptr );
|
||||
|
||||
// Destructor
|
||||
~SGGalaxy( void );
|
||||
|
||||
// build the galaxy object
|
||||
osg::Node *build( SGPath path, double galaxy_size, simgear::SGReaderWriterOptions *options);
|
||||
|
||||
// basic repainting according to sky lighting
|
||||
bool repaint( double sun_angle, double altitude_m );
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // _SG_GALAXY_HXX_
|
@ -100,13 +100,16 @@ void SGSky::build( double h_radius_m,
|
||||
|
||||
stars = new SGStars(property_tree_node);
|
||||
_ephTransform->addChild( stars->build(eph.getNumStars(), eph.getStars(), h_radius_m, options) );
|
||||
|
||||
galaxy = new SGGalaxy(property_tree_node);
|
||||
_ephTransform->addChild( galaxy->build(tex_path, h_radius_m, options) );
|
||||
|
||||
moon = new SGMoon;
|
||||
_ephTransform->addChild( moon->build(tex_path, moon_size) );
|
||||
|
||||
oursun = new SGSun;
|
||||
_ephTransform->addChild( oursun->build(tex_path, sun_size, property_tree_node ) );
|
||||
|
||||
|
||||
pre_root->addChild( pre_transform.get() );
|
||||
}
|
||||
|
||||
@ -123,10 +126,11 @@ bool SGSky::repaint( const SGSkyColor &sc, const SGEphemeris& eph )
|
||||
dome->repaint( sc.adj_sky_color, sc.sky_color, sc.fog_color,
|
||||
sc.sun_angle, effective_visibility );
|
||||
|
||||
stars->repaint( sc.sun_angle, eph.getNumStars(), eph.getStars() );
|
||||
planets->repaint( sc.sun_angle, eph.getNumPlanets(), eph.getPlanets() );
|
||||
stars->repaint( sc.sun_angle, sc.altitude_m, eph.getNumStars(), eph.getStars() );
|
||||
planets->repaint( sc.sun_angle, sc.altitude_m, eph.getNumPlanets(), eph.getPlanets() );
|
||||
oursun->repaint( sc.sun_angle, effective_visibility );
|
||||
moon->repaint( sc.moon_angle );
|
||||
galaxy->repaint( sc.sun_angle, sc.altitude_m );
|
||||
|
||||
for ( unsigned i = 0; i < cloud_layers.size(); ++i ) {
|
||||
if (cloud_layers[i]->getCoverage() != SGCloudLayer::SG_CLOUD_CLEAR){
|
||||
@ -186,7 +190,7 @@ bool SGSky::reposition( const SGSkyState &st, const SGEphemeris& eph, double dt
|
||||
//moon is closer to the center of Earth, times any articial extra factors
|
||||
double moon_dist_factor = moon_r * st.moon_dist_factor;
|
||||
moon->reposition( moon_ra, moon_dec, st.moon_dist_bare, moon_dist_factor, lst, lat, alt );
|
||||
|
||||
|
||||
for ( unsigned i = 0; i < cloud_layers.size(); ++i ) {
|
||||
if ( cloud_layers[i]->getCoverage() != SGCloudLayer::SG_CLOUD_CLEAR ||
|
||||
cloud_layers[i]->get_layer3D()->isDefined3D() ) {
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <simgear/scene/sky/moon.hxx>
|
||||
#include <simgear/scene/sky/oursun.hxx>
|
||||
#include <simgear/scene/sky/stars.hxx>
|
||||
#include <simgear/scene/sky/galaxy.hxx>
|
||||
|
||||
namespace simgear {
|
||||
class SGReaderWriterOptions;
|
||||
@ -75,7 +76,7 @@ struct SGSkyColor
|
||||
SGVec3f fog_color;
|
||||
SGVec3f cloud_color;
|
||||
double sun_angle,
|
||||
moon_angle;
|
||||
moon_angle, altitude_m;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -224,6 +225,7 @@ private:
|
||||
SGSharedPtr<SGMoon> moon;
|
||||
SGSharedPtr<SGStars> planets;
|
||||
SGSharedPtr<SGStars> stars;
|
||||
SGSharedPtr<SGGalaxy> galaxy;
|
||||
layer_list_type cloud_layers;
|
||||
|
||||
osg::ref_ptr<osg::Group> pre_root, pre_transform;
|
||||
|
@ -31,19 +31,19 @@
|
||||
|
||||
#include <osg/Node>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Array>
|
||||
|
||||
#include <simgear/scene/material/EffectGeode.hxx>
|
||||
|
||||
// return a sphere object as an ssgBranch
|
||||
osg::Node*
|
||||
simgear::EffectGeode*
|
||||
SGMakeSphere(double radius, int slices, int stacks)
|
||||
{
|
||||
float rho, drho, dtheta;
|
||||
float s, t, ds, dt;
|
||||
int i, j, imin, imax;
|
||||
float nsign = 1.0;
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
simgear::EffectGeode* geode = new simgear::EffectGeode;
|
||||
|
||||
drho = SGD_PI / (float) stacks;
|
||||
dtheta = SGD_2PI / (float) slices;
|
||||
|
@ -23,9 +23,10 @@
|
||||
|
||||
|
||||
#include <osg/Node>
|
||||
#include <simgear/scene/material/EffectGeode.hxx>
|
||||
|
||||
// return a sphere object as an ssgBranch (and connect in the
|
||||
// specified ssgSimpleState
|
||||
osg::Node* SGMakeSphere(double radius, int slices, int stacks);
|
||||
simgear::EffectGeode* SGMakeSphere(double radius, int slices, int stacks);
|
||||
|
||||
|
||||
|
@ -7,6 +7,11 @@
|
||||
//
|
||||
// Separated out rendering pieces and converted to ssg by Curt Olson,
|
||||
// March 2000
|
||||
//
|
||||
// Switch to sky brightness as a mean to sort visible stars to be
|
||||
// consistent with Milky Way visibility, can be modified from the
|
||||
// property tree from local lighting environment
|
||||
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
@ -58,9 +63,9 @@ SGStars::SGStars( SGPropertyNode* props ) :
|
||||
old_phase(-1)
|
||||
{
|
||||
if (props) {
|
||||
// don't create here - if it's not defined, we won't use the cutoff
|
||||
// don't create here - if it's not defined, we won't use the value
|
||||
// from a property
|
||||
_cutoffProperty = props->getNode("star-magnitude-cutoff");
|
||||
_magDarkSkyProperty = props->getNode("darksky-brightness-magnitude");
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,89 +141,155 @@ SGStars::build( int num, const SGVec3d star_data[], double star_dist,
|
||||
// 0 degrees = high noon
|
||||
// 90 degrees = sun rise/set
|
||||
// 180 degrees = darkest midnight
|
||||
|
||||
bool SGStars::repaint( double sun_angle, int num, const SGVec3d star_data[] )
|
||||
bool SGStars::repaint( double sun_angle, double altitude_m, int num, const SGVec3d star_data[] )
|
||||
{
|
||||
double mag, nmag, alpha, factor, cutoff;
|
||||
|
||||
double mag, nmag, alpha, factor, cutoff;
|
||||
|
||||
/*
|
||||
maximal magnitudes under dark sky on Earth, from Eq.(90) and (91) of astro-ph/1405.4209
|
||||
For (18 < musky < 20)
|
||||
mmax = 0.27 musky + 0.8 - 2.5 * log(F)
|
||||
double magmax;
|
||||
double sundeg, mindeg;
|
||||
double musky, mudarksky;
|
||||
|
||||
For (19.5 µsky 22)
|
||||
mmax = 0.383 musky - 1.44 - 2.5 * log(F)
|
||||
//observer visual acuity in the model used below (F=2)
|
||||
const double logF = 0.30;
|
||||
|
||||
// same as moon.cxx
|
||||
const double earth_radius_in_meters = 6371000.0;
|
||||
|
||||
//sundeg is elevation above the horizon
|
||||
sundeg = 90.0 - sun_angle * SGD_RADIANS_TO_DEGREES;
|
||||
|
||||
// mindeg is the elevation above the horizon at which the sun is
|
||||
// no longer obstructed by the Earth (mindeg <= 0)
|
||||
mindeg = 0.0;
|
||||
if (altitude_m >=0) {
|
||||
mindeg = -90.0 + SGD_RADIANS_TO_DEGREES * asin(earth_radius_in_meters/(altitude_m + earth_radius_in_meters));
|
||||
}
|
||||
// if the prop exists, let's use its value, can be real time changed
|
||||
// due to lighting conditions. Otherwise, we use the default
|
||||
if (_magDarkSkyProperty) {
|
||||
mudarksky = _magDarkSkyProperty->getDoubleValue();
|
||||
}
|
||||
else {
|
||||
mudarksky = _magDarkSkyDefault;
|
||||
}
|
||||
|
||||
// initializing sky brightness to a lot
|
||||
musky = 0.0;
|
||||
|
||||
// same as in galaxy.cxx
|
||||
// in space, we either have the sun in the face or not. If sundeg >= mindeg,
|
||||
// the sun is visible, we see nothing. Otherwise we have:
|
||||
if (sundeg <= mindeg) {
|
||||
|
||||
// same little model as galaxy.cxx, sun illumination of the
|
||||
// atmosphere at zenith (fit to SQM zenital measurements) from
|
||||
// http://www.hnsky.org/sqm_twilight.htm, slightly modified to be
|
||||
// continuous at 0deg, -12deg and -18deg musky is in magV /
|
||||
// arcsec^2
|
||||
|
||||
Let's take F = 1.4 for healthy young pilot
|
||||
mudarksky ~ 22 mag/arcsec^2 => mmax=6.2
|
||||
muastrotwilight ~ 20 mag/arsec^2 => mmax=5.4
|
||||
mu99deg ~ 17.5 mag/arcsec^2 => mmax=4.7
|
||||
mu97.5deg ~ 16 mag/arcsec^2 => ? let's keep it rough
|
||||
*/
|
||||
if ( (sundeg >= -12.0) && (sundeg < 0.0) ) {
|
||||
musky = - 1.057*sundeg + mudarksky - 14.7528;
|
||||
}
|
||||
|
||||
if ( (sundeg >= -18.0 ) && (sundeg < -12.0) ) {
|
||||
musky = -0.0744*sundeg*sundeg - 2.5768*sundeg + mudarksky - 22.2768;
|
||||
musky = min(musky,mudarksky);
|
||||
}
|
||||
|
||||
double mag_nakedeye = 6.2;
|
||||
double mag_twilight_astro = 5.4;
|
||||
double mag_twilight_nautic = 4.7;
|
||||
if ( sundeg < -18.0) {
|
||||
musky = mudarksky;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Simple relation between maximal star magnitudes visible by the
|
||||
// naked eye on Earth, from Eq.(90) and (91) of astro-ph/1405.4209
|
||||
//
|
||||
// For 19.5 < musky < 22
|
||||
// mmax = 0.3834 musky - 1.4400 - 2.5 * log(F)
|
||||
//
|
||||
// For 18 < musky < 20
|
||||
// mmax = 0.270 musky _0.8 - 2.5 * log(F)
|
||||
//
|
||||
// Typical values, let's take F = 2 for healthy pilot. With mudarksky ~ 22
|
||||
// mag/arcsec^2 => mmax=6.2
|
||||
//
|
||||
// We use these linear formulae and switch from one to the other at
|
||||
// their intersection point
|
||||
|
||||
if (musky >= 19.823) {
|
||||
magmax = 0.383 * musky - 1.44 - 2.5 * logF;
|
||||
}
|
||||
else {
|
||||
//extrapolated to all bright (small) musky values
|
||||
magmax = 0.270 * musky + 0.80 - 2.5 * logF;
|
||||
}
|
||||
|
||||
// sirius, brightest star (not brightest object)
|
||||
double mag_min = -1.46;
|
||||
|
||||
int phase;
|
||||
|
||||
// determine which star structure to draw
|
||||
if ( sun_angle > (SGD_PI_2 + 18.0 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
//continously changed at each call to repaint, but we use "phase"
|
||||
//to actually check for repainting, not magmax
|
||||
|
||||
cutoff = magmax;
|
||||
|
||||
// determine which star structure to draw when the sun is not
|
||||
// directly visible
|
||||
if (sundeg <= mindeg) {
|
||||
if ( sun_angle > (SGD_PI_2 + 18.0 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
// deep night, atmosphere is not lighten by the sun
|
||||
factor = 1.0;
|
||||
cutoff = mag_nakedeye;
|
||||
phase = 0;
|
||||
} else if ( sun_angle > (SGD_PI_2 + 12.0 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
} else if ( sun_angle > (SGD_PI_2 + 12.0 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
// less than 18deg and more than 12deg is astronomical twilight
|
||||
factor = 1.0;
|
||||
cutoff = mag_twilight_astro;
|
||||
phase = 1;
|
||||
} else if ( sun_angle > (SGD_PI_2 + 9.0 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
} else if ( sun_angle > (SGD_PI_2 + 9.0 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
// less 12deg and more than 6deg is is nautical twilight
|
||||
factor = 1.0;
|
||||
cutoff = mag_twilight_nautic;
|
||||
phase = 2;
|
||||
} else if ( sun_angle > (SGD_PI_2 + 7.5 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
} else if ( sun_angle > (SGD_PI_2 + 7.5 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
factor = 0.95;
|
||||
cutoff = 3.1;
|
||||
phase = 3;
|
||||
} else if ( sun_angle > (SGD_PI_2 + 7.0 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
} else if ( sun_angle > (SGD_PI_2 + 7.0 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
factor = 0.9;
|
||||
cutoff = 2.4;
|
||||
phase = 4;
|
||||
} else if ( sun_angle > (SGD_PI_2 + 6.5 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
} else if ( sun_angle > (SGD_PI_2 + 6.5 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
factor = 0.85;
|
||||
cutoff = 1.8;
|
||||
phase = 5;
|
||||
} else if ( sun_angle > (SGD_PI_2 + 6.0 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
} else if ( sun_angle > (SGD_PI_2 + 6.0 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
factor = 0.8;
|
||||
cutoff = 1.2;
|
||||
phase = 6;
|
||||
} else if ( sun_angle > (SGD_PI_2 + 5.5 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
} else if ( sun_angle > (SGD_PI_2 + 5.5 * SGD_DEGREES_TO_RADIANS ) ) {
|
||||
factor = 0.75;
|
||||
cutoff = 0.6;
|
||||
phase = 7;
|
||||
} else {
|
||||
} else {
|
||||
// early dusk or late dawn
|
||||
factor = 0.7;
|
||||
cutoff = 0.0;
|
||||
phase = 8;
|
||||
}
|
||||
} else {
|
||||
// at large altitudes (in space), this conditional is triggered
|
||||
// for sun >=mindeg, the sun is directly visible, let's call it
|
||||
// phase 9
|
||||
factor = 1.0;
|
||||
cutoff = 0.0;
|
||||
phase = 9;
|
||||
}
|
||||
|
||||
if (_cutoffProperty) {
|
||||
double propCutoff = _cutoffProperty->getDoubleValue();
|
||||
cutoff = std::min(propCutoff, cutoff);
|
||||
}
|
||||
// repaint only for change of phase or if darksky property has been changed
|
||||
|
||||
if ((phase != old_phase) || (cutoff != _cachedCutoff)) {
|
||||
// cout << " phase change, repainting stars, num = " << num << endl;
|
||||
if ((phase != old_phase) || (mudarksky != _cachedMagDarkSky)) {
|
||||
old_phase = phase;
|
||||
_cachedCutoff = cutoff;
|
||||
_cachedMagDarkSky = mudarksky;
|
||||
|
||||
//cout << " phase change -> repainting stars, num = " << num << endl;
|
||||
//cout << "mudarksky= musky= cutoff= " << mudarksky << " " << musky << " " << cutoff << endl;
|
||||
|
||||
for ( int i = 0; i < num; ++i ) {
|
||||
// if ( star_data[i][2] < min ) { min = star_data[i][2]; }
|
||||
// if ( star_data[i][2] > max ) { max = star_data[i][2]; }
|
||||
@ -232,7 +303,14 @@ bool SGStars::repaint( double sun_angle, int num, const SGVec3d star_data[] )
|
||||
mag = star_data[i][2];
|
||||
if ( mag < cutoff ) {
|
||||
nmag = ( cutoff - mag ) / (cutoff - mag_min); // translate to 0 ... 1.0 scale
|
||||
alpha = nmag * 0.85 + 0.15; // translate to a 0.15 ... 1.0 scale
|
||||
//with Milky Way on, it is more realistic to make the
|
||||
//stars fainting to total darkness when matching the
|
||||
//background sky brightness
|
||||
//
|
||||
//alpha = nmag * 0.85 + 0.15; //
|
||||
//translate to a 0.15 ... 1.0 scale
|
||||
//
|
||||
alpha = nmag;
|
||||
alpha *= factor; // dim when the sun is brighter
|
||||
} else {
|
||||
alpha = 0.0;
|
||||
|
@ -44,9 +44,14 @@ class SGStars : public SGReferenced {
|
||||
osg::ref_ptr<osg::Vec4Array> cl;
|
||||
|
||||
int old_phase; // data for optimization
|
||||
|
||||
double _cachedCutoff = 0.0;
|
||||
SGPropertyNode_ptr _cutoffProperty;
|
||||
|
||||
// the darkest sky at zenith has a brightness equals to (in
|
||||
// magnitude per arcsec^2 for the V band)
|
||||
const double _magDarkSkyDefault = 22.0;
|
||||
|
||||
double _cachedMagDarkSky = 0.0;
|
||||
SGPropertyNode_ptr _magDarkSkyProperty;
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
@ -59,13 +64,13 @@ public:
|
||||
osg::Node* build( int num, const SGVec3d star_data[], double star_dist,
|
||||
simgear::SGReaderWriterOptions* options );
|
||||
|
||||
// repaint the planet magnitudes based on current value of
|
||||
// repaint the star and planet magnitudes based on current value of
|
||||
// sun_angle in degrees relative to verticle (so we can make them
|
||||
// relatively dimmer during dawn and dusk
|
||||
// 0 degrees = high noon
|
||||
// 90 degrees = sun rise/set
|
||||
// 180 degrees = darkest midnight
|
||||
bool repaint( double sun_angle, int num, const SGVec3d star_data[] );
|
||||
bool repaint( double sun_angle, double altitude_m, int num, const SGVec3d star_data[] );
|
||||
};
|
||||
|
||||
|
||||
|
@ -108,11 +108,13 @@ public:
|
||||
const SGVec3d& getHorizLocalDown() const
|
||||
{ return mHorizLocalDown; }
|
||||
|
||||
void setLight(const SGVec3f& direction, const SGVec4f& ambient,
|
||||
void setLight(const SGVec3f& sundirection, const SGVec3f& moondirection,
|
||||
const SGVec4f& ambient,
|
||||
const SGVec4f& diffuse, const SGVec4f& specular,
|
||||
const SGVec4f& fogColor, double sunAngleDeg)
|
||||
{
|
||||
mLightDirection = direction;
|
||||
mLightDirection = sundirection;
|
||||
mSecondLightDirection = moondirection;
|
||||
mAmbientLight = ambient;
|
||||
mDiffuseLight = diffuse;
|
||||
mSpecularLight = specular;
|
||||
@ -122,6 +124,8 @@ public:
|
||||
|
||||
const SGVec3f& getLightDirection() const
|
||||
{ return mLightDirection; }
|
||||
const SGVec3f& getSecondLightDirection() const
|
||||
{ return mSecondLightDirection; }
|
||||
const SGVec4f& getAmbientLight() const
|
||||
{ return mAmbientLight; }
|
||||
const SGVec4f& getDiffuseLight() const
|
||||
@ -217,6 +221,7 @@ private:
|
||||
double mGroundLightsFogExp2Density;
|
||||
|
||||
SGVec3f mLightDirection;
|
||||
SGVec3f mSecondLightDirection;
|
||||
SGVec4f mAmbientLight;
|
||||
SGVec4f mDiffuseLight;
|
||||
SGVec4f mSpecularLight;
|
||||
|
@ -50,6 +50,16 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class MoonDirectionWorldCallback : public osg::Uniform::Callback {
|
||||
public:
|
||||
virtual void operator()(osg::Uniform *uniform, osg::NodeVisitor *nv) {
|
||||
SGUpdateVisitor *uv = dynamic_cast<SGUpdateVisitor *>(nv);
|
||||
osg::Vec3f l = toOsg(uv->getSecondLightDirection());
|
||||
l.normalize();
|
||||
uniform->set(l);
|
||||
}
|
||||
};
|
||||
|
||||
namespace simgear {
|
||||
namespace compositor {
|
||||
|
||||
@ -155,11 +165,16 @@ Compositor::Compositor(osg::View *view,
|
||||
new osg::Uniform("fg_SunDirection", osg::Vec3f()),
|
||||
new osg::Uniform("fg_SunDirectionWorld", osg::Vec3f()),
|
||||
new osg::Uniform("fg_SunZenithCosTheta", 0.0f),
|
||||
new osg::Uniform("fg_MoonDirection", osg::Vec3f()),
|
||||
new osg::Uniform("fg_MoonDirectionWorld", osg::Vec3f()),
|
||||
new osg::Uniform("fg_MoonZenithCosTheta", 0.0f),
|
||||
new osg::Uniform("fg_EarthRadius", 0.0f),
|
||||
}
|
||||
{
|
||||
_uniforms[SG_UNIFORM_SUN_DIRECTION_WORLD]->setUpdateCallback(
|
||||
new SunDirectionWorldCallback);
|
||||
_uniforms[SG_UNIFORM_MOON_DIRECTION_WORLD]->setUpdateCallback(
|
||||
new MoonDirectionWorldCallback);
|
||||
}
|
||||
|
||||
Compositor::~Compositor()
|
||||
@ -214,7 +229,12 @@ Compositor::update(const osg::Matrix &view_matrix,
|
||||
_uniforms[SG_UNIFORM_SUN_DIRECTION_WORLD]->get(sun_dir_world);
|
||||
osg::Vec4f sun_dir_view = osg::Vec4f(
|
||||
sun_dir_world.x(), sun_dir_world.y(), sun_dir_world.z(), 0.0f) * view_matrix;
|
||||
|
||||
|
||||
osg::Vec3f moon_dir_world;
|
||||
_uniforms[SG_UNIFORM_MOON_DIRECTION_WORLD]->get(moon_dir_world);
|
||||
osg::Vec4f moon_dir_view = osg::Vec4f(
|
||||
moon_dir_world.x(), moon_dir_world.y(), moon_dir_world.z(), 0.0f) * view_matrix;
|
||||
|
||||
for (int i = 0; i < SG_TOTAL_BUILTIN_UNIFORMS; ++i) {
|
||||
osg::ref_ptr<osg::Uniform> u = _uniforms[i];
|
||||
switch (i) {
|
||||
@ -259,6 +279,12 @@ Compositor::update(const osg::Matrix &view_matrix,
|
||||
case SG_UNIFORM_SUN_ZENITH_COSTHETA:
|
||||
u->set(float(sun_dir_world * world_up));
|
||||
break;
|
||||
case SG_UNIFORM_MOON_DIRECTION:
|
||||
u->set(osg::Vec3f(moon_dir_view.x(), moon_dir_view.y(), moon_dir_view.z()));
|
||||
break;
|
||||
case SG_UNIFORM_MOON_ZENITH_COSTHETA:
|
||||
u->set(float(moon_dir_world * world_up));
|
||||
break;
|
||||
case SG_UNIFORM_EARTH_RADIUS:
|
||||
u->set(float(camera_pos.length() - camera_pos_geod.getElevationM()));
|
||||
break;
|
||||
|
@ -66,6 +66,9 @@ public:
|
||||
SG_UNIFORM_SUN_DIRECTION,
|
||||
SG_UNIFORM_SUN_DIRECTION_WORLD,
|
||||
SG_UNIFORM_SUN_ZENITH_COSTHETA,
|
||||
SG_UNIFORM_MOON_DIRECTION,
|
||||
SG_UNIFORM_MOON_DIRECTION_WORLD,
|
||||
SG_UNIFORM_MOON_ZENITH_COSTHETA,
|
||||
SG_UNIFORM_EARTH_RADIUS,
|
||||
SG_TOTAL_BUILTIN_UNIFORMS
|
||||
};
|
||||
|
@ -786,6 +786,9 @@ public:
|
||||
ss->addUniform(uniforms[Compositor::SG_UNIFORM_SUN_DIRECTION]);
|
||||
ss->addUniform(uniforms[Compositor::SG_UNIFORM_SUN_DIRECTION_WORLD]);
|
||||
ss->addUniform(uniforms[Compositor::SG_UNIFORM_SUN_ZENITH_COSTHETA]);
|
||||
ss->addUniform(uniforms[Compositor::SG_UNIFORM_MOON_DIRECTION]);
|
||||
ss->addUniform(uniforms[Compositor::SG_UNIFORM_MOON_DIRECTION_WORLD]);
|
||||
ss->addUniform(uniforms[Compositor::SG_UNIFORM_MOON_ZENITH_COSTHETA]);
|
||||
ss->addUniform(uniforms[Compositor::SG_UNIFORM_EARTH_RADIUS]);
|
||||
|
||||
osg::ref_ptr<osg::Uniform> clustered_shading_enabled =
|
||||
|
Loading…
Reference in New Issue
Block a user