00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifdef HAVE_CONFIG_H
00028 # include <simgear_config.h>
00029 #endif
00030
00031 #include <simgear/compiler.h>
00032
00033 #include <osg/AlphaFunc>
00034 #include <osg/BlendFunc>
00035 #include <osg/Fog>
00036 #include <osg/Geode>
00037 #include <osg/Geometry>
00038 #include <osg/Material>
00039 #include <osg/ShadeModel>
00040 #include <osg/TexEnv>
00041 #include <osg/Texture2D>
00042 #include <osgDB/ReadFile>
00043
00044 #include <simgear/math/SGMath.hxx>
00045 #include <simgear/misc/PathOptions.hxx>
00046 #include <simgear/screen/colors.hxx>
00047 #include <simgear/scene/model/model.hxx>
00048 #include "oursun.hxx"
00049
00050 using namespace simgear;
00051
00052
00053 SGSun::SGSun( void ) :
00054 visibility(-9999.0), prev_sun_angle(-9999.0), path_distance(60000.0),
00055 sun_exp2_punch_through(7.0e-06)
00056 {
00057
00058 }
00059
00060
00061
00062 SGSun::~SGSun( void ) {
00063 }
00064
00065
00066
00067 osg::Node*
00068 SGSun::build( SGPath path, double sun_size, SGPropertyNode *property_tree_Node ) {
00069
00070 env_node = property_tree_Node;
00071
00072 osg::ref_ptr<osgDB::ReaderWriter::Options> options
00073 = makeOptionsFromPath(path);
00074
00075
00076 sun_transform = new osg::MatrixTransform;
00077 osg::StateSet* stateSet = sun_transform->getOrCreateStateSet();
00078
00079 osg::TexEnv* texEnv = new osg::TexEnv;
00080 texEnv->setMode(osg::TexEnv::MODULATE);
00081 stateSet->setTextureAttribute(0, texEnv, osg::StateAttribute::ON);
00082
00083 osg::Material* material = new osg::Material;
00084 material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
00085 material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,1));
00086 material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,1));
00087 stateSet->setAttribute(material);
00088
00089 osg::ShadeModel* shadeModel = new osg::ShadeModel;
00090 shadeModel->setMode(osg::ShadeModel::SMOOTH);
00091 stateSet->setAttributeAndModes(shadeModel);
00092
00093 osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
00094 alphaFunc->setFunction(osg::AlphaFunc::ALWAYS);
00095 stateSet->setAttributeAndModes(alphaFunc);
00096
00097 osg::BlendFunc* blendFunc = new osg::BlendFunc;
00098 blendFunc->setSource(osg::BlendFunc::SRC_ALPHA);
00099 blendFunc->setDestination(osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
00100 stateSet->setAttributeAndModes(blendFunc);
00101
00102 stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
00103 stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
00104 stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
00105 stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
00106
00107 osg::Geode* geode = new osg::Geode;
00108 stateSet = geode->getOrCreateStateSet();
00109
00110 stateSet->setRenderBinDetails(-6, "RenderBin");
00111
00112
00113 osg::Texture2D* texture = SGLoadTexture2D("sun.png", options.get());
00114 stateSet->setTextureAttributeAndModes(0, texture);
00115
00116
00117 sun_cl = new osg::Vec4Array;
00118 sun_cl->push_back(osg::Vec4(1, 1, 1, 1));
00119
00120 scene_cl = new osg::Vec4Array;
00121 scene_cl->push_back(osg::Vec4(1, 1, 1, 1));
00122
00123 osg::Vec3Array* sun_vl = new osg::Vec3Array;
00124 sun_vl->push_back(osg::Vec3(-sun_size, 0, -sun_size));
00125 sun_vl->push_back(osg::Vec3(sun_size, 0, -sun_size));
00126 sun_vl->push_back(osg::Vec3(-sun_size, 0, sun_size));
00127 sun_vl->push_back(osg::Vec3(sun_size, 0, sun_size));
00128
00129 osg::Vec2Array* sun_tl = new osg::Vec2Array;
00130 sun_tl->push_back(osg::Vec2(0, 0));
00131 sun_tl->push_back(osg::Vec2(1, 0));
00132 sun_tl->push_back(osg::Vec2(0, 1));
00133 sun_tl->push_back(osg::Vec2(1, 1));
00134
00135 osg::Geometry* geometry = new osg::Geometry;
00136 geometry->setUseDisplayList(false);
00137 geometry->setVertexArray(sun_vl);
00138 geometry->setColorArray(sun_cl.get());
00139 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
00140 geometry->setNormalBinding(osg::Geometry::BIND_OFF);
00141 geometry->setTexCoordArray(0, sun_tl);
00142 geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
00143 geode->addDrawable(geometry);
00144
00145 sun_transform->addChild( geode );
00146
00147
00148 geode = new osg::Geode;
00149 stateSet = geode->getOrCreateStateSet();
00150 stateSet->setRenderBinDetails(-7, "RenderBin");
00151
00152 texture = SGLoadTexture2D("inner_halo.png", options.get());
00153 stateSet->setTextureAttributeAndModes(0, texture);
00154
00155
00156 ihalo_cl = new osg::Vec4Array;
00157 ihalo_cl->push_back(osg::Vec4(1, 1, 1, 1));
00158
00159 float ihalo_size = sun_size * 2.0;
00160 osg::Vec3Array* ihalo_vl = new osg::Vec3Array;
00161 ihalo_vl->push_back(osg::Vec3(-ihalo_size, 0, -ihalo_size));
00162 ihalo_vl->push_back(osg::Vec3(ihalo_size, 0, -ihalo_size));
00163 ihalo_vl->push_back(osg::Vec3(-ihalo_size, 0, ihalo_size));
00164 ihalo_vl->push_back(osg::Vec3(ihalo_size, 0, ihalo_size));
00165
00166 osg::Vec2Array* ihalo_tl = new osg::Vec2Array;
00167 ihalo_tl->push_back(osg::Vec2(0, 0));
00168 ihalo_tl->push_back(osg::Vec2(1, 0));
00169 ihalo_tl->push_back(osg::Vec2(0, 1));
00170 ihalo_tl->push_back(osg::Vec2(1, 1));
00171
00172 geometry = new osg::Geometry;
00173 geometry->setUseDisplayList(false);
00174 geometry->setVertexArray(ihalo_vl);
00175 geometry->setColorArray(ihalo_cl.get());
00176 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
00177 geometry->setNormalBinding(osg::Geometry::BIND_OFF);
00178 geometry->setTexCoordArray(0, ihalo_tl);
00179 geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
00180 geode->addDrawable(geometry);
00181
00182 sun_transform->addChild( geode );
00183
00184
00185
00186 geode = new osg::Geode;
00187 stateSet = geode->getOrCreateStateSet();
00188 stateSet->setRenderBinDetails(-8, "RenderBin");
00189
00190 texture = SGLoadTexture2D("outer_halo.png", options.get());
00191 stateSet->setTextureAttributeAndModes(0, texture);
00192
00193
00194 ohalo_cl = new osg::Vec4Array;
00195 ohalo_cl->push_back(osg::Vec4(1, 1, 1, 1));
00196
00197 double ohalo_size = sun_size * 8.0;
00198 osg::Vec3Array* ohalo_vl = new osg::Vec3Array;
00199 ohalo_vl->push_back(osg::Vec3(-ohalo_size, 0, -ohalo_size));
00200 ohalo_vl->push_back(osg::Vec3(ohalo_size, 0, -ohalo_size));
00201 ohalo_vl->push_back(osg::Vec3(-ohalo_size, 0, ohalo_size));
00202 ohalo_vl->push_back(osg::Vec3(ohalo_size, 0, ohalo_size));
00203
00204 osg::Vec2Array* ohalo_tl = new osg::Vec2Array;
00205 ohalo_tl->push_back(osg::Vec2(0, 0));
00206 ohalo_tl->push_back(osg::Vec2(1, 0));
00207 ohalo_tl->push_back(osg::Vec2(0, 1));
00208 ohalo_tl->push_back(osg::Vec2(1, 1));
00209
00210 geometry = new osg::Geometry;
00211 geometry->setUseDisplayList(false);
00212 geometry->setVertexArray(ohalo_vl);
00213 geometry->setColorArray(ohalo_cl.get());
00214 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
00215 geometry->setNormalBinding(osg::Geometry::BIND_OFF);
00216 geometry->setTexCoordArray(0, ohalo_tl);
00217 geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
00218 geode->addDrawable(geometry);
00219
00220 sun_transform->addChild( geode );
00221
00222
00223 repaint( 0.0, 1.0 );
00224
00225 return sun_transform.get();
00226 }
00227
00228
00229
00230
00231
00232
00233
00234 bool SGSun::repaint( double sun_angle, double new_visibility ) {
00235
00236 if ( visibility != new_visibility ) {
00237 if (new_visibility < 100.0) new_visibility = 100.0;
00238 else if (new_visibility > 45000.0) new_visibility = 45000.0;
00239 visibility = new_visibility;
00240 sun_exp2_punch_through = 2.0/log(visibility);
00241 }
00242
00243 if ( prev_sun_angle != sun_angle ) {
00244 prev_sun_angle = sun_angle;
00245
00246
00247 double aerosol_factor;
00248 if ( visibility < 100 ) {
00249 aerosol_factor = 8000;
00250 }
00251 else {
00252 aerosol_factor = 80.5 / log( visibility / 99.9 );
00253 }
00254
00255
00256 double rel_humidity, density_avg;
00257
00258 if ( !env_node ) {
00259 rel_humidity = 0.5;
00260 density_avg = 0.7;
00261 }
00262 else {
00263 rel_humidity = env_node->getFloatValue( "relative-humidity" );
00264 density_avg = env_node->getFloatValue( "atmosphere/density-tropo-avg" );
00265 }
00266
00267
00268 osg::Vec4 i_halo_color, o_halo_color, scene_color, sun_color;
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281 double red_scat_f, red_scat_corr_f, green_scat_f, blue_scat_f;
00282
00283
00284
00285
00286 red_scat_f = (aerosol_factor * path_distance * density_avg)/5E+07;
00287 red_scat_corr_f = sun_exp2_punch_through / (1 - red_scat_f);
00288 sun_color[0] = 1;
00289 scene_color[0] = 1 - red_scat_f;
00290
00291
00292 green_scat_f = (aerosol_factor * path_distance * density_avg)/8.8938E+06;
00293 sun_color[1] = 1 - green_scat_f * red_scat_corr_f;
00294 scene_color[1] = 1 - green_scat_f;
00295
00296
00297 blue_scat_f = (aerosol_factor * path_distance * density_avg)/3.607E+06;
00298 sun_color[2] = 1 - blue_scat_f * red_scat_corr_f;
00299 scene_color[2] = 1 - blue_scat_f;
00300
00301
00302 sun_color[3] = 1;
00303 scene_color[3] = 1;
00304
00305
00306
00307 double saturation = 1 - ( rel_humidity / 200 );
00308 scene_color[1] += (( 1 - saturation ) * ( 1 - scene_color[1] ));
00309 scene_color[2] += (( 1 - saturation ) * ( 1 - scene_color[2] ));
00310
00311 if (sun_color[0] > 1.0) sun_color[0] = 1.0;
00312 if (sun_color[0] < 0.0) sun_color[0] = 0.0;
00313 if (sun_color[1] > 1.0) sun_color[1] = 1.0;
00314 if (sun_color[1] < 0.0) sun_color[1] = 0.0;
00315 if (sun_color[2] > 1.0) sun_color[2] = 1.0;
00316 if (sun_color[2] < 0.0) sun_color[2] = 0.0;
00317
00318 if (scene_color[0] > 1.0) scene_color[0] = 1.0;
00319 if (scene_color[0] < 0.0) scene_color[0] = 0.0;
00320 if (scene_color[1] > 1.0) scene_color[1] = 1.0;
00321 if (scene_color[1] < 0.0) scene_color[1] = 0.0;
00322 if (scene_color[2] > 1.0) scene_color[2] = 1.0;
00323 if (scene_color[2] < 0.0) scene_color[2] = 0.0;
00324
00325 double scene_f = 0.5 * (1 / (1 - red_scat_f));
00326 double sun_f = 1.0 - scene_f;
00327 i_halo_color[0] = sun_f * sun_color[0] + scene_f * scene_color[0];
00328 i_halo_color[1] = sun_f * sun_color[1] + scene_f * scene_color[1];
00329 i_halo_color[2] = sun_f * sun_color[2] + scene_f * scene_color[2];
00330 i_halo_color[3] = 1;
00331
00332 o_halo_color[0] = 0.2 * sun_color[0] + 0.8 * scene_color[0];
00333 o_halo_color[1] = 0.2 * sun_color[1] + 0.8 * scene_color[1];
00334 o_halo_color[2] = 0.2 * sun_color[2] + 0.8 * scene_color[2];
00335 o_halo_color[3] = blue_scat_f;
00336 if ((visibility < 10000) && (blue_scat_f > 1)) {
00337 o_halo_color[3] = 2 - blue_scat_f;
00338 }
00339 if (o_halo_color[3] > 1) o_halo_color[3] = 1;
00340 if (o_halo_color[3] < 0) o_halo_color[3] = 0;
00341
00342 gamma_correct_rgb( i_halo_color._v );
00343 gamma_correct_rgb( o_halo_color._v );
00344 gamma_correct_rgb( scene_color._v );
00345 gamma_correct_rgb( sun_color._v );
00346
00347 (*sun_cl)[0] = sun_color;
00348 sun_cl->dirty();
00349 (*scene_cl)[0] = scene_color;
00350 scene_cl->dirty();
00351 (*ihalo_cl)[0] = i_halo_color;
00352 ihalo_cl->dirty();
00353 (*ohalo_cl)[0] = o_halo_color;
00354 ohalo_cl->dirty();
00355 }
00356
00357 return true;
00358 }
00359
00360
00361
00362
00363
00364
00365
00366 bool SGSun::reposition( double rightAscension, double declination,
00367 double sun_dist, double lat, double alt_asl, double sun_angle)
00368 {
00369
00370 osg::Matrix T2, RA, DEC;
00371
00372
00373
00374 RA.makeRotate(rightAscension - 90*SGD_DEGREES_TO_RADIANS, osg::Vec3(0, 0, 1));
00375
00376
00377 DEC.makeRotate(declination, osg::Vec3(1, 0, 0));
00378
00379
00380 T2.makeTranslate(osg::Vec3(0, sun_dist, 0));
00381
00382 sun_transform->setMatrix(T2*DEC*RA);
00383
00384
00385 if ( prev_sun_angle != sun_angle ) {
00386 if ( sun_angle == 0 ) sun_angle = 0.1;
00387 const double r_earth_pole = 6356752.314;
00388 const double r_tropo_pole = 6356752.314 + 8000;
00389 const double epsilon_earth2 = 6.694380066E-3;
00390 const double epsilon_tropo2 = 9.170014946E-3;
00391
00392 double r_tropo = r_tropo_pole / sqrt ( 1 - ( epsilon_tropo2 * pow ( cos( lat ), 2 )));
00393 double r_earth = r_earth_pole / sqrt ( 1 - ( epsilon_earth2 * pow ( cos( lat ), 2 )));
00394
00395 double position_radius = r_earth + alt_asl;
00396
00397 double gamma = SG_PI - sun_angle;
00398 double sin_beta = ( position_radius * sin ( gamma ) ) / r_tropo;
00399 if (sin_beta > 1.0) sin_beta = 1.0;
00400 double alpha = SG_PI - gamma - asin( sin_beta );
00401
00402
00403 path_distance = sqrt( pow( position_radius, 2 ) + pow( r_tropo, 2 )
00404 - ( 2 * position_radius * r_tropo * cos( alpha ) ));
00405
00406 double alt_half = sqrt( pow ( r_tropo, 2 ) + pow( path_distance / 2, 2 ) - r_tropo * path_distance * cos( asin( sin_beta )) ) - r_earth;
00407
00408 if ( alt_half < 0.0 ) alt_half = 0.0;
00409
00410
00411 if ( env_node ){
00412 env_node->setDoubleValue( "atmosphere/altitude-troposphere-top", r_tropo - r_earth );
00413 env_node->setDoubleValue( "atmosphere/altitude-half-to-sun", alt_half );
00414 }
00415 }
00416
00417 return true;
00418 }
00419
00420 SGVec4f
00421 SGSun::get_color()
00422 {
00423 return SGVec4f((*sun_cl)[0][0], (*sun_cl)[0][1], (*sun_cl)[0][2], (*sun_cl)[0][3]);
00424 }
00425
00426 SGVec4f
00427 SGSun::get_scene_color()
00428 {
00429 return SGVec4f((*scene_cl)[0][0], (*scene_cl)[0][1], (*scene_cl)[0][2], (*scene_cl)[0][3]);
00430 }