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 - curt@flightgear.org
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 Library General Public
22 // License along with this library; if not, write to the
23 // Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 // Boston, MA 02111-1307, USA.
34 # error This library requires C++
38 #include <plib/ssg.h> // plib include
40 #include <simgear/compiler.h>
41 #include <simgear/misc/sg_path.hxx>
45 #include <simgear/scene/sky/cloud.hxx>
46 #include <simgear/scene/sky/dome.hxx>
47 #include <simgear/scene/sky/moon.hxx>
48 #include <simgear/scene/sky/oursun.hxx>
49 #include <simgear/scene/sky/stars.hxx>
54 typedef vector < SGCloudLayer* > layer_list_type;
55 typedef layer_list_type::iterator layer_list_iterator;
56 typedef layer_list_type::const_iterator layer_list_const_iterator;
59 * A class to model a realistic (time/date/position) based sky.
63 * The SGSky class models a blended sky dome, a haloed sun, a textured
64 * moon with phase that properly matches the date, stars and planets,
65 * and cloud layers. SGSky is designed to be dropped into existing
66 * plib based applications and depends heavily on plib's scene graph
67 * library, ssg. The sky implements various time of day lighting
68 * effects, it plays well with fog and visibility effects, and
69 * implements scudded cloud fly-through effects. Additionally, you can
70 * wire in the output of the SGEphemeris class to accurately position
71 * all the objects in the sky.
76 * Once you have created an instance of SGSky you must call the
77 * build() method. Building the sky requires several textures. So,
78 * you must specify the path/directory where these textures reside
79 * before building the sky. You do this first by calling the
80 * texture_path() method.
82 * The arguments you pass to the build() method allow you to specify
83 * the horizontal and vertical radiuses of the sky dome, the size of
84 * your sun sphere and moon sphere, a number of planets, and a
85 * multitude of stars. For the planets and stars you pass in an array
86 * of right ascensions, declinations, and magnitudes.
90 * Cloud layers can be added, changed, or removed individually. To add
91 * a cloud layer use the add_cloud_layer() method. The arguments
92 * allow you to specify base height above sea level, layer thickness,
93 * a transition zone for entering/leaving the cloud layer, the size of
94 * the cloud object, and the type of cloud texture. All distances are
95 * in meters. There are additional forms of this method that allow you
96 * to specify your own ssgSimpleState or texture name for drawing the
101 * As the sun circles the globe, you can call the repaint() method to
102 * recolor the sky objects to simulate sunrise and sunset effects,
103 * visibility, and other lighting changes. The arguments allow you to
104 * specify a base sky color (for the top of the dome), a fog color
105 * (for the horizon), the sun angle with the horizon (for
106 * sunrise/sunset effects), the moon angle (so we can make it more
107 * yellow at the horizon), and new star and planet data so that we can
108 * optionally change the magnitude of these (for day / night
111 * Positioning Sky Objects
113 * As time progresses and as you move across the surface of the earth,
114 * the apparent position of the objects and the various lighting
115 * effects can change. the reposition() method allows you to specify
116 * the positions of all the sky objects as well as your view position.
117 * The arguments allow you to specify your view position in world
118 * Cartesian coordinates, the zero elevation position in world
119 * Cartesian coordinates (your longitude, your latitude, sea level),
120 * the ``up'' vector in world Cartesian coordinates, current
121 * longitude, latitude, and altitude. A ``spin'' angle can be
122 * specified for orienting the sky with the sun position so sunset and
123 * sunrise effects look correct. You must specify GMT side real time,
124 * the sun right ascension, sun declination, and sun distance from
125 * view point (to keep it inside your view volume.) You also must
126 * specify moon right ascension, moon declination, and moon distance
131 * The sky is designed to be rendered in two stages. The first stage
132 * renders the parts that form your back drop - the sky dome, the
133 * stars and planets, the sun, and the moon. These should be rendered
134 * before the rest of your scene by calling the preDraw() method. The
135 * second stage renders the clouds which are likely to be translucent
136 * (depending on type) and should be drawn after your scene has been
137 * rendered. Use the postDraw() method to draw the second stage of
140 * A typical application might do the following:
142 * <li> thesky->preDraw();
143 * <li> ssgCullAndDraw ( myscene ) ;
144 * <li> thesky->postDraw( my_altitude );
146 * The current altitude in meters is passed to the postDraw() method
147 * so the clouds layers can be rendered correction from most distant
152 * Visibility and fog is important for correctly rendering the
153 * sky. You can inform SGSky of the current visibility by calling the
154 * set_visibility() method.
156 * When transitioning through clouds, it is nice to pull in the fog as
157 * you get close to the cloud layer to hide the fact that the clouds
158 * are drawn as a flat polygon. As you get nearer to the cloud layer
159 * it is also nice to temporarily pull in the visibility to simulate
160 * the effects of flying in and out of the puffy edge of the
161 * cloud. These effects can all be accomplished by calling the
162 * modify_vis() method. The arguments allow you to specify your
163 * current altitude (which is then compared to the altitudes of the
164 * various cloud layers.) You can also specify a time factor which
165 * should be the length in seconds since the last time you called
166 * modify_vis(). The time_factor value allows the puffy cloud effect
167 * to be calculated correctly.
169 * The modify_vis() method alters the SGSky's internal idea of
170 * visibility, so you should subsequently call get_visibility() to get
171 * the actual modified visibility. You should then make the
172 * appropriate glFog() calls to setup fog properly for your scene.
176 * Once an instance of SGSky has been successfully initialized, there
177 * are a couple accessor methods you can use such as get_num_layers()
178 * to return the number of cloud layers, get_cloud_layer(i) to return
179 * cloud layer number i, get_visibility() to return the actual
180 * visibility as modified by the sky/cloud model.
188 // components of the sky
194 layer_list_type cloud_layers;
196 ssgRoot *pre_root, *post_root;
198 ssgSelector *pre_selector, *post_selector;
199 ssgTransform *pre_transform, *post_transform;
205 float effective_visibility;
207 // near cloud visibility state variables
209 double puff_length; // in seconds
210 double puff_progression; // in seconds
211 double ramp_up; // in seconds
212 double ramp_down; // in seconds
223 * Initialize the sky and connect the components to the scene
224 * graph at the provided branch. See discussion in detailed class
226 * @param h_radius_m horizontal radius of sky dome
227 * @param v_radius_m vertical radius of sky dome
228 * @param sun_size size of sun
229 * @param moon_size size of moon
230 * @param nplanets number of planets
231 * @param planet_data an array of planet right ascensions, declinations,
233 * @param nstars number of stars
234 * @param star_data an array of star right ascensions, declinations,
237 void build( double h_radius_m, double v_radius_m,
238 double sun_size, double moon_size,
239 int nplanets, sgdVec3 *planet_data,
240 int nstars, sgdVec3 *star_data );
243 * Repaint the sky components based on current value of sun_angle,
244 * sky, and fog colors. You can also specify new star and planet
245 * data so that we can optionally change the magnitude of these
246 * (for day/night transitions.) See discussion in detailed
249 * Sun and moon angles are specified in degrees relative to local up
250 * <li> 0 degrees = high noon
251 * <li> 90 degrees = sun rise/set
252 * <li> 180 degrees = darkest midnight
253 * @param sky_color the base sky color (for the top of the dome)
254 * @param fog_color the fog color (for the horizon)
255 * @param sun_angle the sun angle with the horizon (for sunrise/sunset
257 * @param moon_angle the moon angle (so we can make it more yellow
259 * @param nplanets number of planets
260 * @param planet_data an array of planet right ascensions, declinations,
262 * @param nstars number of stars
263 * @param star_data an array of star right ascensions, declinations,
266 bool repaint( sgVec4 sky_color, sgVec4 fog_color, sgVec4 cloud_color,
267 double sun_angle, double moon_angle,
268 int nplanets, sgdVec3 *planet_data,
269 int nstars, sgdVec3 *star_data );
272 * Reposition the sky at the specified origin and orientation
274 * lon specifies a rotation about the Z axis
275 * lat specifies a rotation about the new Y axis
276 * spin specifies a rotation about the new Z axis (this allows
277 * additional orientation for the sunrise/set effects and is used
278 * by the skydome and perhaps clouds. See discussion in detailed
280 * @param view_pos specify your view position in world Cartesian
282 * @param zero_elev the zero elevation position in world Cartesian
284 * @param view_up the up vector in world Cartesian coordinates
285 * @param lon current longitude
286 * @param lat current latitude
287 * @param alt current altitude
288 * @param spin an offset angle for orienting the sky effects with the
289 * sun position so sunset and sunrise effects look correct.
290 * @param gst GMT side real time
291 * @param sun_ra the sun's current right ascension
292 * @param sun_dec the sun's current declination
293 * @param sun_dist the sun's distance from the current view point
294 * (to keep it inside your view volume.)
295 * @param moon_ra the moon's current right ascension
296 * @param moon_dec the moon's current declination
297 * @param moon_dist the moon's distance from the current view point.
299 bool reposition( sgVec3 view_pos, sgVec3 zero_elev, sgVec3 view_up,
300 double lon, double lat, double alt, double spin,
302 double sun_ra, double sun_dec, double sun_dist,
303 double moon_ra, double moon_dec, double moon_dist );
306 * Modify the given visibility based on cloud layers, thickness,
307 * transition range, and simulated "puffs". See discussion in detailed
309 * @param alt current altitude
310 * @param time_factor amount of time since modify_vis() last called so
311 * we can scale effect rates properly despite variable frame rates.
313 void modify_vis( float alt, float time_factor );
316 * Draw background portions of the sky ... do this before you draw
317 * the rest of your scene. See discussion in detailed
323 * Draw translucent clouds ... do this after you've drawn all the
324 * oapaque elements of your scene. See discussion in detailed
326 * @param alt current altitude
328 void postDraw( float alt );
331 * Specify the texture path (optional, defaults to current directory)
332 * @param path base path to texture locations
334 inline void texture_path( const string& path ) {
335 tex_path = SGPath( path );
338 /** Enable drawing of the sky. */
339 inline void enable() {
340 pre_selector->select( 1 );
341 post_selector->select( 1 );
345 * Disable drawing of the sky in the scene graph. The leaf node is still
346 * there, how ever it won't be traversed on by ssgCullandRender()
348 inline void disable() {
349 pre_selector->select( 0 );
350 post_selector->select( 0 );
355 * Get the current sun color
357 inline float *get_sun_color() { return oursun->get_color(); }
363 * Transfer pointer ownership to this object.
365 * @param layer The new cloud layer to add.
367 void add_cloud_layer (SGCloudLayer * layer);
371 * Get a cloud layer (const).
373 * Pointer ownership remains with this object.
375 * @param i The index of the cloud layer, zero-based.
376 * @return A const pointer to the cloud layer.
378 const SGCloudLayer * get_cloud_layer (int i) const;
382 * Get a cloud layer (non-const).
384 * Pointer ownership remains with this object.
386 * @param i The index of the cloud layer, zero-based.
387 * @return A non-const pointer to the cloud layer.
389 SGCloudLayer * get_cloud_layer (int i);
393 * Return the number of cloud layers currently available.
395 * @return The cloud layer count.
397 int get_cloud_layer_count () const;
400 /** @return current effective visibility */
401 inline float get_visibility() const { return effective_visibility; }
403 /** Set desired clear air visibility.
404 * @param v visibility in meters
406 inline void set_visibility( float v ) {
407 effective_visibility = visibility = v;
412 #endif // _SG_SKY_HXX