3 * Provides a class to model a realistic (time/date/position) based sky.
6 // Written by Curtis Olson, started December 1997.
7 // SSG-ified by Curtis Olson, February 2000.
9 // Copyright (C) 1997-2000 Curtis L. Olson - http://www.flightgear.org/~curt
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Library General Public
13 // License as published by the Free Software Foundation; either
14 // version 2 of the License, or (at your option) any later version.
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Library General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
33 # error This library requires C++
36 #include <simgear/compiler.h>
37 #include <simgear/misc/sg_path.hxx>
38 #include <simgear/props/props.hxx>
42 #include <osg/ref_ptr>
43 #include <osg/MatrixTransform>
47 #include <simgear/ephemeris/ephemeris.hxx>
48 #include <simgear/math/SGMath.hxx>
50 #include <simgear/scene/sky/cloud.hxx>
51 #include <simgear/scene/sky/dome.hxx>
52 #include <simgear/scene/sky/moon.hxx>
53 #include <simgear/scene/sky/oursun.hxx>
54 #include <simgear/scene/sky/stars.hxx>
57 class SGReaderWriterOptions;
73 SGVec3f adj_sky_color;
76 double sun_angle, moon_angle;
80 * A class to model a realistic (time/date/position) based sky.
84 * The SGSky class models a blended sky dome, a haloed sun, a textured
85 * moon with phase that properly matches the date, stars and planets,
86 * and cloud layers. SGSky is designed to be dropped into existing
87 * plib based applications and depends heavily on plib's scene graph
88 * library, ssg. The sky implements various time of day lighting
89 * effects, it plays well with fog and visibility effects, and
90 * implements scudded cloud fly-through effects. Additionally, you can
91 * wire in the output of the SGEphemeris class to accurately position
92 * all the objects in the sky.
97 * Once you have created an instance of SGSky you must call the
98 * build() method. Building the sky requires several textures. So,
99 * you must specify the path/directory where these textures reside
100 * before building the sky. You do this first by calling the
101 * texture_path() method.
103 * The arguments you pass to the build() method allow you to specify
104 * the horizontal and vertical radiuses of the sky dome, the size of
105 * your sun sphere and moon sphere, a number of planets, and a
106 * multitude of stars. For the planets and stars you pass in an array
107 * of right ascensions, declinations, and magnitudes.
111 * Cloud layers can be added, changed, or removed individually. To add
112 * a cloud layer use the add_cloud_layer() method. The arguments
113 * allow you to specify base height above sea level, layer thickness,
114 * a transition zone for entering/leaving the cloud layer, the size of
115 * the cloud object, and the type of cloud texture. All distances are
116 * in meters. There are additional forms of this method that allow you
117 * to specify your own ssgSimpleState or texture name for drawing the
122 * As the sun circles the globe, you can call the repaint() method to
123 * recolor the sky objects to simulate sunrise and sunset effects,
124 * visibility, and other lighting changes. The arguments allow you to
125 * specify a base sky color (for the top of the dome), a fog color
126 * (for the horizon), the sun angle with the horizon (for
127 * sunrise/sunset effects), the moon angle (so we can make it more
128 * yellow at the horizon), and new star and planet data so that we can
129 * optionally change the magnitude of these (for day / night
132 * Positioning Sky Objects
134 * As time progresses and as you move across the surface of the earth,
135 * the apparent position of the objects and the various lighting
136 * effects can change. the reposition() method allows you to specify
137 * the positions of all the sky objects as well as your view position.
138 * The arguments allow you to specify your view position in world
139 * Cartesian coordinates, the zero elevation position in world
140 * Cartesian coordinates (your longitude, your latitude, sea level),
141 * the ``up'' vector in world Cartesian coordinates, current
142 * longitude, latitude, and altitude. A ``spin'' angle can be
143 * specified for orienting the sky with the sun position so sunset and
144 * sunrise effects look correct. You must specify GMT side real time,
145 * the sun right ascension, sun declination, and sun distance from
146 * view point (to keep it inside your view volume.) You also must
147 * specify moon right ascension, moon declination, and moon distance
152 * The sky is designed to be rendered in three stages. The first stage
153 * renders the parts that form your back drop - the sky dome, the
154 * stars and planets, the sun, and the moon. These should be rendered
155 * before the rest of your scene by calling the preDraw() method. The
156 * second stage renders the clouds that are above the viewer. This stage
157 * is done before translucent objects in the main scene are drawn. It
158 * is seperated from the preDraw routine to enable to implement a
159 * multi passes technique and is located in the drawUpperClouds() method.
160 * The third stage renders the clouds that are below the viewer an which
161 * are likely to be translucent (depending on type) and should be drawn
162 * after your scene has been rendered. Use the drawLowerClouds() method
163 * to draw the second stage of the sky.
165 * A typical application might do the following:
167 * <li> thesky->preDraw( my_altitude );
168 * <li> thesky->drawUpperClouds();
169 * <li> ssgCullAndDraw ( myscene ) ;
170 * <li> thesky->drawLowerClouds();
172 * The current altitude in meters is passed to the preDraw() method
173 * so the clouds layers can be rendered correction from most distant
178 * Visibility and fog is important for correctly rendering the
179 * sky. You can inform SGSky of the current visibility by calling the
180 * set_visibility() method.
182 * When transitioning through clouds, it is nice to pull in the fog as
183 * you get close to the cloud layer to hide the fact that the clouds
184 * are drawn as a flat polygon. As you get nearer to the cloud layer
185 * it is also nice to temporarily pull in the visibility to simulate
186 * the effects of flying in and out of the puffy edge of the
187 * cloud. These effects can all be accomplished by calling the
188 * modify_vis() method. The arguments allow you to specify your
189 * current altitude (which is then compared to the altitudes of the
190 * various cloud layers.) You can also specify a time factor which
191 * should be the length in seconds since the last time you called
192 * modify_vis(). The time_factor value allows the puffy cloud effect
193 * to be calculated correctly.
195 * The modify_vis() method alters the SGSky's internal idea of
196 * visibility, so you should subsequently call get_visibility() to get
197 * the actual modified visibility. You should then make the
198 * appropriate glFog() calls to setup fog properly for your scene.
202 * Once an instance of SGSky has been successfully initialized, there
203 * are a couple accessor methods you can use such as get_num_layers()
204 * to return the number of cloud layers, get_cloud_layer(i) to return
205 * cloud layer number i, get_visibility() to return the actual
206 * visibility as modified by the sky/cloud model.
213 typedef std::vector<SGSharedPtr<SGCloudLayer> > layer_list_type;
214 typedef layer_list_type::iterator layer_list_iterator;
215 typedef layer_list_type::const_iterator layer_list_const_iterator;
217 // components of the sky
218 SGSharedPtr<SGSkyDome> dome;
219 SGSharedPtr<SGSun> oursun;
220 SGSharedPtr<SGMoon> moon;
221 SGSharedPtr<SGStars> planets;
222 SGSharedPtr<SGStars> stars;
223 layer_list_type cloud_layers;
225 osg::ref_ptr<osg::Group> pre_root, cloud_root;
226 osg::ref_ptr<osg::Switch> pre_selector;
227 osg::ref_ptr<osg::Group> pre_transform;
229 osg::ref_ptr<osg::MatrixTransform> _ephTransform;
235 float effective_visibility;
236 float minimum_sky_visibility;
241 // near cloud visibility state variables
243 double puff_length; // in seconds
244 double puff_progression; // in seconds
245 double ramp_up; // in seconds
246 double ramp_down; // in seconds
249 bool clouds_3d_enabled;
252 double clouds_3d_density;
263 * Initialize the sky and connect the components to the scene
264 * graph at the provided branch. See discussion in detailed class
266 * @param h_radius_m horizontal radius of sky dome
267 * @param v_radius_m vertical radius of sky dome
268 * @param sun_size size of sun
269 * @param moon_size size of moon
270 * @param nplanets number of planets
271 * @param planet_data an array of planet right ascensions, declinations,
273 * @param nstars number of stars
274 * @param star_data an array of star right ascensions, declinations,
277 void build( double h_radius_m, double v_radius_m,
278 double sun_size, double moon_size,
279 const SGEphemeris& eph, SGPropertyNode *property_tree_node,
280 simgear::SGReaderWriterOptions* options = 0);
283 * Repaint the sky components based on current value of sun_angle,
284 * sky, and fog colors. You can also specify new star and planet
285 * data so that we can optionally change the magnitude of these
286 * (for day/night transitions.) See discussion in detailed
289 * Sun and moon angles are specified in degrees relative to local up
290 * <li> 0 degrees = high noon
291 * <li> 90 degrees = sun rise/set
292 * <li> 180 degrees = darkest midnight
293 * @param sky_color the base sky color (for the top of the dome)
294 * @param fog_color the fog color (for the horizon)
295 * @param sun_angle the sun angle with the horizon (for sunrise/sunset
297 * @param moon_angle the moon angle (so we can make it more yellow
299 * @param nplanets number of planets
300 * @param planet_data an array of planet right ascensions, declinations,
302 * @param nstars number of stars
303 * @param star_data an array of star right ascensions, declinations,
306 bool repaint( const SGSkyColor &sc, const SGEphemeris& eph );
309 * Reposition the sky at the specified origin and orientation
311 * lon specifies a rotation about the Z axis
312 * lat specifies a rotation about the new Y axis
313 * spin specifies a rotation about the new Z axis (this allows
314 * additional orientation for the sunrise/set effects and is used
315 * by the skydome and perhaps clouds. See discussion in detailed
317 * @param view_pos specify your view position in world Cartesian
319 * @param zero_elev the zero elevation position in world Cartesian
321 * @param view_up the up vector in world Cartesian coordinates
322 * @param lon current longitude
323 * @param lat current latitude
324 * @param alt current altitude
325 * @param spin an offset angle for orienting the sky effects with the
326 * sun position so sunset and sunrise effects look correct.
327 * @param gst GMT side real time
328 * @param sun_ra the sun's current right ascension
329 * @param sun_dec the sun's current declination
330 * @param sun_dist the sun's distance from the current view point
331 * (to keep it inside your view volume.)
332 * @param moon_ra the moon's current right ascension
333 * @param moon_dec the moon's current declination
334 * @param moon_dist the moon's distance from the current view point.
336 bool reposition( const SGSkyState &st, const SGEphemeris& eph, double dt = 0.0 );
339 * Modify the given visibility based on cloud layers, thickness,
340 * transition range, and simulated "puffs". See discussion in detailed
342 * @param alt current altitude
343 * @param time_factor amount of time since modify_vis() last called so
344 * we can scale effect rates properly despite variable frame rates.
346 void modify_vis( float alt, float time_factor );
348 osg::Node* getPreRoot() { return pre_root.get(); }
349 osg::Node* getCloudRoot() { return cloud_root.get(); }
352 * Specify the texture path (optional, defaults to current directory)
353 * @param path base path to texture locations
355 void texture_path( const string& path );
357 /** Enable drawing of the sky. */
358 inline void enable() {
359 pre_selector->setValue(0, 1);
363 * Disable drawing of the sky in the scene graph. The leaf node is still
364 * there, how ever it won't be traversed on by ssgCullandRender()
366 inline void disable() {
367 pre_selector->setValue(0, 0);
371 * Get the current sun color
373 inline SGVec4f get_sun_color() { return oursun->get_color(); }
376 * Get the current scene color
378 inline SGVec4f get_scene_color() { return oursun->get_scene_color(); }
383 * Transfer pointer ownership to this object.
385 * @param layer The new cloud layer to add.
387 void add_cloud_layer (SGCloudLayer * layer);
391 * Get a cloud layer (const).
393 * Pointer ownership remains with this object.
395 * @param i The index of the cloud layer, zero-based.
396 * @return A const pointer to the cloud layer.
398 const SGCloudLayer * get_cloud_layer (int i) const;
402 * Get a cloud layer (non-const).
404 * Pointer ownership remains with this object.
406 * @param i The index of the cloud layer, zero-based.
407 * @return A non-const pointer to the cloud layer.
409 SGCloudLayer * get_cloud_layer (int i);
413 * Return the number of cloud layers currently available.
415 * @return The cloud layer count.
417 int get_cloud_layer_count () const;
420 /** @return current effective visibility */
421 inline float get_visibility() const { return effective_visibility; }
423 /** Set desired clear air visibility.
424 * @param v visibility in meters
426 inline void set_visibility( float v ) {
427 effective_visibility = visibility = (v <= 25.0) ? 25.0 : v;
430 /** Get 3D cloud density */
431 double get_3dCloudDensity() const;
433 /** Set 3D cloud density
434 * @param density 3D cloud density
436 void set_3dCloudDensity(double density);
438 /** Get 3D cloud visibility range*/
439 float get_3dCloudVisRange() const;
441 /** Set 3D cloud visibility range
442 * @param density 3D cloud visibility range
444 void set_3dCloudVisRange(float vis);
446 /** Get 3D cloud impostor distance*/
447 float get_3dCloudImpostorDistance() const;
449 /** Set 3D cloud impostor distance
450 * @param density 3D cloud impostor distance
452 void set_3dCloudImpostorDistance(float vis);
454 /** Get 3D cloud LoD1 Range*/
455 float get_3dCloudLoD1Range() const;
457 /** Set 3D cloud LoD1 Range
458 * @param vis LoD1 Range
460 void set_3dCloudLoD1Range(float vis);
462 /** Get 3D cloud LoD2 Range*/
463 float get_3dCloudLoD2Range() const;
465 /** Set 3D cloud LoD2 Range
466 * @param vis LoD2 Range
468 void set_3dCloudLoD2Range(float vis);
470 /** Get 3D cloud impostor usage */
471 bool get_3dCloudUseImpostors() const;
473 /** Set 3D cloud impostor usage
474 * @param wrap whether use impostors for 3D clouds
476 void set_3dCloudUseImpostors(bool imp);
478 /** Get 3D cloud wrapping */
479 bool get_3dCloudWrap() const;
481 /** Set 3D cloud wrapping
482 * @param wrap whether to wrap 3D clouds
484 void set_3dCloudWrap(bool wrap);
487 /** Get minimum sky visibility */
488 float get_minimum_sky_visibility() const;
490 /** Set minimum sky visibility */
491 void set_minimum_sky_visibility( float value );
493 #endif // _SG_SKY_HXX