diff --git a/Effects/cloud.eff b/Effects/cloud.eff
index 8e2d830e7..094a53682 100644
--- a/Effects/cloud.eff
+++ b/Effects/cloud.eff
@@ -13,6 +13,10 @@
+
+
+
+
@@ -118,6 +122,26 @@
float
+
+ flash
+ float
+
+
+
+ lightning_pos_x
+ float
+
+
+
+ lightning_pos_y
+ float
+
+
+
+ lightning_range
+ float
+
+
diff --git a/Effects/rain-layer.eff b/Effects/rain-layer.eff
index e9835076a..aa834df4d 100644
--- a/Effects/rain-layer.eff
+++ b/Effects/rain-layer.eff
@@ -4,15 +4,13 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -60,8 +58,8 @@
clamp-->
- Shaders/rain-layer-lightfield.vert
- Shaders/rain-layer-lightfield.frag
+ Shaders/rain-layer-ALS.vert
+ Shaders/rain-layer-ALS.frag
baseTexture
@@ -78,12 +76,32 @@
float
-
- terminator
- float
-
+
+ terminator
+ float
+
- true
+
+ flash
+ float
+
+
+
+ lightning_pos_x
+ float
+
+
+
+ lightning_pos_y
+ float
+
+
+
+ lightning_range
+ float
+
+
+
@@ -149,10 +167,10 @@
float
-
- terminator
- float
-
+
+ terminator
+ float
+
true
diff --git a/Environment/environment.xml b/Environment/environment.xml
index 000791e02..58ebd3eae 100644
--- a/Environment/environment.xml
+++ b/Environment/environment.xml
@@ -440,6 +440,15 @@
1.0
+
+
+
+ 0.0
+ 0.0
+ 0.0
+ 0.0
+
+
0.015
diff --git a/Models/Weather/lightning.rgb b/Models/Weather/lightning.rgb
index b5236e53b..91376cf99 100644
Binary files a/Models/Weather/lightning.rgb and b/Models/Weather/lightning.rgb differ
diff --git a/Models/Weather/lightning1.xml b/Models/Weather/lightning1.xml
new file mode 100644
index 000000000..3df51f1f0
--- /dev/null
+++ b/Models/Weather/lightning1.xml
@@ -0,0 +1,54 @@
+
+
+
+ lightning.ac
+
+
+ rect
+ Effects/rain-layer
+
+
+
+ 0.0
+ 0.0
+ -1.2
+
+
+
+
+ scale
+ 700.0
+ 700.0
+ 1000.0
+
+
+
+ material
+
+ 0.9
+ 0.9
+ 1.0
+
+
+
+
+ select
+
+
+ /environment/lightning/flash
+ 0.0
+
+
+
+
+
+ billboard
+ false
+
+
+
+ false
+
+
+
+
diff --git a/Nasal/local_weather/compat_layer.nas b/Nasal/local_weather/compat_layer.nas
index 98c085849..e5ca6b228 100644
--- a/Nasal/local_weather/compat_layer.nas
+++ b/Nasal/local_weather/compat_layer.nas
@@ -618,6 +618,54 @@ model.getNode("load", 1).remove();
}
+###########################################################
+# place a model with control properties
+###########################################################
+
+var place_model_controlled = func(string, path, lat, lon, alt, heading, pitch, roll) {
+
+
+
+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);
+
+
+setprop("/local-weather/"~string~"/latitude-deg", lat);
+setprop("/local-weather/"~string~"/longitude-deg", lon);
+setprop("/local-weather/"~string~"/elevation-ft", alt);
+setprop("/local-weather/"~string~"/heading-deg", heading);
+setprop("/local-weather/"~string~"/pitch-deg", pitch);
+setprop("/local-weather/"~string~"/roll-deg", roll);
+
+
+
+var cmodel = props.globals.getNode("/local-weather/"~string, 1);
+var latN = cmodel.getNode("latitude-deg",1);
+var lonN = cmodel.getNode("longitude-deg",1);
+var altN = cmodel.getNode("elevation-ft",1);
+var headN = cmodel.getNode("heading-deg",1);
+var pitchN = cmodel.getNode("pitch-deg",1);
+var rollN = cmodel.getNode("roll-deg",1);
+
+
+
+model.getNode("path", 1).setValue(path);
+model.getNode("latitude-deg-prop", 1).setValue(latN.getPath());
+model.getNode("longitude-deg-prop", 1).setValue(lonN.getPath());
+model.getNode("elevation-ft-prop", 1).setValue(altN.getPath());
+model.getNode("heading-deg-prop", 1).setValue(headN.getPath());
+model.getNode("pitch-deg-prop", 1).setValue(pitchN.getPath());
+model.getNode("roll-deg-prop", 1).setValue(rollN.getPath());
+model.getNode("tile-index",1).setValue(0);
+model.getNode("load", 1).remove();
+
+
+#return model;
+}
+
diff --git a/Nasal/local_weather/local_weather.nas b/Nasal/local_weather/local_weather.nas
index 16fbe6993..d48c616cf 100644
--- a/Nasal/local_weather/local_weather.nas
+++ b/Nasal/local_weather/local_weather.nas
@@ -1667,6 +1667,7 @@ setprop(lw~"buffer-loop-flag",0);
setprop(lw~"housekeeping-loop-flag",0);
setprop(lw~"convective-loop-flag",0);
setprop(lw~"shadow-loop-flag",0);
+setprop(lw~"thunderstorm-loop-flag",0);
weather_dynamics.convective_loop_kill_flag = 1; # long-running loop needs a different scheme to end
@@ -1731,6 +1732,7 @@ settimer ( func {
setsize(alt_min_array,0);
setsize(alt_mean_array,0);
setsize(weather_dynamics.cloudShadowArray,0);
+ setsize(local_weather.thunderstormArray,0);
setsize(weather_dynamics.cloudShadowCandidateArray,0);
setsize(weather_dynamics.tile_convective_altitude,0);
setsize(weather_dynamics.tile_convective_strength,0);
@@ -4052,6 +4054,14 @@ if (local_weather.cloud_shadow_flag == 1)
# weather_tile_management.watchdog_loop();
+# start thunderstorm management
+
+setprop(lw~"thunderstorm-loop-flag",1);
+
+local_weather.place_model_controlled("lightning", "Models/Weather/lightning1.xml", lat, lon, 0.0, 0.0, 0.0, 0.0);
+
+local_weather.thunderstorm_management_loop();
+
}
diff --git a/Nasal/local_weather/weather_tile_management.nas b/Nasal/local_weather/weather_tile_management.nas
index 1d1c15dae..2d37d831f 100644
--- a/Nasal/local_weather/weather_tile_management.nas
+++ b/Nasal/local_weather/weather_tile_management.nas
@@ -17,6 +17,8 @@
# remove_impostors to delete a ring of impostors to mimick distant clouds
# create_impostors to create a ring of impostors to mimick distant clouds
# shadow_management_loop to manage cloud shadow information
+# thunderstorm_management_loop to manage information on thunderstorm position
+# lightning_strike to get the timing for a lightning strike to the property tree
# watchdog loop (debug helping structure)
# calc_geo to get local Cartesian geometry for latitude conversion
# get_lat to get latitude from Cartesian coordinates
@@ -1261,6 +1263,86 @@ if (local_weather.debug_output_flag == 1)
weather_tiles.create_impostor_ring(lat, lon, alt, alpha, type, n);
}
+##################################
+# Thunderstorm positon management
+##################################
+
+var thunderstorm_management_loop = func {
+
+if (local_weather.local_weather_running_flag == 0) {return;}
+
+# compute some general-purpose stuff for the loop
+
+var eyeLat = lwObserverLat;
+var eyeLon = lwObserverLon;
+
+var n = size(thunderstormArray);
+
+#print("We have ",n," storms.");
+
+for (var i = 0; i < n; i=i+1)
+ {
+ var tstorm = thunderstormArray[i];
+
+ var rn = rand();
+ #if (i == 0) {rn = 0;} else {rn = 1;}
+ if (rn < tstorm.strength)
+ {
+ #print("Lightning strike storm ", i,"!");
+
+ var diffx = -(tstorm.lat - eyeLat) * local_weather.lat_to_m;
+ var diffy = (tstorm.lon - eyeLon) * local_weather.lon_to_m ;
+ var offset_x = -3000.0 + rand() * 6000.0;
+ var offset_y = -3000.0 + rand() * 6000.0;
+
+ var dist = math.sqrt(diffx * diffx + diffy * diffy) ;
+
+ setprop("/environment/lightning/lightning-pos-x", diffx + offset_x);
+ setprop("/environment/lightning/lightning-pos-y", diffy + offset_y);
+ setprop("/environment/lightning/lightning-range", tstorm.size);
+ setprop("/local-weather/lightning/latitude-deg", tstorm.lat - offset_x * local_weather.m_to_lat);
+ setprop("/local-weather/lightning/longitude-deg", tstorm.lon + offset_y * local_weather.m_to_lon);
+ setprop("/local-weather/lightning/altitude-ft", tstorm.alt);
+ lightning_strike();
+
+ if (dist > 50000.0)
+ {
+ thunderstormArray = delete_from_vector(thunderstormArray,i);
+ print("Removing storm ", i);
+ break;
+ }
+ }
+
+
+ }
+
+
+if (getprop(lw~"thunderstorm-loop-flag") ==1) {settimer( func {thunderstorm_management_loop()}, 1.0);}
+}
+
+var lightning_strike = func {
+
+var rn = rand();
+
+var repeat = 1;
+
+if (rn > 0.5) {repeat = 2;}
+
+var duration = 0.1 + 0.1 * rand();
+var strength = 0.5 + 1.0 * rand();
+
+setprop("/environment/lightning/flash", strength);
+settimer( func{ setprop("/environment/lightning/flash", 0.0);}, duration);
+
+var duration1 = 0.1 + 0.1 * rand();
+
+if (repeat == 2)
+ {
+ settimer( func{ setprop("/environment/lightning/flash", strength);}, duration + 0.1);
+ settimer( func{ setprop("/environment/lightning/flash", 0.0);}, duration + 0.1 + duration1);
+ }
+
+}
###############################
# Cloud shadow management
@@ -1528,6 +1610,7 @@ var cloud_view_distance = getprop(lw~"config/clouds-visible-range-m");
var modelArrays = [];
var active_tile_list = [];
+var thunderstormArray = [];
# a bunch of variables to be updated per frame used by different
# routines, managed by the housekeeping loop
@@ -1543,6 +1626,8 @@ var lwTileIndex = 0;
# hashes to manage clouds in scenery or in the buffer
#####################################################
+
+
var cloudBufferArray = [];
@@ -1618,6 +1703,18 @@ var cloudShadow = {
},
};
+var thunderstormHash = {
+ new: func (lat, lon, alt, size, strength) {
+ var t = {parents: [thunderstormHash] };
+ t.lat = lat;
+ t.lon = lon;
+ t.alt = alt;
+ t.size = size;
+ t.strength = strength;
+ return t;
+ },
+};
+
var cloudSceneryArray = [];
var n_cloudSceneryArray = 0;
diff --git a/Nasal/local_weather/weather_tiles.nas b/Nasal/local_weather/weather_tiles.nas
index e0b9709d4..9ff43d635 100644
--- a/Nasal/local_weather/weather_tiles.nas
+++ b/Nasal/local_weather/weather_tiles.nas
@@ -1720,7 +1720,7 @@ local_weather.convective_size_bias = 0.3 + rand() * 0.3;
# and specify the atmosphere
- local_weather.set_atmosphere_ipoint(blat, blon, vis + 12000.0, alt+alt_offset, vis + 20000.0, 0.0, alt+alt_offset +20000.0, alt+alt_offset + 25000.0, 0.85, alt+alt_offset, alt+alt_offset + 2500.0);
+ local_weather.set_atmosphere_ipoint(blat, blon, vis + 12000.0, alt+alt_offset, vis + 20000.0, 0.0, alt+alt_offset +20000.0, alt+alt_offset + 25000.0, 0.75, alt+alt_offset, alt+alt_offset + 2500.0);
var rn = rand();
@@ -4295,18 +4295,34 @@ x = 2.0 * (rand()-0.5) * 12000;
y = 2.0 * (rand()-0.5) * 12000;
if (rand() > 0.6)
- {create_medium_thunderstorm(lat +get_lat(x,y,phi), lon + get_lon(x,y,phi), alt, alpha);}
+ {
+ create_medium_thunderstorm(lat +get_lat(x,y,phi), lon + get_lon(x,y,phi), alt, alpha);
+ var ts = local_weather.thunderstormHash.new (lat +get_lat(x,y,phi), lon + get_lon(x,y,phi), alt, 3000.0, 0.2);
+ append(local_weather.thunderstormArray,ts);
+ }
else
- {create_small_thunderstorm(lat +get_lat(x,y,phi), lon + get_lon(x,y,phi), alt, alpha);}
+ {
+ create_small_thunderstorm(lat +get_lat(x,y,phi), lon + get_lon(x,y,phi), alt, alpha);
+ var ts = local_weather.thunderstormHash.new (lat +get_lat(x,y,phi), lon + get_lon(x,y,phi), alt, 1000.0, 0.15);
+ append(local_weather.thunderstormArray,ts);
+ }
if (rand() > 0.5) # we do a second thunderstorm
{
x = 2.0 * (rand()-0.5) * 12000;
y = 2.0 * (rand()-0.5) * 12000;
if (rand() > 0.8)
- {create_medium_thunderstorm(lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt, alpha);}
+ {
+ create_medium_thunderstorm(lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt, alpha);
+ var ts = local_weather.thunderstormHash.new (lat +get_lat(x,y,phi), lon + get_lon(x,y,phi), alt, 3000.0, 0.2);
+ append(local_weather.thunderstormArray,ts);
+ }
else
- {create_small_thunderstorm(lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt, alpha);}
+ {
+ create_small_thunderstorm(lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt, alpha);
+ var ts = local_weather.thunderstormHash.new (lat +get_lat(x,y,phi), lon + get_lon(x,y,phi), alt, 1000.0, 0.15);
+ append(local_weather.thunderstormArray,ts);
+ }
}
# the convective layer
@@ -4315,6 +4331,10 @@ var strength = 0.10;
var n = int(4000 * strength) * 0.5;
local_weather.cumulus_exclusion_layer(lat, lon, alt, n, 20000.0, 20000.0, alpha, 0.3,2.5 , size(elat), elat, elon, erad);
+# some additional cloud cover
+
+create_4_8_sstratus_domains(lat, lon, alt,alpha);
+
# some turbulence in the convection layer
diff --git a/Shaders/3dcloud-ALS.vert b/Shaders/3dcloud-ALS.vert
index 43f522d6f..6c273e14d 100644
--- a/Shaders/3dcloud-ALS.vert
+++ b/Shaders/3dcloud-ALS.vert
@@ -13,6 +13,10 @@ uniform float cloud_self_shading;
uniform float visibility;
uniform float moonlight;
uniform float air_pollution;
+uniform float flash;
+uniform float lightning_pos_x;
+uniform float lightning_pos_y;
+uniform float lightning_range;
attribute vec3 usrAttr1;
attribute vec3 usrAttr2;
@@ -171,10 +175,21 @@ void main(void)
}
+
+
gl_FrontColor.rgb = intensity * shade * normalize(mix(light_diffuse.rgb, shadedFogColor, smoothstep(0.1,0.4, (1.0 - shade) ))) ;
+ // lightning
+ vec2 lightningRelVector = relVector.xy - vec2(lightning_pos_x, lightning_pos_y);
+ float rCoord = length(lightningRelVector);
+
+
+ float rn = 0.5 + 0.5 * fract(gl_Color.x);
+ gl_FrontColor.rgb += flash * vec3 (0.43, 0.57, 1.0) * (1.0 - smoothstep(lightning_range, 5.0 * lightning_range, rCoord)) * rn;
+ // fading of cloudlets
+
if ((fogCoord > (0.9 * detail_range)) && (fogCoord > center_dist) && (shade_factor < 0.7)) {
// cloudlet is almost at the detail range, so fade it out.
gl_FrontColor.a = 1.0 - smoothstep(0.9 * detail_range, detail_range, fogCoord);
diff --git a/Shaders/model-interior-ALS-detailed.vert b/Shaders/model-interior-ALS-detailed.vert
index b2325534d..df74a60c2 100644
--- a/Shaders/model-interior-ALS-detailed.vert
+++ b/Shaders/model-interior-ALS-detailed.vert
@@ -230,7 +230,7 @@ else // the faster, full-day version without lightfields
yprime_alt = -sqrt(2.0 * EarthRadius * hazeLayerAltitude);
}
-// irradiance mapping
+// irradiance mapping for ambient light
float ambient_irradiance_factor = 1.0;
float steepness = dot(normalize(gl_Normal), vec3 (0.0, 0.0, 1.0));
@@ -253,6 +253,8 @@ else // the faster, full-day version without lightfields
light_ambient = light_ambient * ambient_irradiance_factor;
+// residual ambience - comes with its own irradiance map
+
vec3 residual_ambience = vec3 (residual_ambience_r, residual_ambience_g, residual_ambience_b);
ambient_irradiance_factor = 1.0;
@@ -272,7 +274,10 @@ else // the faster, full-day version without lightfields
ambient_irradiance_factor = (1.0 - ra_irradiance_map_strength) + 1.5 * ra_irradiance_map_strength * (1.0 - abs(steepness)) * (0.5 + 0.5 * forwardness);
}
- light_ambient.rgb += residual_ambience.rgb * ambient_irradiance_factor;
+ // make sure the residual ambience is only visible when it's dark enough
+ float residual_fraction = length(residual_ambience.rgb) / (length(light_ambient.rgb + residual_ambience.rgb) + 0.01);
+
+ light_ambient.rgb += residual_ambience.rgb * ambient_irradiance_factor * smoothstep(0.4, 0.6, residual_fraction);
// default lighting based on texture and material using the light we have just computed
diff --git a/Shaders/rain-layer-lightfield.frag b/Shaders/rain-layer-ALS.frag
similarity index 100%
rename from Shaders/rain-layer-lightfield.frag
rename to Shaders/rain-layer-ALS.frag
diff --git a/Shaders/rain-layer-lightfield.vert b/Shaders/rain-layer-ALS.vert
similarity index 88%
rename from Shaders/rain-layer-lightfield.vert
rename to Shaders/rain-layer-ALS.vert
index b212a867a..b008d5553 100644
--- a/Shaders/rain-layer-lightfield.vert
+++ b/Shaders/rain-layer-ALS.vert
@@ -8,6 +8,10 @@ uniform float range; // From /sim/rendering/clouds3d-vis-range
uniform float scattering;
uniform float terminator;
uniform float altitude;
+uniform float flash;
+uniform float lightning_pos_x;
+uniform float lightning_pos_y;
+uniform float lightning_range;
float shade = 0.8;
@@ -88,6 +92,18 @@ void main(void)
gl_FrontColor = mix(backlight, gl_LightSource[0].diffuse, n);
gl_FrontColor += gl_FrontLightModelProduct.sceneColor;
+ // 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;
+ gl_FrontColor.rgb = gl_FrontColor.rgb * earthShade;
+
+ // lightning
+ vec2 lightningRelVector = relVector.xy - vec2(lightning_pos_x, lightning_pos_y);
+ float rCoord = length(lightningRelVector);
+
+ gl_FrontColor.rgb += 2.0 * flash * vec3 (0.43, 0.57, 1.0) * (1.0 - smoothstep(lightning_range, 5.0 * lightning_range, rCoord));
+ gl_FrontColor.rgb = clamp(gl_FrontColor.rgb,0.0,1.0);
+
// 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;
@@ -100,7 +116,7 @@ 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 = light_diffuse.rgb;
hazeColor.x = hazeColor.x * 0.83;
hazeColor.y = hazeColor.y * 0.9;
hazeColor = hazeColor * scattering;
@@ -109,14 +125,9 @@ float fadeScale = 0.05 + 0.2 * log(fogCoord/1000.0);
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;
+ hazeColor = clamp(hazeColor * earthShade, 0.0,1.0);
+
}