From ebc1002139674744ba34d3aef1205fd2124be375 Mon Sep 17 00:00:00 2001 From: Frederic Bouvier Date: Thu, 8 Mar 2012 23:20:39 +0100 Subject: [PATCH] Sunrises 1.2 by Thorsten Renk --- Effects/cloud-static.eff | 84 ++++++ Effects/cloud.eff | 108 ++++++- Effects/model-default.eff | 101 ++++++- Effects/rain-layer.eff | 91 +++++- Effects/skydome.eff | 247 +++++++-------- Effects/terrain-default.eff | 180 +++++++++-- Environment/environment.xml | 3 +- Environment/local-weather-defaults.xml | 1 + Nasal/local_weather/cloud_definitions.nas | 12 +- Nasal/local_weather/compat_layer.nas | 90 +++++- Nasal/local_weather/local_weather.nas | 53 ++-- Nasal/local_weather/weather_dynamics.nas | 20 +- .../local_weather/weather_tile_management.nas | 13 +- Nasal/local_weather/weather_tiles.nas | 86 ++++-- Shaders/3dcloud-lightfield.frag | 15 + Shaders/3dcloud-lightfield.vert | 169 +++++++++++ Shaders/cloud-static-lightfield.frag | 12 + Shaders/cloud-static-lightfield.vert | 119 ++++++++ Shaders/rain-layer-lightfield.frag | 12 + Shaders/rain-layer-lightfield.vert | 122 ++++++++ Shaders/skydome.frag | 175 +++++++++-- Shaders/skydome.vert | 144 +++++++-- Shaders/terrain-haze.frag | 285 ++++++++++++++++++ Shaders/terrain-haze.vert | 233 ++++++++++++++ gui/dialogs/local_weather_tiles.xml | 20 +- 25 files changed, 2132 insertions(+), 263 deletions(-) create mode 100644 Shaders/3dcloud-lightfield.frag create mode 100644 Shaders/3dcloud-lightfield.vert create mode 100644 Shaders/cloud-static-lightfield.frag create mode 100644 Shaders/cloud-static-lightfield.vert create mode 100644 Shaders/rain-layer-lightfield.frag create mode 100644 Shaders/rain-layer-lightfield.vert create mode 100644 Shaders/terrain-haze.frag create mode 100644 Shaders/terrain-haze.vert diff --git a/Effects/cloud-static.eff b/Effects/cloud-static.eff index 52870a571..55543d9c4 100644 --- a/Effects/cloud-static.eff +++ b/Effects/cloud-static.eff @@ -4,7 +4,81 @@ + + /environment/terminator-relative-position-m + + + /sim/rendering/eye-altitude-m + + + + + + /sim/rendering/shaders/skydome + /sim/rendering/clouds3d-enable + + 1.0 + + + + + + + true + + 0.5 0.5 0.5 1.0 + 0.5 0.5 0.5 1.0 + off + + + greater + 0.01 + + smooth + + src-alpha + one-minus-src-alpha + + + false + + + 9 + DepthSortedBin + + + 0 + texture[0]/type + texture[0]/image + texture[0]/filter + texture[0]/wrap-s + texture[0]/wrap-t + + + + Shaders/cloud-static-lightfield.vert + Shaders/cloud-static-lightfield.frag + + + baseTexture + sampler-2d + 0 + + + terminator + float + terminator + + + altitude + float + altitude + + true + + @@ -58,6 +132,16 @@ sampler-2d 0 + + terminator + float + terminator + + + altitude + float + altitude + true diff --git a/Effects/cloud.eff b/Effects/cloud.eff index 0dc464100..fa43fbb0f 100644 --- a/Effects/cloud.eff +++ b/Effects/cloud.eff @@ -6,8 +6,99 @@ /sim/rendering/clouds3d-vis-range - + + + /rendering/scene/scattering + + + /environment/terminator-relative-position-m + + + /sim/rendering/eye-altitude-m + + + + /sim/rendering/shaders/skydome + + 1.0 + + + + + + + true + + 0.5 0.5 0.5 1.0 + 0.5 0.5 0.5 1.0 + off + + + greater + 0.01 + + smooth + + src-alpha + one-minus-src-alpha + + + false + + + 10 + DepthSortedBin + + + 0 + 2d + texture[0]/image + clamp + clamp + + + Shaders/3dcloud-lightfield.vert + Shaders/3dcloud-lightfield.frag + + usrAttr1 + 10 + + + usrAttr2 + 11 + + + + baseTexture + sampler-2d + 0 + + + range + float + range + + + scattering + float + scattering + + + terminator + float + terminator + + + altitude + float + altitude + + true + + @@ -68,6 +159,21 @@ float range + + scattering + float + scattering + + + terminator + float + terminator + + + altitude + float + altitude + true diff --git a/Effects/model-default.eff b/Effects/model-default.eff index a332b8245..d2e313cf4 100644 --- a/Effects/model-default.eff +++ b/Effects/model-default.eff @@ -32,6 +32,105 @@ + + + + + /sim/rendering/shaders/skydome + + + 2.0 + + + + GL_ARB_shader_objects + GL_ARB_shading_language_100 + GL_ARB_vertex_shader + GL_ARB_fragment_shader + + + + + + true + + material/active + material/ambient + material/diffuse + material/specular + material/emissive + material/shininess + material/color-mode + + + blend/active + blend/source + blend/destination + + shade-model + cull-face + rendering-hint + + + 0 + + texture[0]/type + texture[0]/image + texture[0]/filter + texture[0]/wrap-s + texture[0]/wrap-t + + + + vertex-program-two-side + + + + Shaders/terrain-haze.vert + Shaders/terrain-haze.frag + + + visibility + float + visibility + + + avisibility + float + avisibility + + + hazeLayerAltitude + float + lthickness + + + scattering + float + scattering + + + texture + sampler-2d + 0 + + + colorMode + int + material/color-mode-uniform + + + + @@ -126,7 +225,7 @@ vertex-program-two-side - + Shaders/include_fog.vert Shaders/default.vert Shaders/include_fog.frag diff --git a/Effects/rain-layer.eff b/Effects/rain-layer.eff index 828237fb6..ee9c78c5d 100644 --- a/Effects/rain-layer.eff +++ b/Effects/rain-layer.eff @@ -4,10 +4,88 @@ - + /sim/rendering/clouds3d-vis-range + + /rendering/scene/scattering + + + /environment/terminator-relative-position-m + + + + + /sim/rendering/shaders/skydome + /sim/rendering/clouds3d-enable + + 1.0 + + + + + + + true + + 0.5 0.5 0.5 1.0 + 0.5 0.5 0.5 1.0 + off + + + greater + 0.01 + + smooth + + src-alpha + one-minus-src-alpha + + + false + + + 9 + DepthSortedBin + + + 0 + texture[0]/type + texture[0]/image + texture[0]/filter + texture[0]/wrap-s + texture[0]/wrap-t + + + + Shaders/rain-layer-lightfield.vert + Shaders/rain-layer-lightfield.frag + + + baseTexture + sampler-2d + 0 + + + range + float + range + + + scattering + float + scattering + + + terminator + float + terminator + + true + + @@ -66,7 +144,16 @@ float range - + + scattering + float + scattering + + + terminator + float + terminator + true diff --git a/Effects/skydome.eff b/Effects/skydome.eff index 849af3f32..09fd3ede9 100644 --- a/Effects/skydome.eff +++ b/Effects/skydome.eff @@ -1,145 +1,112 @@ - Effects/skydome - - - /sim/rendering/mie - - - /sim/rendering/rayleigh - - - /sim/rendering/dome-density - - - /rendering/scene/overcast - - - /rendering/scene/saturation - - - /rendering/scene/scattering - - - /environment/ground-visibility-m - - - /environment/visibility-m - - - /environment/ground-haze-thickness-m - - - /environment/terminator-relative-position-m - - - - - - /sim/rendering/shaders/skydome - - - 2.0 - - - - GL_ARB_shader_objects - GL_ARB_shading_language_100 - GL_ARB_vertex_shader - GL_ARB_fragment_shader - - - - + Effects/skydome + + /sim/rendering/mie + /sim/rendering/rayleigh + /sim/rendering/dome-density + /rendering/scene/overcast + /rendering/scene/saturation + /rendering/scene/scattering + /environment/ground-visibility-m + /environment/visibility-m + /environment/ground-haze-thickness-m + /environment/terminator-relative-position-m + /environment/mean-terrain-elevation-m + + + + + /sim/rendering/shader-effects + /sim/rendering/shaders/skydome + + + 2.0 + + + + GL_ARB_shader_objects + GL_ARB_shading_language_100 + GL_ARB_vertex_shader + GL_ARB_fragment_shader + + + + - - true - smooth - back - - Shaders/skydome.vert - Shaders/skydome.frag - - - mK - float - - mie - - - - rK - float - - rayleigh - - - - density - float - - density - - - - overcast - float - - overcast - - - - saturation - float - - saturation - - - - scattering - float - - scattering - - - - visibility - float - - visibility - - - - hazeLayerAltitude - float - - lthickness - - - - terminator - float - - terminator - - - - avisibility - float - - avisibility - - - - + + true + smooth + back + + Shaders/skydome.vert + Shaders/skydome.frag + + + mK + float + mie + + + rK + float + rayleigh + + + density + float + density + + + overcast + float + overcast + + + saturation + float + saturation + + + scattering + float + scattering + + + visibility + float + visibility + + + hazeLayerAltitude + float + lthickness + + + terminator + float + terminator + + + avisibility + float + avisibility + + + terrain_alt + float + terrain_alt + + + - - - - false - smooth - back - - + + + + false + smooth + back + + - \ No newline at end of file + diff --git a/Effects/terrain-default.eff b/Effects/terrain-default.eff index 9f01dfa6d..d4f259abc 100644 --- a/Effects/terrain-default.eff +++ b/Effects/terrain-default.eff @@ -35,28 +35,166 @@ 0 RenderBin - - /environment/ground-visibility-m - - - /environment/visibility-m - - - /environment/ground-haze-thickness-m - - - /rendering/scene/scattering - - - /environment/terminator-relative-position-m - - - /sim/rendering/shaders/skydome - + /environment/ground-visibility-m + /environment/visibility-m + /environment/ground-haze-thickness-m + /rendering/scene/scattering + /environment/terminator-relative-position-m + /environment/mean-terrain-elevation-m + /rendering/scene/overcast + /sim/rendering/eye-altitude-m + /sim/rendering/shaders/skydome - + + + + /sim/rendering/shaders/skydome + + + 2.0 + + + + GL_ARB_shader_objects + GL_ARB_shading_language_100 + GL_ARB_vertex_shader + GL_ARB_fragment_shader + + + + + + true + + material/ambient + material/diffuse + material/specular + material/emissive + material/shininess + ambient-and-diffuse + + transparent + smooth + back + + -1 + RenderBin + + + 0 + texture[0]/image + texture[0]/filter + texture[0]/wrap-s + texture[0]/wrap-t + + texture[0]/internal-format + + + + Shaders/include_fog.vert + Shaders/default.vert + Shaders/include_fog.frag + Shaders/terrain-nocolor.frag + + + texture + sampler-2d + 0 + + 0 0 0 0 + + + true + + material/ambient + material/diffuse + material/specular + material/emissive + material/shininess + ambient-and-diffuse + + transparent + transparent + smooth + back + + render-bin/bin-number + render-bin/bin-name + + + 0 + texture[0]/image + texture[0]/filter + texture[0]/wrap-s + texture[0]/wrap-t + + texture[0]/internal-format + + + + Shaders/terrain-haze.vert + Shaders/terrain-haze.frag + + + visibility + float + visibility + + + avisibility + float + avisibility + + + hazeLayerAltitude + float + lthickness + + + scattering + float + scattering + + + terminator + float + terminator + + + terrain_alt + float + terrain_alt + + + overcast + float + overcast + + + eye_alt + float + eye_alt + + + texture + sampler-2d + 0 + + + colorMode + int + 2 + + + lequal + false + + + + + /sim/rendering/shaders/generic @@ -123,7 +261,7 @@ - + Shaders/include_fog.vert Shaders/default.vert Shaders/include_fog.frag Shaders/terrain-nocolor.frag @@ -254,6 +392,8 @@ + + true diff --git a/Environment/environment.xml b/Environment/environment.xml index 9b17450e7..b1fb84d58 100644 --- a/Environment/environment.xml +++ b/Environment/environment.xml @@ -309,6 +309,7 @@ + false false @@ -330,7 +331,7 @@ - 0.05 + 60.0 diff --git a/Environment/local-weather-defaults.xml b/Environment/local-weather-defaults.xml index bd5dcf320..6826b38e7 100644 --- a/Environment/local-weather-defaults.xml +++ b/Environment/local-weather-defaults.xml @@ -25,6 +25,7 @@ 1.0 0.0 1.0 + 11.69524 120000.0 diff --git a/Nasal/local_weather/cloud_definitions.nas b/Nasal/local_weather/cloud_definitions.nas index 495fd4f6b..2f6ffd5d4 100644 --- a/Nasal/local_weather/cloud_definitions.nas +++ b/Nasal/local_weather/cloud_definitions.nas @@ -53,7 +53,7 @@ else if (type == "Cumulus (cloudlet)"){ cloudAssembly.min_height = 500.0; cloudAssembly.max_height = 700.0; cloudAssembly.min_cloud_width = 1300; - cloudAssembly.min_cloud_height = 700; + cloudAssembly.min_cloud_height = 750; cloudAssembly.bottom_shade = 0.7; } else @@ -65,7 +65,7 @@ else if (type == "Cumulus (cloudlet)"){ cloudAssembly.min_height = 600.0; cloudAssembly.max_height = 900.0; cloudAssembly.min_cloud_width = 1300; - cloudAssembly.min_cloud_height = 700; + cloudAssembly.min_cloud_height = 950; cloudAssembly.bottom_shade = 0.4; } @@ -139,7 +139,7 @@ else if (type == "Cu (volume)"){ cloudAssembly.min_height = 800.0; cloudAssembly.max_height = 1100.0; cloudAssembly.min_cloud_width = 1500; - cloudAssembly.min_cloud_height = 1000; + cloudAssembly.min_cloud_height = 1150; cloudAssembly.bottom_shade = 0.4; } @@ -365,8 +365,8 @@ else if (type == "Cumulus (whisp)"){ cloudAssembly.max_width = 600.0 * mult; cloudAssembly.min_height = 400.0 * mult; cloudAssembly.max_height = 600.0 * mult; - cloudAssembly.min_cloud_width = 800 * mult * mult; - cloudAssembly.min_cloud_height = 800 * mult * mult; + cloudAssembly.min_cloud_width = 800; + cloudAssembly.min_cloud_height = 800; cloudAssembly.z_scale = 1.0; #signal that new routines are used @@ -952,7 +952,7 @@ else if (type == "Stratus") { cloudAssembly.min_height = 2000.0 * mult; cloudAssembly.max_height = 2500.0 * mult; cloudAssembly.min_cloud_width = 5000.0; - cloudAssembly.min_cloud_height = 1.1 * cloudAssembly.max_height; + cloudAssembly.min_cloud_height = 50; #1.1 * cloudAssembly.max_height; #signal that new routines are used diff --git a/Nasal/local_weather/compat_layer.nas b/Nasal/local_weather/compat_layer.nas index a0b4e985d..d4db29730 100644 --- a/Nasal/local_weather/compat_layer.nas +++ b/Nasal/local_weather/compat_layer.nas @@ -23,7 +23,7 @@ # create_cloud_array to place clouds from storage arrays into the scenery # get_elevation to get the terrain elevation at given coordinates # get_elevation_vector to get terrain elevation at given coordinate vector - +# set_wxradarecho_storm to provide info about a storm to the wxradar # This file contains portability wrappers for the local weather system: @@ -126,12 +126,17 @@ print("Compatibility layer: tests done."); # features of a 2.4 binary +# switch terrainsampler to active, should be initialized + + features.can_set_light = 1; features.can_set_scattering = 1; features.terrain_presampling = 1; features.terrain_presampling_active = 1; features.can_disable_environment = 1; + + # features of a current GIT binary features.fast_geodinfo = 1; @@ -750,6 +755,36 @@ if (local_weather.dynamics_flag == 1) } + +########################################################### +# place a model +########################################################### + +var place_model = func(path, lat, lon, alt, heading) { + + + +var m = props.globals.getNode("models", 1); + for (var i = 0; 1; i += 1) + if (m.getChild("model", i, 0) == nil) + break; +var model = m.getChild("model", i, 1); + + +model.getNode("path", 1).setValue(path); +model.getNode("latitude-deg", 1).setValue(lat); +model.getNode("longitude-deg", 1).setValue(lon); +model.getNode("elevation-ft", 1).setValue(alt); +model.getNode("heading-deg", 1).setValue(heading); +model.getNode("load", 1).remove(); + + +} + + + + + ########################################################### # place a single cloud using hard-coded system ########################################################### @@ -953,12 +988,65 @@ for(var i = 0; i < n; i=i+1) return elevation; } +########################################################### +# set the wxradar echo of a storm +########################################################### +var set_wxradarecho_storm = func (lat, lon, base, top, radius, ref, turb, type) { + +# look for the next free index in the wxradar property tree entries + +var n = props.globals.getNode("/instrumentation/wxradar", 1); + for (var i = 0; 1; i += 1) + if (n.getChild("storm", i, 0) == nil) + break; +var s = n.getChild("storm", i, 1); + + +s.getNode("latitude-deg",1).setValue(lat); +s.getNode("longitude-deg",1).setValue(lon); +s.getNode("heading-deg",1).setValue(0.0); +s.getNode("base-altitude-ft",1).setValue(base); +s.getNode("top-altitude-ft",1).setValue(top); +s.getNode("radius-nm",1).setValue(radius * m_to_nm); +s.getNode("reflectivity-norm",1).setValue(ref); +s.getNode("turbulence-norm",1).setValue(turb); +s.getNode("type",1).setValue(type); +s.getNode("show",1).setValue(1); +} + +########################################################### +# remove unused echos +########################################################### + +var remove_wxradar_echos = func { + +var distance_to_remove = 70000.0; + +var storms = props.globals.getNode("/instrumentation/wxradar", 1).getChildren("storm"); + +var pos = geo.aircraft_position(); + +foreach (s; storms) + { + var d_sq = local_weather.calc_d_sq(pos.lat(), pos.lon(), s.getNode("latitude-deg").getValue(), s.getNode("longitude-deg").getValue()); + if (d_sq > distance_to_remove * distance_to_remove) + { + s.remove(); + } + } + +} ############################################################ # global variables ############################################################ +# conversions + +var nm_to_m = 1852.00; +var m_to_nm = 1.0/nm_to_m; + # some common abbreviations var lw = "/local-weather/"; diff --git a/Nasal/local_weather/local_weather.nas b/Nasal/local_weather/local_weather.nas index 1262ddb64..95a61e4c0 100644 --- a/Nasal/local_weather/local_weather.nas +++ b/Nasal/local_weather/local_weather.nas @@ -928,6 +928,8 @@ setprop(lw~"current/wind-speed-kt",windspeed_current); setprop("/environment/config/boundary/entry[0]/wind-from-heading-deg",winddir); setprop("/environment/config/boundary/entry[0]/wind-speed-kt",windspeed_ground); +#setprop("/environment/sea/surface/wind-from-east-fps",windspeed_ground * math.sin(winddir * math.pi/180.0)); +#setprop("/environment/sea/surface/wind-from-east-fps",windspeed_ground * math.cos(winddir * math.pi/180.0)); # end hack @@ -1609,6 +1611,12 @@ settimer ( func { setsize(weather_dynamics.cloudQuadtrees,0);},0.1); # to avoid setsize(effectVolumeArray,0); n_effectVolumeArray = 0; + +# clear any wxradar echos + +if (wxradar_support_flag ==1) + {props.globals.getNode("/instrumentation/wxradar", 1).removeChildren("storm");} + # if we have used METAR, we may no longer want to do so metar_flag = 0; @@ -2887,8 +2895,8 @@ var terrain_presampling_start = func (blat, blon, nc, size, alpha) { # initialize the result vector -setsize(terrain_n,20); -for(var j=0;j<20;j=j+1){terrain_n[j]=0;} +setsize(terrain_n,40); +for(var j=0;j<40;j=j+1){terrain_n[j]=0;} if (thread_flag == 1) { @@ -2911,10 +2919,10 @@ else setprop(lw~"tmp/presampling-status", "finished"); } -if (compat_layer.features.terrain_presampling_active == 1) +if (compat_layer.features.terrain_presampling == 1) { print("Starting hard-coded terrain presampling"); - + setprop("/environment/terrain/area[0]/enabled",1); setprop(lw~"tmp/presampling-status", "sampling"); setprop("/environment/terrain/area[0]/enabled", 1 ); setprop("/environment/terrain/area[0]/input/latitude-deg", blat ); @@ -3000,7 +3008,7 @@ var elevation_vec = compat_layer.get_elevation_array(lat_vec, lon_vec); for (i=0; i int(0.5 *n_tot)) {alt_med = i * 500.0; break;} } sum = 0; - for (var i=0; i<20;i=i+1) + for (var i=0; i<40;i=i+1) { sum = sum + terrain_n[i]; if (sum > int(0.3 *n_tot)) {alt_20 = i * 500.0; break;} } - for (var i=0; i<20;i=i+1) {alt_mean = alt_mean + terrain_n[i] * i * 500.0;} + for (var i=0; i<40;i=i+1) {alt_mean = alt_mean + terrain_n[i] * i * 500.0;} alt_mean = alt_mean/n_tot; - for (var i=0; i<20;i=i+1) {if (terrain_n[i] > 0) {alt_min = i * 500.0; break;}} + for (var i=0; i<40;i=i+1) {if (terrain_n[i] > 0) {alt_min = i * 500.0; break;}} var n_max = 0; sum = 0; - for (var i=0; i<19;i=i+1) + for (var i=0; i<39;i=i+1) { sum = sum + terrain_n[i]; if (terrain_n[i] > n_max) {n_max = terrain_n[i];} @@ -3090,6 +3098,11 @@ append(alt_50_array, alt_med); append(alt_20_array, alt_20); append(alt_min_array, alt_min); append(alt_mean_array, alt_mean); + + +current_mean_alt = 0.5 * (current_mean_alt + alt_20); + + } @@ -3592,7 +3605,7 @@ debug_output_flag = getprop(lw~"config/debug-output-flag"); fps_control_flag = getprop(lw~"config/fps-control-flag"); realistic_visibility_flag = getprop(lw~"config/realistic-visibility-flag"); detailed_terrain_interaction_flag = getprop(lw~"config/detailed-terrain-interaction-flag"); -scattering_shader_flag = getprop("/sim/rendering/scattering-shader"); +scattering_shader_flag = getprop("/sim/rendering/shaders/skydome"); } @@ -4257,11 +4270,11 @@ setlistener(lw~"config/target-framerate", func {target_framerate = getprop(lw~"c setlistener(lw~"config/small-scale-persistence", func {weather_tiles.small_scale_persistence = getprop(lw~"config/small-scale-persistence");}); setlistener(lw~"config/ground-haze-factor", func {ground_haze_factor = getprop(lw~"config/ground-haze-factor");}); -setlistener(lw~"config/max-vis-range-m", func {max_vis_range = getprop(lw~"config/max-vis-range-m");}); +setlistener(lw~"config/aux-max-vis-range-m", func {max_vis_range = math.exp(getprop(lw~"config/aux-max-vis-range-m")); setprop(lw~"config/max-vis-range-m",max_vis_range);}); setlistener(lw~"config/temperature-offset-degc", func {temperature_offset = getprop(lw~"config/temperature-offset-degc");}); -setlistener("/sim/rendering/scattering-shader", func {scattering_shader_flag = getprop("/sim/rendering/scattering-shader"); }); +setlistener("/sim/rendering/shaders/skydome", func {scattering_shader_flag = getprop("/sim/rendering/shaders/skydome"); }); } @@ -4273,6 +4286,7 @@ var test = func { var lat = getprop("position/latitude-deg"); var lon = getprop("position/longitude-deg"); +var alt = getprop("position/altitude-ft"); thread_flag = 0; dynamics_flag = 0; @@ -4294,11 +4308,11 @@ presampling_flag = 0; #var pos = geo.aircraft_position(); -debug.dump(geodinfo(lat, lon)); +# debug.dump(geodinfo(lat, lon)); #create_cumulonimbus_cloud(lat, lon, 6000.0, 2.5); -# geo.put_model("Models/Astro/Earth.ac",lat, lon); +local_weather.place_model("Models/Weather/cloudsphere.ac",lat, lon, alt-10000.0, 0.0); #setprop("/environment/terrain/area[0]/input/latitude-deg", lat ); #setprop("/environment/terrain/area[0]/input/longitude-deg", lon ); @@ -4586,7 +4600,7 @@ var ec = "/environment/config/"; # a hash map of the strength for convection associated with terrain types -var landcover_map = {BuiltUpCover: 0.35, Town: 0.35, Freeway:0.35, BarrenCover:0.3, HerbTundraCover: 0.25, GrassCover: 0.2, CropGrassCover: 0.2, EvergreenBroadCover: 0.2, EvergreenNeedleCover: 0.2, Sand: 0.25, Grass: 0.2, Ocean: 0.01, Marsh: 0.05, Lake: 0.01, ShrubCover: 0.15, Landmass: 0.2, CropWoodCover: 0.15, MixedForestCover: 0.15, DryCropPastureCover: 0.25, MixedCropPastureCover: 0.2, IrrCropPastureCover: 0.15, DeciduousBroadCover: 0.1, DeciduousNeedleCover: 0.1, Bog: 0.05, pa_taxiway : 0.35, pa_tiedown: 0.35, pc_taxiway: 0.35, pc_tiedown: 0.35, Glacier: 0.03, SnowCover: 0.04, DryLake: 0.3, IntermittentStream: 0.2, DryCrop: 0.2, Lava: 0.3, GolfCourse: 0.2, Rock: 0.3, Construction: 0.35}; +var landcover_map = {BuiltUpCover: 0.35, Town: 0.35, Freeway:0.35, BarrenCover:0.3, HerbTundraCover: 0.25, GrassCover: 0.2, CropGrassCover: 0.2, EvergreenBroadCover: 0.2, EvergreenNeedleCover: 0.2, Sand: 0.25, Grass: 0.2, Ocean: 0.01, Marsh: 0.05, Lake: 0.01, ShrubCover: 0.15, Landmass: 0.2, CropWoodCover: 0.15, MixedForestCover: 0.15, DryCropPastureCover: 0.25, MixedCropPastureCover: 0.2, IrrCropPastureCover: 0.15, DeciduousBroadCover: 0.1, DeciduousNeedleCover: 0.1, Bog: 0.05, pa_taxiway : 0.35, pa_tiedown: 0.35, pc_taxiway: 0.35, pc_tiedown: 0.35, Glacier: 0.03, SnowCover: 0.04, DryLake: 0.3, IntermittentStream: 0.2, DryCrop: 0.2, Lava: 0.3, GolfCourse: 0.2, Rock: 0.3, Construction: 0.35, PackIce: 0.04, NaturalCrop: 0.2}; # a hash map of average vertical cloud model sizes @@ -4694,11 +4708,12 @@ var detailed_terrain_interaction_flag = 1; var hardcoded_clouds_flag = 1; var realistic_visibility_flag = 0; var scattering_shader_flag = 0; +var wxradar_support_flag = 1; var ground_haze_factor = 1.0; var max_vis_range = 120000.0; var temperature_offset = 0.0; - +var current_mean_alt = 0.0; # globals for framerate controlled cloud management @@ -4758,6 +4773,8 @@ setprop(lw~"effect-volumes/number-active-sat",0); # setprop(lw~"config/max-vis-range-m", 120000.0); setprop(lw~"config/temperature-offset-degc", 0.0); +setprop("/sim/rendering/eye-altitude-m", getprop("/position/altitude-ft") * ft_to_m); + # create properties for tile management setprop(lw~"tiles/tile-counter",0); diff --git a/Nasal/local_weather/weather_dynamics.nas b/Nasal/local_weather/weather_dynamics.nas index 49ff8dae2..8f1615676 100644 --- a/Nasal/local_weather/weather_dynamics.nas +++ b/Nasal/local_weather/weather_dynamics.nas @@ -117,10 +117,24 @@ time_lw = time_lw + dt_lw; # directly referencing /sim/time/sun-angle-rad as uniform doesn't # work since that is a tied property -var sun_angle = 1.57079632675 - getprop("/sim/time/sun-angle-rad"); +#var sun_angle = 1.57079632675 - getprop("/sim/time/sun-angle-rad"); -var terminator_offset = sun_angle / 0.017451 * 110000.0 + 250000.0; -setprop("/environment/terminator-relative-position-m",terminator_offset); +#var terminator_offset = sun_angle / 0.017451 * 110000.0;# + 250000.0; +#setprop("/environment/terminator-relative-position-m",terminator_offset); + +var viewpos = geo.viewer_position(); + +# setprop("/environment/alt-in-haze-m", getprop("/environment/ground-haze-thickness-m")-viewpos.alt()); + +setprop("/sim/rendering/eye-altitude-m", viewpos.alt()); + +if (local_weather.presampling_flag == 1) + { + var mean_terrain_elevation_m = ft_to_m * local_weather.current_mean_alt ; } +else + {var mean_terrain_elevation_m = 0.0;} + +setprop("/environment/mean-terrain-elevation-m", mean_terrain_elevation_m); if (getprop(lw~"timing-loop-flag") ==1) {settimer(timing_loop, 0);} diff --git a/Nasal/local_weather/weather_tile_management.nas b/Nasal/local_weather/weather_tile_management.nas index 25b741d21..aebf4f015 100644 --- a/Nasal/local_weather/weather_tile_management.nas +++ b/Nasal/local_weather/weather_tile_management.nas @@ -53,7 +53,7 @@ var this_frame_action_flag = 0; # use this flag to avoid overlapping tile operat setsize(active_tile_list,0); #append(active_tile_list,0); # tile zero formally containing static objects is always active -var distance_to_load = current_visibility; +var distance_to_load = current_visibility + 10000.0; if (distance_to_load > 65000.0) {distance_to_load = 65000.0;} if (distance_to_load < 29000.0) {distance_to_load = 29000.0;} @@ -64,7 +64,9 @@ if (distance_to_load < 29000.0) {distance_to_load = 29000.0;} #if (distance_to_load < 29000.0) # {distance_to_load = 29000.0;} -var distance_to_remove = distance_to_load + 500.0; +var distance_to_remove = distance_to_load + 20000.0; +if (distance_to_remove > 65500.0) {distance_to_remove = 65500.0;} + # check here if we have a new weather station if METAR is running @@ -202,7 +204,7 @@ foreach (var t; tNode) { -if (getprop(lw~"tile-loop-flag") ==1) {settimer(tile_management_loop, 5.0);} +if (getprop(lw~"tile-loop-flag") ==1) {settimer(tile_management_loop, 4.0);} } @@ -713,6 +715,11 @@ if (local_weather.dynamics_flag ==1) local_weather.assemble_effect_array(); +if (local_weather.wxradar_support_flag == 1) + { + local_weather.remove_wxradar_echos(); + } + } diff --git a/Nasal/local_weather/weather_tiles.nas b/Nasal/local_weather/weather_tiles.nas index ffc41e383..e3d28581a 100644 --- a/Nasal/local_weather/weather_tiles.nas +++ b/Nasal/local_weather/weather_tiles.nas @@ -112,14 +112,21 @@ alt_offset = 0.0; #create_4_8_cirrocumulus_streaks(blat, blon, 10000.0 + alt_offset, alpha); #create_4_8_alttstratus_streaks(blat, blon, 5000+alt_offset, alpha) ; +# create_4_8_alttstratus_streaks(blat, blon, 5000+alt_offset, alpha) ; #create_2_8_cirrocumulus_patches(blat, blon, 13000+alt_offset, alpha) ; -#create_8_8_nimbus_rain(blat, blon, 3000+alt_offset, alpha, 0.3) ; +# create_8_8_nimbus_rain(blat, blon, 3000.0, alpha, 0.3) ; #create_8_8_tstratus(blat, blon, 5000+alt_offset, alpha); -#create_8_8_cirrostratus(blat, blon, 5000+alt_offset, alpha); -create_thunderstorm_scenario (blat, blon, 3000.0, alpha); + +# create_8_8_cirrostratus(blat, blon, 30000.0, alpha); + +#create_thunderstorm_scenario (blat, blon, 3000.0, alpha); #create_big_thunderstorm (blat, blon, 3000.0, alpha); +#create_2_8_cirrus(blat, blon, 30000.0, alpha); +#create_2_8_cirrus(blat, blon, 20000.0, alpha); +create_4_8_cirrus(blat, blon, 30000.0, alpha); + #create_4_8_altocumulus_perlucidus(blat, blon, 5000+alt_offset, alpha) ; #create_detailed_stratocumulus_bank(blat, blon, 4000+alt_offset,alpha); @@ -193,7 +200,7 @@ else #rn = 0.1; -if (rn > 0.8) +if (rn > 0.833) { # cloud scenario 1: weak cumulus development and blue thermals @@ -213,7 +220,7 @@ if (rn > 0.8) # and specify the atmosphere local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.0, 25000.0, 30000.0, 0.9, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.6) +else if (rn > 0.666) { # cloud scenario 2: some Cirrocumulus patches @@ -227,7 +234,7 @@ else if (rn > 0.6) # and specify the atmosphere local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.1, alt+alt_offset +30000.0, alt+alt_offset + 35000.0, 0.9, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.4) +else if (rn > 0.5) { # cloud scenario 3: Cirrostratus undulatus over weak cumulus @@ -240,7 +247,7 @@ else if (rn > 0.4) local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.15, alt+alt_offset +28000.0, alt+alt_offset + 32000.0, 0.9, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.2) +else if (rn > 0.333) { # cloud scenario 4: Cirrostratus undulatus streak @@ -252,7 +259,7 @@ else if (rn > 0.2) # and specify the atmosphere local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.15, alt+alt_offset +28000.0, alt+alt_offset + 32000.0, 0.9, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.0) +else if (rn > 0.166) { # cloud scenario 5: Cirrus @@ -267,7 +274,13 @@ else if (rn > 0.0) # and specify the atmosphere local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.0, alt+alt_offset +28000.0, alt+alt_offset + 33000.0, 0.9, alt+alt_offset, alt+alt_offset + 2500.0); } +else if (rn > 0.0) + { + # cloud scenario 6: strong Cirrus cover + create_4_8_cirrus(blat, blon, alt + alt_offset + 35000.0, alpha); + local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.0, alt+alt_offset +28000.0, alt+alt_offset + 33000.0, 0.9, alt+alt_offset, alt+alt_offset + 2500.0); + } # store convective altitude and strength @@ -528,18 +541,12 @@ else if (rn > 0.666) } else if (rn > 0.555) { - # cloud scenario 4: Cumulonimbus banks + # cloud scenario 4: thin Stratus streaks strength = 0.7 + rand() * 0.3; local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0); - for (var i = 0; i < 3; i = i + 1) - { - x = 2.0 * (rand()-0.5) * 16000; - y = 2.0 * (rand()-0.5) * 16000; - - create_cloud_bank("Cumulonimbus", blat+get_lat(x,y,phi), blon+get_lon(x,y,phi), alt+alt_offset, 1600.0, 800.0, 3000.0, 9, alpha); - } + create_4_8_alttstratus_streaks(blat, blon, alt+alt_offset +10000.0, alpha); # and specify the atmosphere local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.0, alt+alt_offset +20000.0, alt+alt_offset + 25000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); @@ -854,8 +861,6 @@ if (rand() < small_scale_persistence) else {rnd_store = rn;} -#rn = 0.1; - if (rn > 0.8) { @@ -1001,7 +1006,7 @@ local_weather.set_weather_station(blat, blon, alt_offset, vis, T, D, p * hp_to_i # set a closed Nimbostratus layer -var alt = spread * 400.0; +var alt = spread * 400.0 + local_weather.cloud_vertical_size_map["Nimbus"] * 0.5 * m_to_ft; var strength = 0.0; #var alt = 3000.0; @@ -2533,7 +2538,7 @@ var create_8_8_cirrostratus = func (lat, lon, alt, alpha) { if (local_weather.hardcoded_clouds_flag == 1) {alt = alt - local_weather.offset_map["Cirrostratus"];} -local_weather.create_streak("Cirrostratus",lat,lon,alt,500.0,30,1250.0,0.0,400.0,30,1250.0,0.0,400.0,alpha,1.0); +local_weather.create_streak("Cirrostratus",lat,lon,alt,500.0,30,1300.0,0.0,400.0,30,1300.0,0.0,400.0,alpha,1.0); } var create_8_8_nimbus = func (lat, lon, alt, alpha) { @@ -3060,6 +3065,19 @@ else } +var create_4_8_cirrus = func (lat, lon, alt, alpha) { + +var phi = alpha * math.pi/180.0; + +var x = 2.0 * (rand()-0.5) * 1000; +var y = 2.0 * (rand()-0.5) * 1000; + + +local_weather.create_streak("Cirrus",lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt,1500.0,4,10000.0,0.0, 3000.0, 4,10000.0,0.0,3000.0,alpha,1.0); + +} + + var create_2_8_stratus = func (lat, lon, alt, alpha) { if (local_weather.hardcoded_clouds_flag == 1) {alt = alt - local_weather.offset_map["Stratus"];} @@ -3430,7 +3448,14 @@ append(elat, lat); append(elon, lon); append(erad, 4000.0 * scale * 1.2); # set precipitation, visibility, updraft and turbulence in the cloud -local_weather.create_effect_volume(1, lat, lon, 4000.0 * 0.7 * scale, 4000.0 * 0.7 * scale , 0.0, 0.0, 20000.0, 600.0, 0.8, -1, 0.6, 15.0,1 ,-1); +local_weather.create_effect_volume(1, lat, lon, 4000.0 * 0.7 * scale, 4000.0 * 0.7 * scale , 0.0, 0.0, 20000.0, 1100.0, 0.8, -1, 0.6, 15.0,1 ,-1); + +# set the wxradar echo + +if (local_weather.wxradar_support_flag == 1) + { + compat_layer.set_wxradarecho_storm (lat, lon, alt, 20000.0, 4000.0 * 0.7 * scale, 1.0, 0.6, "single_cell"); + } } @@ -3458,7 +3483,15 @@ append(elat, lat); append(elon, lon); append(erad, 6000.0 * scale * 1.2); # set precipitation, visibility, updraft and turbulence in the cloud -local_weather.create_effect_volume(1, lat, lon, 6000.0 * 0.7 * scale, 6000.0 * 0.7 * scale , 0.0, 0.0, 20000.0, 500.0, 1.0, -1, 0.8, 20.0,1,-1 ); +local_weather.create_effect_volume(1, lat, lon, 6000.0 * 0.7 * scale, 6000.0 * 0.7 * scale , 0.0, 0.0, 20000.0, 1100.0, 1.0, -1, 0.8, 20.0,1,-1 ); + +# set the wxradar echo + +if (local_weather.wxradar_support_flag == 1) + { + compat_layer.set_wxradarecho_storm (lat, lon, alt, 20000.0, 6000.0 * 0.7 * scale, 1.0, 0.8, "single_cell"); + } + } @@ -3492,7 +3525,14 @@ local_weather.create_layer("Stratus (thin)", lat+get_lat(0,-4000,phi), lon+get_l # set the exclusion region for the Cumulus layer append(elat, lat); append(elon, lon); append(erad, 7500.0 * scale * 1.2); -local_weather.create_effect_volume(1, lat, lon, 7500.0 * 0.7 * scale, 7500.0 * 0.7 * scale , 0.0, 0.0, 20000.0, 500.0, 1.0, -1, 1.0, 25.0,1,-1 ); +local_weather.create_effect_volume(1, lat, lon, 7500.0 * 0.7 * scale, 7500.0 * 0.7 * scale , 0.0, 0.0, 20000.0, 1100.0, 1.0, -1, 1.0, 25.0,1,-1 ); + +# set the wxradar echo + +if (local_weather.wxradar_support_flag == 1) + { + compat_layer.set_wxradarecho_storm (lat, lon, alt, 24000.0, 7500.0 * 0.7 * scale, 1.0, 1.0, "single_cell"); + } } diff --git a/Shaders/3dcloud-lightfield.frag b/Shaders/3dcloud-lightfield.frag new file mode 100644 index 000000000..dd90fdddf --- /dev/null +++ b/Shaders/3dcloud-lightfield.frag @@ -0,0 +1,15 @@ +uniform sampler2D baseTexture; +varying float fogFactor; + +varying vec3 hazeColor; + +void main(void) +{ + vec4 base = texture2D( baseTexture, gl_TexCoord[0].st); + vec4 finalColor = base * gl_Color; + //gl_FragColor.rgb = mix(gl_Fog.color.rgb, finalColor.rgb, fogFactor ); + gl_FragColor.rgb = mix(hazeColor, finalColor.rgb, fogFactor ); + //gl_FragColor.a = mix(0.0, finalColor.a, fogFactor); + gl_FragColor.a = mix(0.0, finalColor.a, 1.0 - 0.5 * (1.0 - fogFactor)); +} + diff --git a/Shaders/3dcloud-lightfield.vert b/Shaders/3dcloud-lightfield.vert new file mode 100644 index 000000000..0f512fbea --- /dev/null +++ b/Shaders/3dcloud-lightfield.vert @@ -0,0 +1,169 @@ +// -*-C++-*- +#version 120 + +varying float fogFactor; +varying vec3 hazeColor; + +uniform float range; // From /sim/rendering/clouds3d-vis-range +uniform float scattering; +uniform float terminator; +uniform float altitude; + +attribute vec3 usrAttr1; +attribute vec3 usrAttr2; + +float shade_factor = usrAttr1.g; +float cloud_height = usrAttr1.b; +float bottom_factor = usrAttr2.r; +float middle_factor = usrAttr2.g; +float top_factor = usrAttr2.b; + +const float EarthRadius = 5800000.0; + +// light_func is a generalized logistic function fit to the light intensity as a function +// of scaled terminator position obtained from Flightgear core + +float light_func (in float x, in float a, in float b, in float c, in float d, in float e) +{ +x = x-0.5; + +// use the asymptotics to shorten computations +if (x > 30.0) {return e;} +if (x < -15.0) {return 0.0;} + + +return e / pow((1.0 + a * exp(-b * (x-c)) ),(1.0/d)); +} + +void main(void) +{ + + float intensity; + gl_TexCoord[0] = gl_MultiTexCoord0; + vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0); + vec4 l = gl_ModelViewMatrixInverse * vec4(0.0,0.0,1.0,1.0); + vec3 u = normalize(ep.xyz - l.xyz); + + // Find a rotation matrix that rotates 1,0,0 into u. u, r and w are + // the columns of that matrix. + vec3 absu = abs(u); + vec3 r = normalize(vec3(-u.y, u.x, 0.0)); + vec3 w = cross(u, r); + + // Do the matrix multiplication by [ u r w pos]. Assume no + // scaling in the homogeneous component of pos. + gl_Position = vec4(0.0, 0.0, 0.0, 1.0); + gl_Position.xyz = gl_Vertex.x * u; + gl_Position.xyz += gl_Vertex.y * r; + gl_Position.xyz += gl_Vertex.z * w; + // Apply Z scaling to allow sprites to be squashed in the z-axis + gl_Position.z = gl_Position.z * gl_Color.w; + + // Now shift the sprite to the correct position in the cloud. + gl_Position.xyz += gl_Color.xyz; + + // Determine a lighting normal based on the vertex position from the + // center of the cloud, so that sprite on the opposite side of the cloud to the sun are darker. + float n = dot(normalize(-gl_LightSource[0].position.xyz), + normalize(vec3(gl_ModelViewMatrix * vec4(- gl_Position.x, - gl_Position.y, - gl_Position.z, 0.0)))); + + // Determine the position - used for fog and shading calculations + vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Position); + float fogCoord = abs(ecPosition.z); + + // Determine the shading of the vertex. We shade it based on it's position + // in the cloud relative to the sun, and it's vertical position in the cloud. + float shade = mix(shade_factor, top_factor, smoothstep(-0.3, 0.3, n)); + //if (n < 0) { + // shade = mix(top_factor, shade_factor, abs(n)); + //} + + if (gl_Position.z < 0.5 * cloud_height) { + shade = min(shade, mix(bottom_factor, middle_factor, gl_Position.z * 2.0 / cloud_height)); + } else { + shade = min(shade, mix(middle_factor, top_factor, gl_Position.z * 2.0 / cloud_height - 1.0)); + } + + //float h = gl_Position.z / cloud_height; + //if (h < 0.5) { + // shade = min(shade, mix(bottom_factor, middle_factor, smoothstep(0.0, 0.5, h))); + //} else { + // shade = min(shade, mix(middle_factor, top_factor, smoothstep(2.0 * (h - 0.5))); + // } + + // Final position of the sprite + vec3 relVector = gl_Position.xyz - ep.xyz; + gl_Position = gl_ModelViewProjectionMatrix * gl_Position; + + + + // Light at the final position + + // first obtain normal to sun position + + vec3 lightFull = (gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz; + vec3 lightHorizon = normalize(vec3(lightFull.x,lightFull.y, 0.0)); + + // yprime is the distance of the vertex into sun direction, corrected for altitude + // the altitude correction is clamped to reasonable values, sometimes altitude isn't parsed correctly, leading + // to overbright or overdark clouds + // float vertex_alt = clamp(altitude * 0.30480 + relVector.z,1000.0,10000.0); + float vertex_alt = clamp(altitude + relVector.z, 300.0, 10000.0); + float yprime = -dot(relVector, lightHorizon); + float yprime_alt = yprime -sqrt(2.0 * EarthRadius * vertex_alt); + + // compute the light at the position + vec4 light_diffuse; + + float lightArg = (terminator-yprime_alt)/100000.0; + + light_diffuse.b = light_func(lightArg, 1.330e-05, 0.264, 2.227, 1.08e-05, 1.0); + light_diffuse.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0); + light_diffuse.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0); + light_diffuse.a = 0.0; + + intensity = length(light_diffuse); + light_diffuse = intensity * normalize(mix(light_diffuse, 2.0*vec4 (0.55, 0.6, 0.8, 1.0), (1.0 - smoothstep(0.3,0.8, scattering)))); + + + + + //gl_FrontColor = gl_LightSource[0].diffuse * shade + gl_FrontLightModelProduct.sceneColor; + gl_FrontColor = light_diffuse * shade + gl_FrontLightModelProduct.sceneColor; + + // As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out. + gl_FrontColor.a = min(smoothstep(10.0, 100.0, fogCoord), 1.0 - smoothstep(range*0.9, range, fogCoord)); + //gl_BackColor = gl_FrontColor; + + // Fog doesn't affect clouds as much as other objects. + float fadeScale = 0.05 + 0.2 * log(fogCoord/1000.0); + if (fadeScale < 0.05) fadeScale = 0.05; + fogFactor = exp( -gl_Fog.density * fogCoord * fadeScale); + + + // Fog doesn't affect clouds as much as other objects. + //fogFactor = exp( -gl_Fog.density * fogCoord * 0.5); + //fogFactor = clamp(fogFactor, 0.0, 1.0); + +// haze of ground haze shader is slightly bluish + //hazeColor = vec3 (gl_LightSource[0].diffuse.x, gl_LightSource[0].diffuse.y, gl_LightSource[0].diffuse.z); + hazeColor = light_diffuse.xyz; + hazeColor.x = hazeColor.x * 0.83; + hazeColor.y = hazeColor.y * 0.9; + hazeColor = hazeColor * scattering; + + // in sunset or sunrise conditions, do extra shading of clouds + + // two times terminator width governs how quickly light fades into shadow + float terminator_width = 200000.0; + float earthShade = 0.9 * smoothstep(terminator_width+ terminator, -terminator_width + terminator, yprime_alt) + 0.1; + + // change haze color to blue hue for strong fogging + intensity = length(hazeColor); + hazeColor = intensity * normalize(mix(hazeColor, 2.0* vec3 (0.55, 0.6, 0.8), (1.0 - smoothstep(0.3,0.8,scattering)))); + + + hazeColor = hazeColor * earthShade; + gl_FrontColor.xyz = gl_FrontColor.xyz * earthShade; + gl_BackColor = gl_FrontColor; +} diff --git a/Shaders/cloud-static-lightfield.frag b/Shaders/cloud-static-lightfield.frag new file mode 100644 index 000000000..1c84c0a47 --- /dev/null +++ b/Shaders/cloud-static-lightfield.frag @@ -0,0 +1,12 @@ +uniform sampler2D baseTexture; +varying float fogFactor; + +varying vec3 hazeColor; + +void main(void) +{ + vec4 base = texture2D( baseTexture, gl_TexCoord[0].st); + vec4 finalColor = base * gl_Color; + gl_FragColor.rgb = mix(hazeColor, finalColor.rgb, fogFactor ); + gl_FragColor.a = mix(0.0, finalColor.a, 1.0 - 0.5 * (1.0 - fogFactor)); +} diff --git a/Shaders/cloud-static-lightfield.vert b/Shaders/cloud-static-lightfield.vert new file mode 100644 index 000000000..1efb10a4e --- /dev/null +++ b/Shaders/cloud-static-lightfield.vert @@ -0,0 +1,119 @@ +// -*-C++-*- +#version 120 + +varying float fogFactor; +varying vec3 hazeColor; + +uniform float terminator; +uniform float altitude; + +const float shade = 1.0; +const float cloud_height = 1000.0; +const float EarthRadius = 5800000.0; + +// light_func is a generalized logistic function fit to the light intensity as a function +// of scaled terminator position obtained from Flightgear core + +float light_func (in float x, in float a, in float b, in float c, in float d, in float e) +{ +x = x-0.5; + +// use the asymptotics to shorten computations +if (x > 30.0) {return e;} +if (x < -15.0) {return 0.0;} + + +return e / pow((1.0 + a * exp(-b * (x-c)) ),(1.0/d)); +} + +void main(void) +{ + + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + //gl_TexCoord[0] = gl_MultiTexCoord0 + vec4(textureIndexX, textureIndexY, 0.0, 0.0); + vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0); + vec4 l = gl_ModelViewMatrixInverse * vec4(0.0,0.0,1.0,1.0); + vec3 u = normalize(ep.xyz - l.xyz); + + gl_Position = vec4(0.0, 0.0, 0.0, 1.0); + gl_Position.x = gl_Vertex.x; + gl_Position.y += gl_Vertex.y; + gl_Position.z += gl_Vertex.z; + gl_Position.xyz += gl_Color.xyz; + + + // Determine a lighting normal based on the vertex position from the + // center of the cloud, so that sprite on the opposite side of the cloud to the sun are darker. + float n = dot(normalize(-gl_LightSource[0].position.xyz), + normalize(mat3x3(gl_ModelViewMatrix) * (- gl_Position.xyz)));; + + // Determine the position - used for fog and shading calculations + vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Position); + float fogCoord = abs(ecPosition.z); + float fract = smoothstep(0.0, cloud_height, gl_Position.z + cloud_height); + + vec3 relVector = gl_Position.xyz - ep.xyz; + gl_Position = gl_ModelViewProjectionMatrix * gl_Position; + + // Light at the final position + + // first obtain normal to sun position + + vec3 lightFull = (gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz; + vec3 lightHorizon = normalize(vec3(lightFull.x,lightFull.y, 0.0)); + + // yprime is the distance of the vertex into sun direction, corrected for altitude + //float vertex_alt = max(altitude * 0.30480 + relVector.z,100.0); + float vertex_alt = altitude + relVector.z; + float yprime = -dot(relVector, lightHorizon); + float yprime_alt = yprime -sqrt(2.0 * EarthRadius * vertex_alt); + + // compute the light at the position + vec4 light_diffuse; + + float lightArg = (terminator-yprime_alt)/100000.0; + + light_diffuse.b = light_func(lightArg, 1.330e-05, 0.264, 2.827, 1.08e-05, 1.0); + light_diffuse.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0); + light_diffuse.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0); + light_diffuse.a = 0.0; + + +// Determine the shading of the sprite based on its vertical position and position relative to the sun. + n = min(smoothstep(-0.5, 0.0, n), fract); +// Determine the shading based on a mixture from the backlight to the front + vec4 backlight = light_diffuse * shade; + + gl_FrontColor = mix(backlight, gl_LightSource[0].diffuse, n); + gl_FrontColor += gl_FrontLightModelProduct.sceneColor; + + // As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out. + gl_FrontColor.a = min(smoothstep(100.0, 250.0, fogCoord), 1.0 - smoothstep(70000.0, 75000.0, fogCoord)); + + // Fog doesn't affect rain as much as other objects. + //fogFactor = exp( -gl_Fog.density * fogCoord * 0.4); + //fogFactor = clamp(fogFactor, 0.0, 1.0); + +float fadeScale = 0.05 + 0.2 * log(fogCoord/1000.0); + if (fadeScale < 0.05) fadeScale = 0.05; + fogFactor = exp( -gl_Fog.density * fogCoord * fadeScale); + + hazeColor = light_diffuse.xyz; + hazeColor.x = hazeColor.x * 0.83; + hazeColor.y = hazeColor.y * 0.9; + + // in sunset or sunrise conditions, do extra shading of clouds + + + + // two times terminator width governs how quickly light fades into shadow + float terminator_width = 200000.0; + + // now dim the light + float earthShade = 0.9 * smoothstep(terminator_width+ terminator, -terminator_width + terminator, yprime_alt) + 0.1; + + hazeColor = hazeColor * earthShade; + gl_FrontColor.xyz = gl_FrontColor.xyz * earthShade; + gl_BackColor = gl_FrontColor; + +} diff --git a/Shaders/rain-layer-lightfield.frag b/Shaders/rain-layer-lightfield.frag new file mode 100644 index 000000000..000da97c8 --- /dev/null +++ b/Shaders/rain-layer-lightfield.frag @@ -0,0 +1,12 @@ +uniform sampler2D baseTexture; +varying float fogFactor; + +varying vec3 hazeColor; + +void main(void) +{ + vec4 base = texture2D( baseTexture, gl_TexCoord[0].st); + vec4 finalColor = base * gl_Color; + gl_FragColor.rgb = mix(hazeColor, finalColor.rgb, fogFactor ); + gl_FragColor.a = mix(0.0, finalColor.a, fogFactor); +} diff --git a/Shaders/rain-layer-lightfield.vert b/Shaders/rain-layer-lightfield.vert new file mode 100644 index 000000000..b212a867a --- /dev/null +++ b/Shaders/rain-layer-lightfield.vert @@ -0,0 +1,122 @@ +// -*-C++-*- +#version 120 + +varying float fogFactor; +varying vec3 hazeColor; + +uniform float range; // From /sim/rendering/clouds3d-vis-range +uniform float scattering; +uniform float terminator; +uniform float altitude; + + +float shade = 0.8; +float cloud_height = 1000.0; +const float EarthRadius = 5800000.0; + +// light_func is a generalized logistic function fit to the light intensity as a function +// of scaled terminator position obtained from Flightgear core + +float light_func (in float x, in float a, in float b, in float c, in float d, in float e) +{ +x = x-0.5; +return e / pow((1.0 + a * exp(-b * (x-c)) ),(1.0/d)); +} + +void main(void) +{ + + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + //gl_TexCoord[0] = gl_MultiTexCoord0 + vec4(textureIndexX, textureIndexY, 0.0, 0.0); + vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0); + vec4 l = gl_ModelViewMatrixInverse * vec4(0.0,0.0,1.0,1.0); + vec3 u = normalize(ep.xyz - l.xyz); + + gl_Position = vec4(0.0, 0.0, 0.0, 1.0); + gl_Position.x = gl_Vertex.x; + gl_Position.y += gl_Vertex.y; + gl_Position.z += gl_Vertex.z; + gl_Position.xyz += gl_Color.xyz; + + + + // Determine a lighting normal based on the vertex position from the + // center of the cloud, so that sprite on the opposite side of the cloud to the sun are darker. + float n = dot(normalize(-gl_LightSource[0].position.xyz), + normalize(mat3x3(gl_ModelViewMatrix) * (- gl_Position.xyz)));; + + // Determine the position - used for fog and shading calculations + vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Position); + float fogCoord = abs(ecPosition.z); + float fract = smoothstep(0.0, cloud_height, gl_Position.z + cloud_height); + + vec3 relVector = gl_Position.xyz - ep.xyz; + gl_Position = gl_ModelViewProjectionMatrix * gl_Position; + + +// Light at the final position + + // first obtain normal to sun position + + vec3 lightFull = (gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz; + vec3 lightHorizon = normalize(vec3(lightFull.x,lightFull.y, 0.0)); + + // yprime is the distance of the vertex into sun direction, corrected for altitude + float vertex_alt = max(altitude * 0.30480 + relVector.z,100.0); + float yprime = -dot(relVector, lightHorizon); + float yprime_alt = yprime -sqrt(2.0 * EarthRadius * vertex_alt); + + // compute the light at the position + vec4 light_diffuse; + + float lightArg = (terminator-yprime_alt)/100000.0; + + light_diffuse.b = light_func(lightArg, 1.330e-05, 0.264, 2.827, 1.08e-05, 1.0); + light_diffuse.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0); + light_diffuse.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0); + light_diffuse.a = 0.0; + + //light_diffuse = light_diffuse * scattering; + float intensity = length(light_diffuse); + light_diffuse = intensity * normalize(mix(light_diffuse, 2.0*vec4 (0.55, 0.6, 0.8, 1.0), (1.0 - smoothstep(0.3,0.8, scattering)))); + +// Determine the shading of the sprite based on its vertical position and position relative to the sun. + n = min(smoothstep(-0.5, 0.0, n), fract); +// Determine the shading based on a mixture from the backlight to the front + vec4 backlight = gl_LightSource[0].diffuse * shade; + + gl_FrontColor = mix(backlight, gl_LightSource[0].diffuse, n); + gl_FrontColor += gl_FrontLightModelProduct.sceneColor; + + // As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out. + gl_FrontColor.a = min(smoothstep(100.0, 250.0, fogCoord), 1.0 - smoothstep(range*0.9, range, fogCoord)); + gl_BackColor = gl_FrontColor; + + // Fog doesn't affect rain as much as other objects. + //fogFactor = exp( -gl_Fog.density * fogCoord * 0.4); + //fogFactor = clamp(fogFactor, 0.0, 1.0); + +float fadeScale = 0.05 + 0.2 * log(fogCoord/1000.0); + if (fadeScale < 0.05) fadeScale = 0.05; + fogFactor = exp( -gl_Fog.density * 1.0 * fogCoord * fadeScale); + + hazeColor = light_diffuse.xyz; + hazeColor.x = hazeColor.x * 0.83; + hazeColor.y = hazeColor.y * 0.9; + hazeColor = hazeColor * scattering; + +// change haze color to blue hue for strong fogging + intensity = length(hazeColor); + hazeColor = intensity * normalize(mix(hazeColor, 2.0 * vec3 (0.55, 0.6, 0.8), (1.0-smoothstep(0.3,0.8,scattering)))); + + // two times terminator width governs how quickly light fades into shadow + float terminator_width = 200000.0; + + // now dim the light + float earthShade = 0.9 * smoothstep(terminator_width+ terminator, -terminator_width + terminator, yprime_alt) + 0.1; + + hazeColor = hazeColor * earthShade; + gl_FrontColor.xyz = gl_FrontColor.xyz * earthShade; + gl_BackColor = gl_FrontColor; + +} diff --git a/Shaders/skydome.frag b/Shaders/skydome.frag index c50309fc5..a65f5e5d9 100644 --- a/Shaders/skydome.frag +++ b/Shaders/skydome.frag @@ -7,8 +7,21 @@ varying vec3 rayleigh; varying vec3 mie; varying vec3 eye; -varying float ct; - +varying vec3 hazeColor; +varying float ct; +//varying float cosphi; +varying float delta_z; +varying float alt; +varying float earthShade; + +uniform float overcast; +uniform float saturation; +uniform float visibility; +uniform float avisibility; +uniform float scattering; + +const float EarthRadius = 5800000.0; + float miePhase(in float cosTheta, in float g) { float g2 = g*g; @@ -32,36 +45,154 @@ void main() { float cosTheta = dot(normalize(eye), gl_LightSource[0].position.xyz); + // position of the horizon line + + float lAltitude = alt + delta_z; + float radiusEye = EarthRadius + alt; + float radiusLayer = EarthRadius + lAltitude; + float cthorizon; + float ctterrain; + + if (radiusEye > radiusLayer) cthorizon = -sqrt(radiusEye * radiusEye - radiusLayer * radiusLayer)/radiusEye; + else cthorizon = sqrt(radiusLayer * radiusLayer - radiusEye * radiusEye)/radiusLayer; + + ctterrain = -sqrt(radiusEye * radiusEye - EarthRadius * EarthRadius)/radiusEye; vec3 color = rayleigh * rayleighPhase(cosTheta); color += mie * miePhase(cosTheta, -0.8); - vec3 white = vec3(1.0,1.0,1.0); - - - //float scale = dot(normalize(white),normalize(color)); - //float scale1 = 1.0 - exp(-5.0 * length(color)); - //float scale2 = length(color)/length(white); - - //if (scale1>1.0) color = color/scale1; - - //color = color/scale1; - + vec3 black = vec3(0.0,0.0,0.0); - if (color.x > 0.8) color.x = 0.8 + 0.8* log(color.x/0.8); - if (color.y > 0.8) color.y = 0.8 + 0.8* log(color.y/0.8); - if (color.z > 0.8) color.z = 0.8 + 0.8* log(color.z/0.8); + float ovc = overcast; - vec3 fogColor = vec3 (gl_Fog.color.x, gl_Fog.color.y, gl_Fog.color.z); - - if (ct > -0.03) color = mix(color, fogColor ,smoothstep(0.2, -0.2, ct)); - else color = mix (color, fogColor, smoothstep(0.2,-0.2,-0.03)); + + float sat = 1.0 - ((1.0 - saturation) * 2.0); + if (sat < 0.3) sat = 0.3; + + + // float wscale = 1.732; +// an overexposure filter, the log() seems to be pretty expensive though - +// if (color.x > 0.8) color.x = 0.8 + 0.8* log(color.x/0.8); +// if (color.y > 0.8) color.y = 0.8 + 0.8* log(color.y/0.8); +// if (color.z > 0.8) color.z = 0.8 + 0.8* log(color.z/0.8); + +//vec3 fogColor = vec3 (gl_Fog.color.x, gl_Fog.color.y, gl_Fog.color.z); + + +// reduce the whiteout near the horizon generated by the single scattering approximation + +if (ct > cthorizon) color = mix(color, black ,smoothstep(0.2+cthorizon, -0.2+cthorizon, ct)); +else color = mix (color, black, smoothstep(0.2+cthorizon,-0.2+cthorizon, cthorizon)); + + + + +// fog computations for a ground haze layer, extending from zero to lAltitude + + + +float transmission; +float vAltitude; +float delta_zv; + +float costheta = ct; + +float vis= visibility; + +// hack - in an effect volume the visibility only may be reduced, so we take care here +if (avisibility < visibility){vis = avisibility;} + + if (delta_z > 0.0) // we're inside the layer + { + if (costheta>0.0 + ctterrain) // looking up, view ray intersecting upper layer edge + { + transmission = exp(-min((delta_z/max(costheta,0.1)),25000.0)/vis); + //transmission = 1.0; + vAltitude = min(vis * costheta, delta_z); + delta_zv = delta_z - vAltitude; + } + + else // looking down, view range intersecting terrain (which may not be drawn) + { + transmission = exp(alt/vis/costheta); + vAltitude = min(-vis * costheta, alt); + delta_zv = delta_z + vAltitude; + } + } + else // we see the layer from above + { + if (costheta < 0.0 + cthorizon) + { + transmission = exp(-min(lAltitude/abs(costheta),25000.0)/vis); + transmission = transmission * exp(-alt/avisibility/abs(costheta)); + transmission = 1.0 - (1.0 - transmission) * smoothstep(0+cthorizon, -0.02+cthorizon, costheta); + vAltitude = min(lAltitude, -vis * costheta); + delta_zv = vAltitude; + } + else + { + transmission = 1.0; + delta_zv = 0.0; + } + } + +// combined intensity reduction by cloud shading and fog self-shading, corrected for Weber-Fechner perception law + +float eqColorFactor; + eqColorFactor = 1.0 - 0.1 * delta_zv/vis - (1.0 -scattering); + + + + + +// there's always residual intensity, we should never be driven to zero +if (eqColorFactor < 0.2) eqColorFactor = 0.2; + + +// postprocessing of haze color +vec3 hColor = hazeColor; + +// high altitude desaturation +float intensity = length(hColor); +hColor = intensity * normalize (mix(hColor, intensity * vec3 (1.0,1.0,1.0), 0.7* smoothstep(5000.0, 50000.0, alt))); + +// blue hue +hColor.x = 0.83 * hColor.x; +hColor.y = 0.9 * hColor.y; + + + +// further blueshift when in shadow, either cloud shadow, or self-shadow or Earth shadow, dependent on indirect +// light + +float fade_out = max(0.65 - 0.3 *overcast, 0.45); +intensity = length(hColor); +hColor = intensity * normalize(mix(hColor, 1.5* vec3 (0.45, 0.6, 0.8), 1.0 -smoothstep(0.25, fade_out,earthShade) )); +hColor = intensity * normalize(mix(hColor, 2.0 * vec3 (0.55, 0.6, 0.8), (1.0 - smoothstep(0.3,0.8,eqColorFactor)))); +hColor = hColor * earthShade; + +// accounting for overcast and saturation + + +color = ovc * mix(color, hazeColor * earthShade ,smoothstep(-0.1+ctterrain, 0.0+ctterrain, ct)) + (1-ovc) * color; +color = sat * color + (1.0 - sat) * mix(color, black, smoothstep(0.4+cthorizon,0.2+cthorizon,ct)); + + +// the terrain below the horizon gets drawn in one optical thickness +vec3 terrainHazeColor = eqColorFactor * hColor; +color = mix(color, terrainHazeColor ,smoothstep(0.01 + ctterrain, 0.0+ctterrain, ct)); + +// mix fog the skydome with the right amount of haze + +color = transmission * color + (1.0-transmission) * eqColorFactor * hColor; + + gl_FragColor = vec4(color, 1.0); - gl_FragDepth = 0.1; + gl_FragDepth = 0.1; + } diff --git a/Shaders/skydome.vert b/Shaders/skydome.vert index 5c3505f01..58219e6e6 100644 --- a/Shaders/skydome.vert +++ b/Shaders/skydome.vert @@ -6,19 +6,30 @@ uniform mat4 osg_ViewMatrix; -uniform mat4 osg_ViewMatrixInverse; - +uniform mat4 osg_ViewMatrixInverse; +uniform float hazeLayerAltitude; +uniform float terminator; +uniform float avisibility; +uniform float visibility; +uniform float terrain_alt; + varying vec3 rayleigh; varying vec3 mie; varying vec3 eye; -varying float ct; - +varying vec3 hazeColor; +varying float ct; +//varying float cosphi; +varying float delta_z; +varying float alt; +varying float earthShade; + // Dome parameters from FG and screen const float domeSize = 80000.0; const float realDomeSize = 100000.0; const float groundRadius = 0.984503332 * domeSize; const float altitudeScale = domeSize - groundRadius; - +const float EarthRadius = 5800000.0; + // Dome parameters when calculating scattering // Assuming dome size is 5.0 const float groundLevel = 0.984503332 * 5.0; @@ -35,7 +46,22 @@ uniform float density = 0.5; //1.0 vec3 rayleighK = rK * vec3(5.602, 7.222, 19.644); vec3 mieK = vec3(mK); vec3 sunIntensity = 10.0*vec3(120.0, 125.0, 130.0); - + +// light_func is a generalized logistic function fit to the light intensity as a function +// of scaled terminator position obtained from Flightgear core + +float light_func (in float x, in float a, in float b, in float c, in float d, in float e) +{ +x = x - 0.5; + +// use the asymptotics to shorten computations +if (x > 30.0) {return e;} +if (x < -15.0) {return 0.0;} + +return e / pow((1.0 + a * exp(-b * (x-c)) ),(1.0/d)); +} + + // Find intersections of ray to skydome // ray must be normalized // cheight is camera height @@ -51,7 +77,6 @@ float intersection (in float cheight, in vec3 ray, in float rad2) float outscatterscale(in float costheta) { - if (costheta < -0.12) costheta = -0.12 - 4.0* (costheta+0.12) ; float x = 1.0 - costheta; @@ -89,7 +114,12 @@ void main() // Make it so that 0.0 is ground level and 1.0 is 100km (space) level float altitude = distance(groundPoint, vec4(0.0, 0.0, 0.0, 1.0)); float scaledAltitude = altitude / realDomeSize; - + + // the local horizon angle + float radiusEye = EarthRadius + altitude; + float ctterrain = -sqrt(radiusEye * radiusEye - EarthRadius * EarthRadius)/radiusEye; + + // Camera's position, z is up! float cameraRealAltitude = groundLevel + heightScale*scaledAltitude; vec3 camera = vec3(0.0, 0.0, cameraRealAltitude); @@ -110,21 +140,27 @@ void main() vec3 lightDirection = gl_LightSource[0].position.xyz; // Cos theta of camera's position and sample point - // Since camera is 0,0,z, dot porduct is just the z coordinate + // Since camera is 0,0,z, dot product is just the z coordinate float cameraCosTheta; // If sample is above camera, reverse ray direction if(positionDelta.z < 0.0) cameraCosTheta = -positionDelta.z / deltaLength; else cameraCosTheta = positionDelta.z / deltaLength; + float cameraCosTheta1 = -positionDelta.z / deltaLength; + // Total attenuation from camera to skydome float totalCameraScatter = outscatter(cameraCosTheta, scaledAltitude); - // Do numerical integration of scsattering function from skydome to camera - vec3 color = vec3(0.0); + // Do numerical integration of scattering function from skydome to camera + vec3 color = vec3(0.0); + + // no scattering integrations where terrain is later drawn + if (cameraCosTheta1 > (ctterrain-0.05)) + { for(int i = 0; i < nSamples; i++) { // Altitude of the sample point 0...1 @@ -158,24 +194,98 @@ void main() color += inScatter * deltaLength; sample += positionDelta; } - + } color *= sunIntensity; ct = cameraCosTheta1; rayleigh = rayleighK * color; mie = mieK * color; eye = gl_NormalMatrix * positionDelta; - - - - // We need to move the camera so that the dome appears to be centered around earth + + // We need to move the camera so that the dome appears to be centered around earth // to make the dome render correctly! float moveDown = -altitude; // Center dome on camera moveDown += groundRadius; moveDown += scaledAltitude * altitudeScale; // And move correctly according to altitude // Vertex transformed correctly so that at 100km we are at space border - vec4 finalVertex = realVertex - vec4(0.0, 0.0, 1.0, 0.0) * moveDown; + vec4 finalVertex = realVertex - vec4(0.0, 0.0, 1.0, 0.0) * moveDown; + + // prepare some stuff for a ground haze layer + + delta_z = hazeLayerAltitude - altitude; + alt = altitude; + + + // establish coordinates relative to sun position + vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0); + vec3 lightFull = (gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz; + vec3 lightHorizon = normalize(vec3(lightFull.x,lightFull.y, 0.0) ); + + + vec3 relVector = normalize(finalVertex.xyz - ep.xyz); + + // and compute the twilight shading + + + // yprime is the coordinate from/towards terminator + float yprime; + + if (alt > hazeLayerAltitude) // we're looking from above and can see far + { + if (ct < 0.0) + { + yprime = -dot(relVector,lightHorizon) * altitude/-(ct-0.001); + yprime = yprime -sqrt(2.0 * EarthRadius * hazeLayerAltitude); + } + else // the only haze we see looking up is overcast, assume its altitude + { + yprime = -dot(relVector,lightHorizon) * avisibility; + yprime = yprime -sqrt(2.0 * EarthRadius * 10000.0); + } + } + else + {yprime = -dot(relVector,lightHorizon) * avisibility; + yprime = yprime -sqrt(2.0 * EarthRadius * hazeLayerAltitude); + } + + if (terminator > 1000000.0){yprime = -sqrt(2.0 * EarthRadius * hazeLayerAltitude);} + + //float edgeAlt = max(hazeLayerAltitude - (alt-terrain_alt)/avisibility * visibility, terrain_alt); + + //yprime = yprime -sqrt(2.0 * EarthRadius * edgeAlt); + + float terminator_width = 200000.0; + earthShade = 0.9 * smoothstep((terminator_width+ terminator), (-terminator_width + terminator), yprime) + 0.1; + + +//hazeColor = vec3 (gl_LightSource[0].diffuse.x, gl_LightSource[0].diffuse.y, gl_LightSource[0].diffuse.z); + + //hazeColor.x = hazeColor.x * 0.83; + //hazeColor.y = hazeColor.y * 0.9; + + float lightArg = (terminator-yprime)/100000.0; + vec4 light_diffuse; + light_diffuse.b = light_func(lightArg, 1.330e-05, 0.264, 2.527, 1.08e-05, 1.0); + light_diffuse.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0); + light_diffuse.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0); + light_diffuse.a = 0.0; + hazeColor = light_diffuse.xyz; + + float intensity = length(hazeColor.xyz); + float mie_magnitude = 0.5 * smoothstep(350000.0, 150000.0, terminator -sqrt(2.0 * EarthRadius * terrain_alt)); + float mie_angle = (0.5 * dot(normalize(relVector), normalize(lightFull)) ) + 0.5; + hazeColor = intensity * ((1.0 - mie_magnitude) + mie_magnitude * mie_angle) * normalize(mix(hazeColor, vec3 (0.5, 0.58, 0.65), mie_magnitude * (0.5 - 0.5 * mie_angle)) ); + + +// high altitude desaturation - would be best here this causes a box-like bug for some reason +// so it moved to the fragment shader where it has no issues + +//float intensity = length(hazeColor.xyz); +//hazeColor = intensity * normalize (mix(hazeColor, intensity * vec3 (1.0,1.0,1.0), 0.8* smoothstep(5000.0, 50000.0, alt))); + + + // Transform gl_Position = gl_ModelViewProjectionMatrix * finalVertex; } diff --git a/Shaders/terrain-haze.frag b/Shaders/terrain-haze.frag new file mode 100644 index 000000000..bf14090b9 --- /dev/null +++ b/Shaders/terrain-haze.frag @@ -0,0 +1,285 @@ +// -*-C++-*- + +// written by Thorsten Renk, Oct 2011, based on default.frag +// Ambient term comes in gl_Color.rgb. +varying vec4 diffuse_term; +varying vec3 normal; +varying vec3 relPos; + +//varying vec3 hazeColor; +//varying float fogCoord; + +uniform sampler2D texture; + +//varying float ct; +//varying float delta_z; +//varying float alt; + +varying float earthShade; +//varying float yprime; +//varying float vertex_alt; +varying float yprime_alt; +varying float mie_angle; + + +uniform float visibility; +uniform float avisibility; +uniform float scattering; +uniform float terminator; +uniform float terrain_alt; +uniform float hazeLayerAltitude; +uniform float overcast; +//uniform float altitude; +uniform float eye_alt; + +const float EarthRadius = 5800000.0; +const float terminator_width = 200000.0; + +float alt; + +float luminance(vec3 color) +{ + return dot(vec3(0.212671, 0.715160, 0.072169), color); +} + + +float light_func (in float x, in float a, in float b, in float c, in float d, in float e) +{ +x = x - 0.5; + +// use the asymptotics to shorten computations +if (x > 30.0) {return e;} +if (x < -15.0) {return 0.0;} + +return e / pow((1.0 + a * exp(-b * (x-c)) ),(1.0/d)); +} + +// this determines how light is attenuated in the distance +// physically this should be exp(-arg) but for technical reasons we use a sharper cutoff +// for distance > visibility + +float fog_func (in float targ) +{ + + +float fade_mix; + +// for large altitude > 30 km, we switch to some component of quadratic distance fading to +// create the illusion of improved visibility range + +targ = 1.25 * targ; // need to sync with the distance to which terrain is drawn + + +if (alt < 30000.0) + {return exp(-targ - targ * targ * targ * targ);} +else if (alt < 50000.0) + { + fade_mix = (alt - 30000.0)/20000.0; + return fade_mix * exp(-targ*targ - pow(targ,4.0)) + (1.0 - fade_mix) * exp(-targ - pow(targ,4.0)); + } +else + { + return exp(- targ * targ - pow(targ,4.0)); + } + +} + +void main() +{ + +// this is taken from default.frag + vec3 n; + float NdotL, NdotHV, fogFactor; + vec4 color = gl_Color; + vec3 lightDir = gl_LightSource[0].position.xyz; + vec3 halfVector = gl_LightSource[0].halfVector.xyz; + vec4 texel; + vec4 fragColor; + vec4 specular = vec4(0.0); + float intensity; + + + + vec4 light_specular = gl_LightSource[0].specular; + + // If gl_Color.a == 0, this is a back-facing polygon and the + // normal should be reversed. + n = (2.0 * gl_Color.a - 1.0) * normal; + n = normalize(n); + + NdotL = dot(n, lightDir); + if (NdotL > 0.0) { + color += diffuse_term * NdotL; + NdotHV = max(dot(n, halfVector), 0.0); + if (gl_FrontMaterial.shininess > 0.0) + specular.rgb = (gl_FrontMaterial.specular.rgb + * light_specular.rgb + * pow(NdotHV, gl_FrontMaterial.shininess)); + } + color.a = diffuse_term.a; + // This shouldn't be necessary, but our lighting becomes very + // saturated. Clamping the color before modulating by the texture + // is closer to what the OpenGL fixed function pipeline does. + color = clamp(color, 0.0, 1.0); + texel = texture2D(texture, gl_TexCoord[0].st); + fragColor = color * texel + specular; + + + +// here comes the terrain haze model + + +float delta_z = hazeLayerAltitude - eye_alt; +float dist = length(relPos); + + +if (dist > 40.0) +{ + +alt = eye_alt; + + +float transmission; +float vAltitude; +float delta_zv; +float H; +float distance_in_layer; +float transmission_arg; + +// angle with horizon +float ct = dot(vec3(0.0, 0.0, 1.0), relPos)/dist; + + +// we solve the geometry what part of the light path is attenuated normally and what is through the haze layer + +if (delta_z > 0.0) // we're inside the layer + { + if (ct < 0.0) // we look down + { + distance_in_layer = dist; + //lambda = visibility; + vAltitude = min(distance_in_layer,visibility) * ct; + delta_zv = delta_z - vAltitude; + } + else // we may look through upper layer edge + { + H = dist * ct; + if (H > delta_z) {distance_in_layer = dist/H * delta_z;} + else {distance_in_layer = dist;} + //lambda = visibility; + vAltitude = min(distance_in_layer,visibility) * ct; + delta_zv = delta_z - vAltitude; + } + } + else // we see the layer from above, delta_z < 0.0 + { + H = dist * -ct; + if (H < (-delta_z)) // we don't see into the layer at all, aloft visibility is the only fading + { + distance_in_layer = 0.0; + delta_zv = 0.0; + } + else + { + vAltitude = H + delta_z; + distance_in_layer = vAltitude/H * dist; + vAltitude = min(distance_in_layer,visibility) * (-ct); + delta_zv = vAltitude; + } + } + + +// ground haze cannot be thinner than aloft visibility in the model, +// so we need to use aloft visibility otherwise + + +transmission_arg = (dist-distance_in_layer)/avisibility; + + +float eqColorFactor; + + +if (visibility < avisibility) + { + transmission_arg = transmission_arg + (distance_in_layer/visibility); + // this combines the Weber-Fechner intensity + eqColorFactor = 1.0 - 0.1 * delta_zv/visibility - (1.0 -scattering); + + } +else + { + transmission_arg = transmission_arg + (distance_in_layer/avisibility); + // this combines the Weber-Fechner intensity + eqColorFactor = 1.0 - 0.1 * delta_zv/avisibility - (1.0 -scattering); + } + + +transmission = fog_func(transmission_arg); + +// there's always residual intensity, we should never be driven to zero +if (eqColorFactor < 0.2) eqColorFactor = 0.2; + + +float lightArg = (terminator-yprime_alt)/100000.0; + +vec3 hazeColor; + +hazeColor.b = light_func(lightArg, 1.330e-05, 0.264, 2.527, 1.08e-05, 1.0); +hazeColor.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0); +hazeColor.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0); + + +// now dim the light for haze +earthShade = 0.9 * smoothstep(terminator_width+ terminator, -terminator_width + terminator, yprime_alt) + 0.1; + +// Mie-like factor + +if (lightArg < 5.0) + {intensity = length(hazeColor); + float mie_magnitude = 0.5 * smoothstep(350000.0, 150000.0, terminator-sqrt(2.0 * EarthRadius * terrain_alt)); + hazeColor = intensity * ((1.0 - mie_magnitude) + mie_magnitude * mie_angle) * normalize(mix(hazeColor, vec3 (0.5, 0.58, 0.65), mie_magnitude * (0.5 - 0.5 * mie_angle)) ); + } + +// high altitude desaturation of the haze color + +intensity = length(hazeColor); +hazeColor = intensity * normalize (mix(hazeColor, intensity * vec3 (1.0,1.0,1.0), 0.7* smoothstep(5000.0, 50000.0, alt))); + +// blue hue of haze + +hazeColor.x = hazeColor.x * 0.83; +hazeColor.y = hazeColor.y * 0.9; + + +// additional blue in indirect light +float fade_out = max(0.65 - 0.3 *overcast, 0.45); +intensity = length(hazeColor); +hazeColor = intensity * normalize(mix(hazeColor, 1.5* vec3 (0.45, 0.6, 0.8), 1.0 -smoothstep(0.25, fade_out,earthShade) )); + +// change haze color to blue hue for strong fogging +//intensity = length(hazeColor); +hazeColor = intensity * normalize(mix(hazeColor, 2.0 * vec3 (0.55, 0.6, 0.8), (1.0-smoothstep(0.3,0.8,eqColorFactor)))); + + +// reduce haze intensity when looking at shaded surfaces, only in terminator region + +float shadow = mix( min(1.0 + dot(normal,lightDir),1.0), 1.0, 1.0-smoothstep(0.1, 0.4, transmission)); +hazeColor = mix(shadow * hazeColor, hazeColor, 0.3 + 0.7* smoothstep(250000.0, 400000.0, terminator)); + + +// determine the right mix of transmission and haze + +//fragColor.xyz = transmission * fragColor.xyz + (1.0-transmission) * eqColorFactor * hazeColor * earthShade; + +fragColor.xyz = mix(eqColorFactor * hazeColor * earthShade, fragColor.xyz,transmission); + +gl_FragColor = fragColor; + +} +else // if dist < 40.0 no fogging at all +{ +gl_FragColor = fragColor; +} + +} + diff --git a/Shaders/terrain-haze.vert b/Shaders/terrain-haze.vert new file mode 100644 index 000000000..f1cd4732d --- /dev/null +++ b/Shaders/terrain-haze.vert @@ -0,0 +1,233 @@ +// -*-C++-*- + +// Shader that uses OpenGL state values to do per-pixel lighting +// +// The only light used is gl_LightSource[0], which is assumed to be +// directional. +// +// Diffuse colors come from the gl_Color, ambient from the material. This is +// equivalent to osg::Material::DIFFUSE. +// Haze part added by Thorsten Renk, Oct. 2011 + + +#define MODE_OFF 0 +#define MODE_DIFFUSE 1 +#define MODE_AMBIENT_AND_DIFFUSE 2 + +// The constant term of the lighting equation that doesn't depend on +// the surface normal is passed in gl_{Front,Back}Color. The alpha +// component is set to 1 for front, 0 for back in order to work around +// bugs with gl_FrontFacing in the fragment shader. +varying vec4 diffuse_term; +varying vec3 normal; +varying vec3 relPos; + +varying float earthShade; +//varying float yprime; +//varying float vertex_alt; +varying float yprime_alt; +varying float mie_angle; + + + + +uniform int colorMode; +uniform float hazeLayerAltitude; +uniform float terminator; +uniform float terrain_alt; +uniform float avisibility; +uniform float visibility; +uniform float overcast; +uniform float scattering; + + +// This is the value used in the skydome scattering shader - use the same here for consistency? +const float EarthRadius = 5800000.0; +const float terminator_width = 200000.0; + +float light_func (in float x, in float a, in float b, in float c, in float d, in float e) +{ +//x = x - 0.5; + +// use the asymptotics to shorten computations +if (x < -15.0) {return 0.0;} + +return e / pow((1.0 + a * exp(-b * (x-c)) ),(1.0/d)); +} + + +void main() +{ + + vec4 light_diffuse; + vec4 light_ambient; + + //float yprime_alt; + float yprime; + float lightArg; + float intensity; + float vertex_alt; + +// this code is copied from default.vert + + //vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex; + gl_Position = ftransform(); + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + normal = gl_NormalMatrix * gl_Normal; + vec4 ambient_color, diffuse_color; + if (colorMode == MODE_DIFFUSE) { + diffuse_color = gl_Color; + ambient_color = gl_FrontMaterial.ambient; + } else if (colorMode == MODE_AMBIENT_AND_DIFFUSE) { + diffuse_color = gl_Color; + ambient_color = gl_Color; + } else { + diffuse_color = gl_FrontMaterial.diffuse; + ambient_color = gl_FrontMaterial.ambient; + } + + + + // here start computations for the haze layer + // we need several geometrical quantities + + // first current altitude of eye position in model space + vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0); + + // and relative position to vector + relPos = gl_Vertex.xyz - ep.xyz; + + // unfortunately, we need the distance in the vertex shader, although the more accurate version + // is later computed in the fragment shader again + float dist = length(relPos); + + // branch dependent on daytime + +if (terminator < 1000000.0) // the full, sunrise and sunset computation +{ + // altitude of the vertex in question, somehow zero leads to artefacts, so ensure it is at least 100m + vertex_alt = max(gl_Vertex.z,100.0); + + // establish coordinates relative to sun position + + vec3 lightFull = (gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz; + vec3 lightHorizon = normalize(vec3(lightFull.x,lightFull.y, 0.0)); + + + + // yprime is the distance of the vertex into sun direction + yprime = -dot(relPos, lightHorizon); + + // this gets an altitude correction, higher terrain gets to see the sun earlier + yprime_alt = yprime - sqrt(2.0 * EarthRadius * vertex_alt); + + // two times terminator width governs how quickly light fades into shadow + // now the light-dimming factor + earthShade = 0.6 * (1.0 - smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt)) + 0.4; + + // parametrized version of the Flightgear ground lighting function + lightArg = (terminator-yprime_alt)/100000.0; + + // directional scattering for low sun + if (lightArg < 5.0) + {mie_angle = (0.5 * dot(normalize(relPos), normalize(lightFull)) ) + 0.5;} + else + {mie_angle = 1.0;} + + + light_diffuse.b = light_func(lightArg, 1.330e-05, 0.264, 3.827, 1.08e-05, 1.0); + light_diffuse.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0); + light_diffuse.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0); + light_diffuse.a = 0.0; + light_diffuse = light_diffuse * scattering; + + light_ambient.b = light_func(lightArg, 0.000506, 0.131, -3.315, 0.000457, 0.5); + light_ambient.g = light_func(lightArg, 2.264e-05, 0.134, 0.967, 3.66e-05, 0.4); + light_ambient.r = light_func(lightArg, 0.236, 0.253, 1.073, 0.572, 0.33); + light_ambient.a = 0.0; + + + + +// correct ambient light intensity and hue before sunrise +if (earthShade < 0.5) + { + light_ambient = light_ambient * (0.4 + 0.6 * smoothstep(0.2, 0.5, earthShade)); + intensity = length(light_ambient.xyz); + + light_ambient.xyz = intensity * normalize(mix(light_ambient.xyz, vec3 (0.45, 0.6, 0.8), 1.0 -smoothstep(0.1, 0.5,earthShade) )); + + intensity = length(light_diffuse.xyz); + light_diffuse.xyz = intensity * normalize(mix(light_diffuse.xyz, vec3 (0.45, 0.6, 0.8), 1.0 -smoothstep(0.1, 0.5,earthShade) )); + } + + +// the haze gets the light at the altitude of the haze top if the vertex in view is below +// but the light at the vertex if the vertex is above + +vertex_alt = max(vertex_alt,hazeLayerAltitude); + +if (vertex_alt > hazeLayerAltitude) + { + if (dist > 0.8 * avisibility) + { + vertex_alt = mix(vertex_alt, hazeLayerAltitude, smoothstep(0.8*avisibility, avisibility, dist)); + yprime_alt = yprime -sqrt(2.0 * EarthRadius * vertex_alt); + } + } +else + { + vertex_alt = hazeLayerAltitude; + yprime_alt = yprime -sqrt(2.0 * EarthRadius * vertex_alt); + } + +} +else // the faster, full-day version without lightfields +{ + //vertex_alt = max(gl_Vertex.z,100.0); + + earthShade = 1.0; + mie_angle = 1.0; + + if (terminator > 3000000.0) + {light_diffuse = vec4 (1.0, 1.0, 1.0, 0.0); + light_ambient = vec4 (0.33, 0.4, 0.5, 0.0); } + else + { + + lightArg = (terminator/100000.0 - 10.0)/20.0; + light_diffuse.b = 0.78 + lightArg * 0.21; + light_diffuse.g = 0.907 + lightArg * 0.091; + light_diffuse.r = 0.904 + lightArg * 0.092; + light_diffuse.a = 0.0; + + light_ambient.b = 0.41 + lightArg * 0.08; + light_ambient.g = 0.333 + lightArg * 0.06; + light_ambient.r = 0.316 + lightArg * 0.016; + light_ambient.a = 0.0; + } + + light_diffuse = light_diffuse * scattering; + yprime_alt = -sqrt(2.0 * EarthRadius * hazeLayerAltitude); + + +} + + +// default lighting based on texture and material using the light we have just computed + + diffuse_term = diffuse_color* light_diffuse; + vec4 constant_term = gl_FrontMaterial.emission + ambient_color * + (gl_LightModel.ambient + light_ambient); + // Super hack: if diffuse material alpha is less than 1, assume a + // transparency animation is at work + if (gl_FrontMaterial.diffuse.a < 1.0) + diffuse_term.a = gl_FrontMaterial.diffuse.a; + else + diffuse_term.a = gl_Color.a; + // Another hack for supporting two-sided lighting without using + // gl_FrontFacing in the fragment shader. + gl_FrontColor.rgb = constant_term.rgb; gl_FrontColor.a = 1.0; + gl_BackColor.rgb = constant_term.rgb; gl_BackColor.a = 0.0; +} + diff --git a/gui/dialogs/local_weather_tiles.xml b/gui/dialogs/local_weather_tiles.xml index c21db9feb..9863855c4 100644 --- a/gui/dialogs/local_weather_tiles.xml +++ b/gui/dialogs/local_weather_tiles.xml @@ -399,7 +399,7 @@ 160 100 - + @@ -407,9 +407,9 @@ 100 90 20 - 30000.0 - 140000.0 - /local-weather/config/max-vis-range-m + 9.90348 + 12.429216196 + /local-weather/config/aux-max-vis-range-m dialog-apply @@ -418,7 +418,17 @@ 330 100 - + + + + + + 380 + 100 + + %.fm + true + /local-weather/config/max-vis-range-m