diff --git a/Effects/cloud-static.eff b/Effects/cloud-static.eff index 55543d9c4..737407c79 100644 --- a/Effects/cloud-static.eff +++ b/Effects/cloud-static.eff @@ -66,15 +66,15 @@ sampler-2d 0 - - terminator - float - terminator + + terminator + float + terminator - - altitude - float - altitude + + altitude + float + altitude true @@ -132,15 +132,15 @@ sampler-2d 0 - - terminator - float - terminator + + terminator + float + terminator - - altitude - float - altitude + + altitude + float + altitude true diff --git a/Effects/cloud.eff b/Effects/cloud.eff index fa43fbb0f..47a6efe08 100644 --- a/Effects/cloud.eff +++ b/Effects/cloud.eff @@ -86,15 +86,15 @@ float scattering - - terminator - float - terminator + + terminator + float + terminator - - altitude - float - altitude + + altitude + float + altitude true @@ -164,15 +164,15 @@ float scattering - - terminator - float - terminator + + terminator + float + terminator - - altitude - float - altitude + + altitude + float + altitude true diff --git a/Effects/rain-layer.eff b/Effects/rain-layer.eff index ee9c78c5d..e9835076a 100644 --- a/Effects/rain-layer.eff +++ b/Effects/rain-layer.eff @@ -78,10 +78,10 @@ float scattering - - terminator - float - terminator + + terminator + float + terminator true @@ -149,10 +149,10 @@ float scattering - - terminator - float - terminator + + terminator + float + terminator true diff --git a/Effects/skydome.eff b/Effects/skydome.eff index a7070ff55..1c916d08d 100644 --- a/Effects/skydome.eff +++ b/Effects/skydome.eff @@ -1,9 +1,9 @@ - - - Effects/skydome - - /sim/rendering/mie - /sim/rendering/rayleigh + + + Effects/skydome + + /sim/rendering/mie + /sim/rendering/rayleigh /sim/rendering/dome-density /rendering/scene/overcast /rendering/scene/saturation @@ -12,100 +12,101 @@ /environment/visibility-m /environment/ground-haze-thickness-m /environment/terminator-relative-position-m - /environment/mean-terrain-elevation-m - - - - - /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 + /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 - - rK - float - rayleigh + + overcast + float + overcast - - density - float - density + + saturation + float + saturation - - overcast - float - overcast + + scattering + float + scattering - - saturation - float - saturation + + visibility + float + visibility - - scattering - float - scattering + + hazeLayerAltitude + float + lthickness - - visibility - float - visibility + + terminator + float + terminator - - hazeLayerAltitude - float - lthickness + + avisibility + float + avisibility - - terminator - float - terminator - - - avisibility - float - avisibility - - - terrain_alt - float - terrain_alt - - - - - - - - false - smooth - back - - - - + + terrain_alt + float + terrain_alt + + + + + + + + false + smooth + back + + + + diff --git a/Effects/terrain-default.eff b/Effects/terrain-default.eff index 28a190d22..ea632780d 100644 --- a/Effects/terrain-default.eff +++ b/Effects/terrain-default.eff @@ -30,6 +30,13 @@ normalized + + Textures.high/Terrain/snow3.dds + linear-mipmap-linear + repeat + repeat + normalized + false 0 @@ -40,14 +47,420 @@ /environment/visibility-m /environment/ground-haze-thickness-m /rendering/scene/scattering + /environment/surface/scattering /environment/terminator-relative-position-m /environment/mean-terrain-elevation-m /rendering/scene/overcast /sim/rendering/eye-altitude-m + /environment/mysnow-level-m + /environment/surface/dust-cover-factor /sim/rendering/shaders/skydome + /environment/fog-structure + + + + + /sim/rendering/shaders/skydome + + 4.0 + /sim/rendering/shaders/landmass + + + + 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 + + + + 1 + noise + + + 6 + texture[6]/image + texture[6]/filter + texture[6]/wrap-s + texture[6]/wrap-t + + texture[6]/internal-format + + + + Shaders/terrain-haze-detailed.vert + Shaders/terrain-haze-detailed.frag + + + visibility + float + visibility + + + avisibility + float + avisibility + + + hazeLayerAltitude + float + lthickness + + + scattering + float + scattering + + + ground_scattering + float + ground_scattering + + + terminator + float + terminator + + + terrain_alt + float + terrain_alt + + + overcast + float + overcast + + + eye_alt + float + eye_alt + + + mysnowlevel + float + mysnow_level + + + dust_cover_factor + float + dust_cover_factor + + + fogstructure + float + fogstructure + + + texture + sampler-2d + 0 + + + NoiseTex + sampler-3d + 1 + + + snow_texture + sampler-2d + 6 + + + colorMode + int + 2 + + + lequal + false + + + + + + + + + /sim/rendering/shaders/skydome + + 4.0 + /sim/rendering/shaders/landmass + + + + 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 + + + + 1 + noise + + + 6 + texture[6]/image + texture[6]/filter + texture[6]/wrap-s + texture[6]/wrap-t + + texture[6]/internal-format + + + + Shaders/terrain-haze-detailed.vert + Shaders/terrain-haze-detailed.frag + + + visibility + float + visibility + + + avisibility + float + avisibility + + + hazeLayerAltitude + float + lthickness + + + scattering + float + scattering + + + ground_scattering + float + ground_scattering + + + terminator + float + terminator + + + terrain_alt + float + terrain_alt + + + overcast + float + overcast + + + eye_alt + float + eye_alt + + + mysnowlevel + float + mysnow_level + + + dust_cover_factor + float + dust_cover_factor + + + fogstructure + float + fogstructure + + + texture + sampler-2d + 0 + + + NoiseTex + sampler-3d + 1 + + + snow_texture + sampler-2d + 6 + + + colorMode + int + 2 + + + lequal + false + + + + + + @@ -158,6 +571,11 @@ float scattering + + ground_scattering + float + ground_scattering + terminator float diff --git a/Effects/water.eff b/Effects/water.eff index ec71fe839..49c0a6630 100644 --- a/Effects/water.eff +++ b/Effects/water.eff @@ -109,26 +109,443 @@ - - /environment/ground-visibility-m - - - /environment/visibility-m - - - /environment/ground-haze-thickness-m - - - /rendering/scene/scattering - - - /environment/terminator-relative-position-m - + /environment/ground-visibility-m + /environment/visibility-m + /environment/ground-haze-thickness-m + /rendering/scene/scattering + /environment/surface/scattering + /environment/terminator-relative-position-m + /environment/mean-terrain-elevation-m + /rendering/scene/overcast + /sim/rendering/eye-altitude-m /sim/rendering/shaders/skydome + + /environment/sea/color_r + /environment/sea/color_g + /environment/sea/color_b + + + + + + + /sim/rendering/shaders/skydome + + 4.0 + /sim/rendering/shaders/water + + + + 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 + + ambient-and-diffuse + + + transparent + + + transparent + + smooth + back + + + render-bin/bin-number + + + render-bin/bin-name + + + + + + 2 + + texture[2]/image + + + texture[2]/filter + + + texture[2]/wrap-s + + + texture[2]/wrap-t + + + texture[2]/internal-format + + + + 3 + + texture[3]/image + + + texture[3]/filter + + + texture[3]/wrap-s + + + texture[3]/wrap-t + + + texture[3]/internal-format + + + + + 5 + + texture[5]/image + + + texture[5]/filter + + + texture[5]/wrap-s + + + texture[5]/wrap-t + + + texture[5]/internal-format + + + + 6 + + texture[6]/image + + + texture[6]/filter + + + texture[6]/wrap-s + + + texture[6]/wrap-t + + + texture[6]/internal-format + + + + + + Shaders/water_lightfield.vert + + Shaders/water_lightfield.frag + + + + + water_normalmap + sampler-2d + 2 + + + water_dudvmap + sampler-2d + 3 + + + + sea_foam + sampler-2d + 5 + + + perlin_normalmap + sampler-2d + 6 + + + saturation + float + + saturation + + + + + WindE + float + + windE + + + + WindN + float + + windN + + + + + WaveFreq + float + + WaveFreq + + + + WaveAmp + float + + WaveAmp + + + + WaveSharp + float + + WaveSharp + + + + WaveAngle + float + + WaveAngle + + + + WaveFactor + float + + WaveFactor + + + + WaveDAngle + float + + WaveDAngle + + + + + + + + visibility + float + + visibility + + + + avisibility + float + + avisibility + + + + hazeLayerAltitude + float + + lthickness + + + + scattering + float + + scattering + + + + ground_scattering + float + ground_scattering + + + terminator + float + + terminator + + + + terrain_alt + float + terrain_alt + + + overcast + float + overcast + + + eye_alt + float + eye_alt + + + + sea_r + float + sea_r + + + sea_g + float + sea_g + + + sea_b + float + sea_b + + + + + + + + + + + @@ -742,7 +1159,6 @@ status - Overcast diff --git a/Environment/environment.xml b/Environment/environment.xml index 1ae19dc53..b2b65d2bb 100644 --- a/Environment/environment.xml +++ b/Environment/environment.xml @@ -333,12 +333,22 @@ 0.05 + 0.148 + 0.27 + 0.3 16000.0 + 0.0 2000.0 1000000.0 0.0 - + 3200.0 + 0.0 + + + 0.7 + 0.0 + diff --git a/Nasal/local_weather/cloud_definitions.nas b/Nasal/local_weather/cloud_definitions.nas index 2f6ffd5d4..51843548c 100644 --- a/Nasal/local_weather/cloud_definitions.nas +++ b/Nasal/local_weather/cloud_definitions.nas @@ -410,7 +410,7 @@ else if (type == "Cumulus bottom"){ cloudAssembly.num_tex_y = 1; #characterize the cloud - cloudAssembly.bottom_shade = 1.0; + cloudAssembly.bottom_shade = 0.5; cloudAssembly.n_sprites = 4; cloudAssembly.min_width = 600.0 * mult; cloudAssembly.max_width = 800.0 * mult; @@ -452,7 +452,7 @@ else if (type == "Congestus bottom"){ cloudAssembly.num_tex_y = 1; #characterize the cloud - cloudAssembly.bottom_shade = 0.7; + cloudAssembly.bottom_shade = 0.5; cloudAssembly.n_sprites = 4; cloudAssembly.min_width = 1100.0 * mult; cloudAssembly.max_width = 1400.0 * mult; diff --git a/Nasal/local_weather/cloud_placement_lowlevel.nas b/Nasal/local_weather/cloud_placement_lowlevel.nas new file mode 100644 index 000000000..5232fe39e --- /dev/null +++ b/Nasal/local_weather/cloud_placement_lowlevel.nas @@ -0,0 +1,243 @@ +######################################################## +# routines to set up, transform and manage advanced weather +# Thorsten Renk, April 2012 +######################################################## + +# function purpose +# +# create_undulatus to create an undulating cloud pattern +# create_cumulus_alleys to create an alley pattern of Cumulus clouds +# create_layer to create a cloud layer with optional precipitation + +########################################################### +# place an undulatus pattern +########################################################### + +var create_undulatus = func (type, blat, blong, balt, alt_var, nx, xoffset, edgex, x_var, ny, yoffset, edgey, y_var, und_strength, direction, tri) { + +var flag = 0; +var path = "Models/Weather/blank.ac"; +local_weather.calc_geo(blat); +var dir = direction * math.pi/180.0; + +var ymin = -0.5 * ny * yoffset; +var xmin = -0.5 * nx * xoffset; +var xinc = xoffset * (tri-1.0) /ny; + +var jlow = int(nx*edgex); +var ilow = int(ny*edgey); + +var und = 0.0; +var und_array = []; + +for (var i=0; i(nx-jlow-1))) and ((i(ny-ilow-1)))) # select a small or no cloud + { + if (rn > 2.0) {flag = 1;} else {path = select_cloud_model(type,"small");} + } + if ((j(nx-jlow-1)) or (i(ny-ilow-1))) + { + if (rn > 5.0) {flag = 1;} else {path = select_cloud_model(type,"small");} + } + else { # select a large cloud + if (rn > 5.0) {flag = 1;} else {path = select_cloud_model(type,"large");} + } + + + if (flag==0){ + if (thread_flag == 1) + {create_cloud_vec(path, lat, long, alt, 0.0);} + else + {local_weather.create_cloud(path, lat, long, alt, 0.0);} + + + } + } + + } + +} + + + +########################################################### +# place a Cumulus alley pattern +########################################################### + +var create_cumulus_alleys = func (blat, blon, balt, alt_var, nx, xoffset, edgex, x_var, ny, yoffset, edgey, y_var, und_strength, direction, tri) { + +var flag = 0; +var path = "Models/Weather/blank.ac"; +local_weather.calc_geo(blat); +var dir = direction * math.pi/180.0; + +var ymin = -0.5 * ny * yoffset; +var xmin = -0.5 * nx * xoffset; +var xinc = xoffset * (tri-1.0) /ny; + +var jlow = int(nx*edgex); +var ilow = int(ny*edgey); + +var und = 0.0; +var und_array = []; + +var spacing = 0.0; +var spacing_array = []; + + +for (var i=0; i(nx-jlow-1))) and ((i(ny-ilow-1)))) # select a small or no cloud + { + if (rn > 2.0) {flag = 1;} else {strength = 0.3 + rand() * 0.5;} + } + if ((j(nx-jlow-1)) or (i(ny-ilow-1))) + { + if (rn > 5.0) {flag = 1;} else {strength = 0.7 + rand() * 0.5;} + } + else { # select a large cloud + if (rn > 5.0) {flag = 1;} else {strength = 1.1 + rand() * 0.6;} + } + + + if (flag==0){create_detailed_cumulus_cloud(lat, lon, alt, strength); } + } + + } + +} + + +########################################################### +# place a cloud layer +########################################################### + +var create_layer = func (type, blat, blon, balt, bthick, rx, ry, phi, density, edge, rainflag, rain_density) { + + +var i = 0; +var area = math.pi * rx * ry; +var circ = math.pi * (rx + ry); # that's just an approximation +var n = int(area/80000000.0 * 100 * density); +var m = int(circ/63000.0 * 40 * rain_density); +var path = "Models/Weather/blank.ac"; + +#print("density: ",n); + +phi = phi * math.pi/180.0; + +if (contains(local_weather.cloud_vertical_size_map, type)) + {var alt_offset = cloud_vertical_size_map[type]/2.0 * m_to_ft;} + else {var alt_offset = 0.0;} + +while(i ((1.0 - edge) * (1.0- edge))) + { + if (rand() > 0.4) { + path = select_cloud_model(type,"small"); + if (thread_flag == 1) + {create_cloud_vec(path, lat, lon, alt, 0.0);} + else + {compat_layer.create_cloud(path, lat, lon, alt, 0.0);} + } + } + else { + path = select_cloud_model(type,"large"); + if (thread_flag == 1) + {create_cloud_vec(path, lat, lon, alt, 0.0);} + else + {compat_layer.create_cloud(path, lat, lon, alt, 0.0);} + } + i = i + 1; + } + } + +i = 0; + +if (rainflag ==1){ + +if (local_weather.hardcoded_clouds_flag == 1) {balt = balt + local_weather.offset_map[type]; } + + while(i c.top_shade) {c.bottom_shade = c.top_shade;} +c.middle_shade = c.top_shade; + # write the actual cloud into the scenery @@ -812,8 +822,8 @@ var p = props.Node.new({ "layer" : 0, "max-sprite-height-m": c.max_height, "num-sprites": c.n_sprites, "min-bottom-lighting-factor": c.bottom_shade, - "min-middle-lighting-factor": 0.9, - "min-top-lighting-factor": 1.0, + "min-middle-lighting-factor": c.middle_shade, + "min-top-lighting-factor": c.top_shade, "min-shade-lighting-factor": c.bottom_shade, "texture": c.texture_sheet, "num-textures-x": c.num_tex_x, diff --git a/Nasal/local_weather/local_weather.nas b/Nasal/local_weather/local_weather.nas index 95a61e4c0..534da9704 100644 --- a/Nasal/local_weather/local_weather.nas +++ b/Nasal/local_weather/local_weather.nas @@ -34,15 +34,13 @@ # create_detailed_cumulus_cloud to place multiple cloudlets into a box based on a size parameter # create_cumulonimbus_cloud to place multiple cloudlets into a box # create_cumulonimbus_cloud_rain to place multiple cloudlets into a box and add a rain layer beneath -# create_cumosys wrapper to place a convective cloud system based on terrain coverage +# create_cumosys (wrapper to place a convective cloud system based on terrain coverage) # cumulus_loop to place 25 Cumulus clouds each frame # create_cumulus to place a convective cloud system based on terrain coverage # recreate_cumulus to respawn convective clouds as part of the convective dynamics algorithm # cumulus_exclusion_layer to create a layer with 'holes' left for thunderstorm placement # create_rise_clouds to create a barrier cloud system # create_streak to create a cloud streak -# create_undulatus to create an undulating cloud pattern -# create_layer to create a cloud layer with optional precipitation # create_hollow_layer to create a cloud layer in a hollow cylinder (better for performance) # create_cloudbox to create a sophisticated cumulus cloud with different textures (experimental) # terrain_presampling_start to initialize terrain presampling @@ -640,29 +638,65 @@ if (vis > max_vis_range) if (scattering_shader_flag == 1) { - var rayleigh = 0.0003 ; - var mie = 0.003; + #var rayleigh = 0.0003 ; + #var mie = 0.003; + #var density = 0.3; + + # values to be used with new exposure filter + var rayleigh = 0.0003; + var mie = 0.005; var density = 0.3; + var vis_factor = (vis - 30000.0)/90000.0; + if (vis_factor < 0.0) {vis_factor = 0.0;} + if (vis_factor > 1.0) {vis_factor = 1.0;} + + #if (altitude < 30000.0) + # { + # rayleigh = 0.0004 - altitude/30000.0 * 0.0001; + # mie = 0.004 - altitude/30000.0 * 0.001; + # mie = 0.002 - altitude/30000.0 * 0.001; + # } + #else if (altitude < 60000.0) + # { + # rayleigh = 0.0003 - (altitude-30000.0)/30000.0 * 0.0001; + # mie = 0.003 - (altitude-30000.0)/30000.0 * 0.001; + # } + #else if (altitude < 85000.0) + # { + # rayleigh = 0.0002 - (altitude-60000.0)/25000.0 * 0.0001; + # mie = 0.002; + # } + #else + # {rayleigh = 0.0001; mie = 0.002;} - - if (altitude < 30000.0) + if (altitude < 36000.0) { - rayleigh = 0.0004 - altitude/30000.0 * 0.0001; - mie = 0.004 - altitude/30000.0 * 0.001; - } - else if (altitude < 60000.0) - { - rayleigh = 0.0003 - (altitude-30000.0)/30000.0 * 0.0001; - mie = 0.003 - (altitude-30000.0)/30000.0 * 0.001; + rayleigh = 0.0003 - 0.0001 * vis_factor; + mie = 0.005 - vis_factor * 0.002; } else if (altitude < 85000.0) { - rayleigh = 0.0002 - (altitude-60000.0)/25000.0 * 0.0001; - mie = 0.002; + rayleigh = (0.0003 - 0.0001 * vis_factor) - (altitude-36000.0)/49000.0 * 0.0001; + mie = 0.005 - vis_factor * 0.002 - (altitude-36000.0)/49000.0 * 0.002; } else - {rayleigh = 0.0001; mie = 0.002;} + {rayleigh = 0.0002 - 0.0001 * vis_factor; mie = 0.003 - vis_factor * 0.002;} + + # now the pollution factor + + if (altitude < alt1) + { + rayleigh = rayleigh +0.0003 * air_pollution_norm + 0.0004 * air_pollution_norm * (1.0 - (altitude/alt1) * (altitude/alt1)); + density = density + 0.05 * air_pollution_norm + 0.05 * air_pollution_norm * (1.0 - (altitude/alt1) * (altitude/alt1)); + } + else + { + rayleigh = rayleigh + 0.0003 * air_pollution_norm; + density = density + 0.05 * air_pollution_norm; + } + + } # otherwise compute normal skydome shader parameters @@ -725,6 +759,8 @@ if (scattering_shader_flag == 1) local_weather.setScattering(scatt); local_weather.setOvercast(ovcst); + + # now check if an effect volume writes the property and set only if not @@ -928,10 +964,15 @@ 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 +# set scattering on the ground - this doesn't affect fog but is diffuse and specular light reduction +# so it is stronger than normal scattering + +var scatt_ground = 2.0 * (scatt_max - 0.5); +if (scatt_ground < 0.0) {scatt_ground = 0.0;} + +setprop("/environment/surface/scattering", scatt_ground); if (getprop(lw~"interpolation-loop-flag") ==1) {settimer(interpolation_loop, interpolation_loop_time);} @@ -1506,6 +1547,7 @@ if (path == "new") # we have to switch to new cloud generating routines local_weather.cloudAssembly.lat = lat; local_weather.cloudAssembly.lon = long; local_weather.cloudAssembly.alt = alt; + local_weather.cloudAssembly.top_shade = top_shade; #print(lat," ",long, " ", alt); @@ -2564,158 +2606,10 @@ for (var i=0; i(nx-jlow-1))) and ((i(ny-ilow-1)))) # select a small or no cloud - { - if (rn > 2.0) {flag = 1;} else {path = select_cloud_model(type,"small");} - } - if ((j(nx-jlow-1)) or (i(ny-ilow-1))) - { - if (rn > 5.0) {flag = 1;} else {path = select_cloud_model(type,"small");} - } - else { # select a large cloud - if (rn > 5.0) {flag = 1;} else {path = select_cloud_model(type,"large");} - } - if (flag==0){ - if (thread_flag == 1) - {create_cloud_vec(path, lat, long, alt, 0.0);} - else - {compat_layer.create_cloud(path, lat, long, alt, 0.0);} - - - } - } - - } - -} -########################################################### -# place a cloud layer -########################################################### - -var create_layer = func (type, blat, blon, balt, bthick, rx, ry, phi, density, edge, rainflag, rain_density) { - - -var i = 0; -var area = math.pi * rx * ry; -var circ = math.pi * (rx + ry); # that's just an approximation -var n = int(area/80000000.0 * 100 * density); -var m = int(circ/63000.0 * 40 * rain_density); -var path = "Models/Weather/blank.ac"; - -#print("density: ",n); - -phi = phi * math.pi/180.0; - -if (contains(cloud_vertical_size_map, type)) - {var alt_offset = cloud_vertical_size_map[type]/2.0 * m_to_ft;} - else {var alt_offset = 0.0;} - -while(i ((1.0 - edge) * (1.0- edge))) - { - if (rand() > 0.4) { - path = select_cloud_model(type,"small"); - if (thread_flag == 1) - {create_cloud_vec(path, lat, lon, alt, 0.0);} - else - {compat_layer.create_cloud(path, lat, lon, alt, 0.0);} - } - } - else { - path = select_cloud_model(type,"large"); - if (thread_flag == 1) - {create_cloud_vec(path, lat, lon, alt, 0.0);} - else - {compat_layer.create_cloud(path, lat, lon, alt, 0.0);} - } - i = i + 1; - } - } - -i = 0; - -if (rainflag ==1){ - -if (local_weather.hardcoded_clouds_flag == 1) {balt = balt + local_weather.offset_map[type]; } - - while(i (ivector_size-1)) {index = 0;} + +# pick one point for distance re-computation per loop iteration + +var viewpos = geo.aircraft_position(); +var ppos = geo.Coord.new(); +var s = interpolation_vector[index]; +ppos.set_latlon(s.lat,s.lon,0.0); +s.distance = viewpos.distance_to(ppos); + + +# interpolate the rgb values + + +var sum_r = 0.148/1000000.0; +var sum_g = 0.27/1000000.0; +var sum_b = 0.3/1000000.0; +var sum_norm = 1.0/1000000.0; # default point is 1000 km away + +for (var i = 0; i < ivector_size; i = i + 1) + { + s = interpolation_vector[i]; + sum_norm = sum_norm + 1./s.distance * s.weight; + sum_r = sum_r + s.r/s.distance * s.weight; + sum_g = sum_g + s.g/s.distance * s.weight; + sum_b = sum_b + s.b/s.distance * s.weight; + + #print("index: ", i, " dist: ", s.distance, " r: ", s.r); + } + +var r = sum_r / sum_norm; +var g = sum_g / sum_norm; +var b = sum_b / sum_norm; + +setprop("/environment/sea/color_r", r); +setprop("/environment/sea/color_g", g); +setprop("/environment/sea/color_b", b); + + +settimer( func {sea_color_loop(index+1) },1.0); +} + +var ivector_size = 0; +var interpolation_vector = []; diff --git a/Nasal/local_weather/weather_tiles.nas b/Nasal/local_weather/weather_tiles.nas index e3d28581a..62d501ac5 100644 --- a/Nasal/local_weather/weather_tiles.nas +++ b/Nasal/local_weather/weather_tiles.nas @@ -54,6 +54,10 @@ var dir_index = getprop(lw~"tiles/tmp/dir-index"); local_weather.assemble_effect_array(); +# reset lighting + +local_weather.top_shade = 1.0; + if (local_weather.debug_output_flag == 1) {print("Finished setting up tile type ",current_code, " in direction ",dir_index);} @@ -104,16 +108,16 @@ alt_offset = 0.0; #local_weather.create_cumosys(blat,blon, 3000.0, get_n(strength), 20000.0); #create_2_8_altocumulus_streaks(blat, blon, 12000+alt_offset, alpha) ; -#create_2_8_altocumulus_streaks(blat, blon, 12000+alt_offset, alpha) ; +# create_2_8_altocumulus_streaks(blat, blon, 12000+alt_offset, alpha) ; #create_6_8_stratus(blat, blon, 3000+alt_offset, alpha) ; #create_4_8_tstratus_patches(blat, blon, 5000+alt_offset, alpha) ; #create_4_8_sstratus_patches(blat, blon, 5000+alt_offset, alpha) ; #create_4_8_cirrostratus_patches(blat, blon, 5000+alt_offset, alpha) ; #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_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.0, alpha, 0.3) ; #create_8_8_tstratus(blat, blon, 5000+alt_offset, alpha); @@ -125,11 +129,16 @@ alt_offset = 0.0; #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_cirrus(blat, blon, 30000.0, alpha); -#create_4_8_altocumulus_perlucidus(blat, blon, 5000+alt_offset, alpha) ; +#create_2_8_altocumulus_perlucidus(blat, blon, 12000+alt_offset, alpha) ; -#create_detailed_stratocumulus_bank(blat, blon, 4000+alt_offset,alpha); +# create_detailed_stratocumulus_bank(blat, blon, 4000,alpha); + +local_weather.top_shade = 0.6; + +create_4_8_cumulus_alleys(blat, blon, 3000.0, alpha); +# create_4_8_cirrostratus_undulatus(blat, blon, 25000.0, alpha); #store convective altitude and strength @@ -191,6 +200,9 @@ var alt = spread * 400; var strength = 0.0; +# bias Cumulus clouds towards smaller sizes due to lack of water vapour and convection +local_weather.convective_size_bias = -0.2 - rand() * 0.1; + var rn = rand(); if (rand() < small_scale_persistence) @@ -198,9 +210,9 @@ if (rand() < small_scale_persistence) else {rnd_store = rn;} -#rn = 0.1; +# rn = 0.1; -if (rn > 0.833) +if (rn > 0.875) { # cloud scenario 1: weak cumulus development and blue thermals @@ -220,7 +232,7 @@ if (rn > 0.833) # 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.666) +else if (rn > 0.75) { # cloud scenario 2: some Cirrocumulus patches @@ -234,7 +246,7 @@ else if (rn > 0.666) # 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.5) +else if (rn > 0.625) { # cloud scenario 3: Cirrostratus undulatus over weak cumulus @@ -247,7 +259,7 @@ else if (rn > 0.5) 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.333) +else if (rn > 0.5) { # cloud scenario 4: Cirrostratus undulatus streak @@ -259,7 +271,7 @@ else if (rn > 0.333) # 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.166) +else if (rn > 0.375) { # cloud scenario 5: Cirrus @@ -274,13 +286,33 @@ else if (rn > 0.166) # 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) +else if (rn > 0.25) { # 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); } +else if (rn > 0.125) + { + # cloud scenario 7: clear + + 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, 1.0, alt+alt_offset, alt+alt_offset + 2500.0); + } +else if (rn > 0.0) + { + # cloud scenario 8: Cirrocumulus + + if (rand() > 0.7) # this is very expensive, so don't do it for every tile + {create_2_8_cirrocumulus_patches(blat, blon, alt + alt_offset + 26000.0, alpha);} + else + {create_2_8_cirrocumulus(blat, blon, alt + alt_offset + 26000.0, alpha);} + + # and specify the atmosphere + local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.2, alt+alt_offset +24000.0, alt+alt_offset + 26000.0, 0.9, alt+alt_offset, alt+alt_offset + 2500.0); + + } + # store convective altitude and strength @@ -347,7 +379,7 @@ else # rn = 0.1; -if (rn > 0.8) +if (rn > 0.875) { # cloud scenario 1: possible Cirrus over Cumulus strength = 0.2 + rand() * 0.4; @@ -372,7 +404,7 @@ if (rn > 0.8) 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 + 30000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.6) +else if (rn > 0.75) { # cloud scenario 2: Cirrostratus over weak Cumulus @@ -385,7 +417,7 @@ else if (rn > 0.6) local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.2, alt+alt_offset +20000.0, alt+alt_offset + 25000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.4) +else if (rn > 0.625) { # cloud scenario 3: Cirrocumulus sheet over Cumulus @@ -404,7 +436,7 @@ else if (rn > 0.4) 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 + 24000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.2) +else if (rn > 0.5) { # cloud scenario 4: Cirrostratus undulatus over weak Cumulus @@ -416,7 +448,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 +20000.0, alt+alt_offset + 25000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.0) +else if (rn > 0.375) { # cloud scenario 5: some scattered Altocumuli over Cumulus @@ -430,6 +462,43 @@ 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 +20000.0, alt+alt_offset + 25000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); } +else if (rn > 0.25) + { + # cloud scenario 6: Cirrocumulus over Cumulus + strength = 0.2 + rand() * 0.1; + local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0); + + if (rand() > 0.8) # this is very expensive, so don't do it for every tile + {create_2_8_cirrocumulus_patches(blat, blon, alt + alt_offset + 26000.0, alpha);} + else + {create_2_8_cirrocumulus(blat, blon, alt + alt_offset + 26000.0, alpha);} + + # and specify the atmosphere + local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.3, alt+alt_offset +24000.0, alt+alt_offset + 26000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); + } +else if (rn > 0.125) + { + # cloud scenario 7: just Cumulus + + strength = 0.3 + rand() * 0.1; + local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.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 +20000.0, alt+alt_offset + 25000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); + } +else if (rn > 0.0) + { + # cloud scenario 8: Altocumulus Perlucidus over Cumulus + + strength = 0.2 + rand() * 0.1; + local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0); + + create_2_8_altocumulus_perlucidus(blat, blon, alt + alt_offset + 12000.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); + } + # store convective altitude and strength @@ -488,13 +557,17 @@ var strength = 0.0; var rn = rand(); + + if (rand() < small_scale_persistence) {rn = rnd_store;} else {rnd_store = rn;} -if (rn > 0.888) +# rn = 0.05; + +if (rn > 0.9) { # cloud scenario 1: Altocumulus patch over weak Cumulus strength = 0.1 + rand() * 0.1; @@ -509,7 +582,7 @@ if (rn > 0.888) 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); } -else if (rn > 0.777) +else if (rn > 0.8) { # cloud scenario 2: Altocumulus streaks strength = 0.15 + rand() * 0.2; @@ -526,7 +599,7 @@ else if (rn > 0.777) 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); } -else if (rn > 0.666) +else if (rn > 0.7) { # cloud scenario 3: Cirrus @@ -539,7 +612,7 @@ else if (rn > 0.666) 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 + 22000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.555) +else if (rn > 0.6) { # cloud scenario 4: thin Stratus streaks @@ -552,7 +625,7 @@ else if (rn > 0.555) 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); } -else if (rn > 0.444) +else if (rn > 0.5) { # cloud scenario 5: scattered Stratus @@ -567,7 +640,7 @@ else if (rn > 0.444) local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.2, alt+alt_offset +20000.0, alt+alt_offset + 25000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.333) +else if (rn > 0.4) { # cloud scenario 6: Cirrocumulus sheets @@ -590,7 +663,7 @@ else if (rn > 0.333) # 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.85, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.222) +else if (rn > 0.3) { # cloud scenario 7: Thin Cirrocumulus sheets over weak Cumulus @@ -603,7 +676,7 @@ else if (rn > 0.222) local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.05, alt+alt_offset +20000.0, alt+alt_offset + 25000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.111) +else if (rn > 0.2) { # cloud scenario 8: Altocumulus perlucidus @@ -615,7 +688,7 @@ else if (rn > 0.111) local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.25, alt+alt_offset +26000.0, alt+alt_offset + 30000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.0) +else if (rn > 0.1) { # cloud scenario 9: Cumulus, Altocumulus and Cirrus @@ -630,7 +703,16 @@ 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 +26000.0, alt+alt_offset + 30000.0, 0.8, alt+alt_offset, alt+alt_offset + 2500.0); } +else if (rn > 0.0) + { + # cloud scenario 10: Cumulus alleys and Cirrus + create_4_8_cumulus_alleys(blat, blon, alt+ alt_offset, alpha); + create_4_8_cirrus(blat, blon, alt + alt_offset + 35000.0, alpha); + + # 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.8, alt+alt_offset, alt+alt_offset + 2500.0); + } # store convective altitude and strength @@ -700,8 +782,10 @@ if (rand() < small_scale_persistence) else {rnd_store = rn;} +# rn = 0.05; -if (rn > 0.857) + +if (rn > 0.875) { # cloud scenario 1: low Stratocumulus, thin streaks above @@ -716,7 +800,7 @@ if (rn > 0.857) 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.75, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.714) +else if (rn > 0.75) { # cloud scenario 2: weak Cumulus, Stratus undulatus above @@ -730,7 +814,7 @@ else if (rn > 0.714) # 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); } -else if (rn > 0.571) +else if (rn > 0.625) { # cloud scenario 3: Stratocumulus banks with patches above @@ -742,7 +826,7 @@ else if (rn > 0.571) # 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.7, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.428) +else if (rn > 0.5) { # cloud scenario 4: structured Stratus @@ -753,7 +837,7 @@ else if (rn > 0.428) # and specify the atmosphere local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.25, alt+alt_offset +20000.0, alt+alt_offset + 25000.0, 0.7, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.285) +else if (rn > 0.375) { # cloud scenario 5: Stratus blending with Cumulus with Cirrocumulus above @@ -767,7 +851,7 @@ else if (rn > 0.285) # 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 +20000.0, alt+alt_offset + 25000.0, 0.75, alt+alt_offset, alt+alt_offset + 2500.0); } -else if (rn > 0.142) +else if (rn > 0.250) { # cloud scenario 6: small Stratocumulus banks @@ -781,7 +865,7 @@ else if (rn > 0.142) # and specify the atmosphere local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.3, alt+alt_offset +20000.0, alt+alt_offset + 25000.0, 0.75, alt+alt_offset, alt+alt_offset + 2500.0); } -else +else if (rn > 0.125) { # cloud scenario 7: blended structured and unstructured Stratiform clouds @@ -793,6 +877,19 @@ else # and specify the atmosphere local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.2, alt+alt_offset +20000.0, alt+alt_offset + 25000.0, 0.75, alt+alt_offset, alt+alt_offset + 2500.0); } +else if (rn > 0.0) + { + # cloud scenario 8: Cumulus alleys beneath a high dense stratus cover + + local_weather.top_shade = 0.7; + create_4_8_cumulus_alleys(blat, blon, alt+ alt_offset, alpha); + + local_weather.top_shade = 1.0; + create_6_8_tstratus_undulatus(blat, blon, alt+alt_offset + 6000.0,alpha); + + # and specify the atmosphere + local_weather.set_atmosphere_ipoint(blat, blon, vis + 10000.0, alt+alt_offset, vis + 15000.0, 0.5, alt+alt_offset +5500.0, alt+alt_offset + 6500.0, 0.65, alt+alt_offset + 6000.0, alt+alt_offset + 7500.0); + } @@ -1081,6 +1178,9 @@ local_weather.set_weather_station(blat, blon, alt_offset, vis, T, D, p * hp_to_i var alt = spread * 400.0; var strength = 0.0; +# bias Cumulus clouds towards larger sizes due to strong convection +local_weather.convective_size_bias = 0.3 + rand() * 0.1; + var rn = rand(); if (rand() < small_scale_persistence) @@ -1093,7 +1193,7 @@ else if (rn > 0.5) { # cloud scenario 1: strong Cumulus development - strength = 0.8 + rand() * 0.2; + strength = 0.6 + rand() * 0.1; local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0); # and specify the atmosphere @@ -1104,7 +1204,7 @@ else if (rn > 0.0) { # cloud scenario 2: Cirrocumulus sheets over Cumulus - strength = 0.6 + rand() * 0.2; + strength = 0.5 + rand() * 0.1; local_weather.create_cumosys(blat,blon, alt + alt_offset, get_n(strength), 20000.0); for (var i = 0; i < 2; i = i + 1) @@ -2293,19 +2393,23 @@ for (var i = n; i 0.66) + if (rn > 0.75) {create_2_8_tstratus(blat, blon, altitude+metar_alt_offset, alpha);} - else if (rn > 0.33) + else if (rn > 0.5) {create_2_8_sstratus(blat, blon, altitude+metar_alt_offset, alpha);} - else + else if (rn > 0.25) + {create_2_8_altocumulus_perlucidus(blat, blon, altitude+metar_alt_offset, alpha);} + else if (rn > 0.0) {create_2_8_alttstratus(blat, blon, altitude+metar_alt_offset, alpha);} } else { var rn = rand(); - if (rn > 0.5) + if (rn > 0.9) + {create_2_8_cirrocumulus_patches(blat, blon, altitude+metar_alt_offset, alpha);} + if (rn > 0.4) {create_2_8_cirrocumulus(blat, blon, altitude+metar_alt_offset, alpha);} - else + else if (rn > 0.0) {create_2_8_alttstratus(blat, blon, altitude+metar_alt_offset, alpha);} } @@ -2627,7 +2731,7 @@ if (rain > 0.1) } else { - local_weather.create_effect_volume(3, lat, lon, 20000.0, 20000.0, alpha, alt-1500.0, alt+900.0, 2000.0, -1 , -1, -1, -1,0 ,-1); + local_weather.create_effect_volume(3, lat, lon, 20000.0, 20000.0, alpha, alt, alt+900.0, 2000.0, -1 , -1, -1, -1,0 ,-1); local_weather.create_effect_volume(3, lat, lon, 20000.0, 20000.0, alpha, 0.0, alt, -1, rain , -1, -1, -1,0 ,0.9); } @@ -3065,6 +3169,23 @@ else } +var create_4_8_cumulus_alleys = func (lat, lon, alt, alpha) { + + +var phi = alpha * math.pi/180.0; +var x = 2.0 * (rand()-0.5) * 5000; +var y = 2.0 * (rand()-0.5) * 5000; +var tri = 1.0 + 0.4 * rand(); + +# create_cumulus_alleys = func (blat, blong, balt, alt_var, nx, xoffset, edgex, x_var, ny, yoffset, edgey, y_var, und_strength, direction, tri) + +local_weather.create_cumulus_alleys(lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt, 0.0, 9, 3500.0,0.2, 500.0, 30 ,1130.0, 0.2, 300.0, 1000.0, alpha,tri); + +} + + + + var create_4_8_cirrus = func (lat, lon, alt, alpha) { var phi = alpha * math.pi/180.0; @@ -3133,6 +3254,22 @@ for (var i=0; i<8; i=i+1) +var create_2_8_altocumulus_perlucidus = func (lat, lon, alt, alpha) { + +if (local_weather.hardcoded_clouds_flag == 1) {alt = alt - 300.0;} + +var phi = alpha * math.pi/180.0; + +for (var i=0; i<40; i=i+1) + { + var x = 2.0 * (rand()-0.5) * 18000; + var y = 2.0 * (rand()-0.5) * 18000; + var beta = (rand() -0.5) * 180.0; + local_weather.create_streak("Altocumulus perlucidus",lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt,300.0,2,1400.0,0.1,900.0,2,1400.0,0.1,900.0,alpha+beta,1.0); + + } + +} @@ -3386,14 +3523,14 @@ if (local_weather.hardcoded_clouds_flag == 0) } else { - local_weather.create_streak("Stratocumulus",lat+get_lat(x,y+7500,phi), lon+get_lon(x,y+7500,phi), alt-1000.0 ,500.0,m,1100.0,0.1,400.0,n,1100.0,0.1,400.0,alpha+90.0+beta,tri); + local_weather.create_streak("Stratocumulus",lat+get_lat(x,y+7500,phi), lon+get_lon(x,y+7500,phi), alt-local_weather.offset_map["Congestus"] + 400.0 ,500.0,m,1100.0,0.1,400.0,n,1100.0,0.1,400.0,alpha+90.0+beta,tri); - local_weather.create_streak("Stratocumulus",lat+get_lat(x,y-7500,phi), lon+get_lon(x,y-7500,phi), alt-1000.0 ,500.0,m,1100.0,0.1,400.0,n,1100.0,0.1,400.0,alpha+270.0+beta,tri); + local_weather.create_streak("Stratocumulus",lat+get_lat(x,y-7500,phi), lon+get_lon(x,y-7500,phi), alt-local_weather.offset_map["Congestus"] + 400.0 ,500.0,m,1100.0,0.1,400.0,n,1100.0,0.1,400.0,alpha+270.0+beta,tri); - local_weather.create_streak("Stratocumulus bottom",lat+get_lat(x,y+5250,phi), lon+get_lon(x,y+5250,phi), alt-1000.0,0.0,m+1,700.0,0.2,400.0,n+1,700.0,0.0,400.0,alpha+90.0+beta,tri); + local_weather.create_streak("Stratocumulus bottom",lat+get_lat(x,y+5250,phi), lon+get_lon(x,y+5250,phi), alt-local_weather.offset_map["Stratus"],0.0,m+1,700.0,0.2,400.0,n+1,700.0,0.0,400.0,alpha+90.0+beta,tri); - local_weather.create_streak("Stratocumulus bottom",lat+get_lat(x,y-5250,phi), lon+get_lon(x,y-5250,phi), alt-1000.0,0.0,m+1,700.0,0.2,400.0,n+1,700.0,0.0,400.0,alpha+270.0+beta,tri); + local_weather.create_streak("Stratocumulus bottom",lat+get_lat(x,y-5250,phi), lon+get_lon(x,y-5250,phi), alt-local_weather.offset_map["Stratus"],0.0,m+1,700.0,0.2,400.0,n+1,700.0,0.0,400.0,alpha+270.0+beta,tri); } @@ -3413,14 +3550,14 @@ var n = int(6 + rand() * 5); var alt_offset = 0.5 * local_weather.cloud_vertical_size_map["Cumulus"] * ft_to_m; -local_weather.create_streak("Stratocumulus",lat+get_lat(x,y+7500,phi), lon+get_lon(x,y+7500,phi), alt + alt_offset,500.0,m,1100.0,0.12,400.0,n,1100.0,0.12,400.0,alpha+90.0+beta,tri); +local_weather.create_streak("Stratocumulus",lat+get_lat(x,y+7500,phi), lon+get_lon(x,y+7500,phi), alt - local_weather.offset_map["Congestus"] + 400.0,500.0,m,1100.0,0.12,400.0,n,1100.0,0.12,400.0,alpha+90.0+beta,tri); -local_weather.create_streak("Stratocumulus",lat+get_lat(x,y-7500,phi), lon+get_lon(x,y-7500,phi), alt + alt_offset,500.0,m,1100.0,0.12,400.0,n,1100.0,0.12,400.0,alpha+270.0+beta,tri); +local_weather.create_streak("Stratocumulus",lat+get_lat(x,y-7500,phi), lon+get_lon(x,y-7500,phi), alt -local_weather.offset_map["Congestus"] + 400.0,500.0,m,1100.0,0.12,400.0,n,1100.0,0.12,400.0,alpha+270.0+beta,tri); -local_weather.create_streak("Stratocumulus bottom",lat+get_lat(x,y+7050,phi), lon+get_lon(x,y+7050,phi), alt,0.0,m,700.0,0.2,400.0,n,700.0,0.0,400.0,alpha+90.0+beta,tri); +local_weather.create_streak("Stratocumulus bottom",lat+get_lat(x,y+7050,phi), lon+get_lon(x,y+7050,phi), alt - local_weather.offset_map["Stratus"],0.0,m,700.0,0.2,400.0,n,700.0,0.0,400.0,alpha+90.0+beta,tri); -local_weather.create_streak("Stratocumulus bottom",lat+get_lat(x,y-7050,phi), lon+get_lon(x,y-7050,phi), alt,0.0,m,700.0,0.2,400.0,n,700.0,0.0,400.0,alpha+270.0+beta,tri); +local_weather.create_streak("Stratocumulus bottom",lat+get_lat(x,y-7050,phi), lon+get_lon(x,y-7050,phi), alt-local_weather.offset_map["Stratus"],0.0,m,700.0,0.2,400.0,n,700.0,0.0,400.0,alpha+270.0+beta,tri); } @@ -3536,7 +3673,7 @@ if (local_weather.wxradar_support_flag == 1) } -# spectacular, but not useful in practice + var create_2_8_cirrocumulus_patches = func (lat, lon, alt, alpha) { @@ -3550,9 +3687,7 @@ for (var i=0; i<2; i=i+1) var tri = 1.5 + rand(); var beta = rand() * math.pi; - #local_weather.create_streak("Cirrocumulus (new)",lat+get_lat(x,y,phi), lon+get_lon(x,y,phi), alt,0.0,50,150.0,0.2,50.0,50,150.0,0.2,50.0,alpha ,tri); - - local_weather.create_layer("Cirrocumulus (new)", lat+get_lat(x,y,phi), lon+get_lat(x,y,phi), alt, 0.0, 8500.0, 5000.0, beta, 15.0, 0.25, 0, 0.0); + local_weather.create_layer("Cirrocumulus (new)", lat+get_lat(x,y,phi), lon+get_lat(x,y,phi), alt, 0.0, 8000.0, 4500.0, beta, 10.0, 0.25, 0, 0.0); } } diff --git a/Shaders/3dcloud-lightfield.frag b/Shaders/3dcloud-lightfield.frag index dd90fdddf..5c55008f0 100644 --- a/Shaders/3dcloud-lightfield.frag +++ b/Shaders/3dcloud-lightfield.frag @@ -7,9 +7,8 @@ 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 index 0f512fbea..e965a24f9 100644 --- a/Shaders/3dcloud-lightfield.vert +++ b/Shaders/3dcloud-lightfield.vert @@ -2,6 +2,7 @@ #version 120 varying float fogFactor; +//varying float MieFactor; varying vec3 hazeColor; uniform float range; // From /sim/rendering/clouds3d-vis-range @@ -35,6 +36,12 @@ if (x < -15.0) {return 0.0;} return e / pow((1.0 + a * exp(-b * (x-c)) ),(1.0/d)); } + +float mie_func (in float x, in float Mie) +{ +return x + 2.0 * x * Mie * (1.0 -0.8*x) * (1.0 -0.8*x); +} + void main(void) { @@ -104,6 +111,8 @@ void main(void) 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 @@ -146,7 +155,6 @@ void main(void) //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; @@ -163,7 +171,30 @@ void main(void) 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; + hazeColor = hazeColor * earthShade; + gl_FrontColor.xyz = gl_FrontColor.xyz * earthShade; + + // Mie correction + float Mie; + float MieFactor; + + if (shade_factor > 0.6) + { + MieFactor = dot(normalize(lightFull), normalize(relVector)); + Mie = 1.5 * smoothstep(0.9,1.0, MieFactor) * smoothstep(0.6, 0.8, shade_factor); + } + else {Mie = 0.0;} + + if (Mie > 0.0) + { + hazeColor.r = mie_func(hazeColor.r, Mie); + hazeColor.g = mie_func(hazeColor.g, 0.8* Mie); + hazeColor.b = mie_func(hazeColor.b, 0.5* Mie); + + gl_FrontColor.r = mie_func(gl_FrontColor.r, Mie); + gl_FrontColor.g = mie_func(gl_FrontColor.g, 0.8* Mie); + gl_FrontColor.b = mie_func(gl_FrontColor.b, 0.5*Mie); + } + + gl_BackColor = gl_FrontColor; } diff --git a/Shaders/skydome.frag b/Shaders/skydome.frag index a65f5e5d9..6b721a59f 100644 --- a/Shaders/skydome.frag +++ b/Shaders/skydome.frag @@ -80,13 +80,20 @@ void main() // 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); - + +// a different exposure filter +//color.x = 1.0 - exp(-1.3 * color.x); +//color.y = 1.0 - exp(-1.3 * color.y); +//color.z = 1.0 - exp(-1.3 * color.z); + +if (color.x > 0.58) color.x = 1.0 - exp(-1.5 * color.x); +if (color.y > 0.58) color.y = 1.0 - exp(-1.5 * color.y); +if (color.z > 0.58) color.z = 1.0 - exp(-1.5 * 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)); +//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)); @@ -101,10 +108,10 @@ float delta_zv; float costheta = ct; -float vis= visibility; +float vis = min(visibility, avisibility); // hack - in an effect volume the visibility only may be reduced, so we take care here -if (avisibility < visibility){vis = avisibility;} +//if (avisibility < visibility){vis = avisibility;} if (delta_z > 0.0) // we're inside the layer { @@ -142,11 +149,9 @@ if (avisibility < visibility){vis = avisibility;} // 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); - - +//float scattering = ground_scattering + (1.0 - ground_scattering) * smoothstep(avisibility, 1.5 * avisibility, -alt/costheta); +float eqColorFactor = 1.0 - 0.1 * delta_zv/vis - (1.0 -scattering); // there's always residual intensity, we should never be driven to zero diff --git a/Shaders/skydome.vert b/Shaders/skydome.vert index 58219e6e6..43673a5c8 100644 --- a/Shaders/skydome.vert +++ b/Shaders/skydome.vert @@ -43,7 +43,8 @@ const float fSamples = float(nSamples); uniform float rK = 0.0003; //0.00015; uniform float mK = 0.003; //0.0025; uniform float density = 0.5; //1.0 -vec3 rayleighK = rK * vec3(5.602, 7.222, 19.644); +//vec3 rayleighK = rK * vec3(5.602, 7.222, 19.644); +vec3 rayleighK = rK * vec3(4.5, 8.62, 17.3); vec3 mieK = vec3(mK); vec3 sunIntensity = 10.0*vec3(120.0, 125.0, 130.0); @@ -235,7 +236,7 @@ void main() { if (ct < 0.0) { - yprime = -dot(relVector,lightHorizon) * altitude/-(ct-0.001); + yprime = -dot(relVector,lightHorizon) * altitude/-ct;//(ct-0.001); yprime = yprime -sqrt(2.0 * EarthRadius * hazeLayerAltitude); } else // the only haze we see looking up is overcast, assume its altitude diff --git a/Shaders/terrain-haze-detailed.frag b/Shaders/terrain-haze-detailed.frag new file mode 100644 index 000000000..8764e1956 --- /dev/null +++ b/Shaders/terrain-haze-detailed.frag @@ -0,0 +1,351 @@ +// -*-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 vec4 rawPos; + + +//varying vec3 hazeColor; +//varying float fogCoord; + +uniform sampler2D texture; +uniform sampler3D NoiseTex; +uniform sampler2D snow_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; +varying float steepness; + + +uniform float visibility; +uniform float avisibility; +uniform float scattering; +//uniform float ground_scattering; +uniform float terminator; +uniform float terrain_alt; +uniform float hazeLayerAltitude; +uniform float overcast; +//uniform float altitude; +uniform float eye_alt; +uniform float mysnowlevel; +uniform float dust_cover_factor; +uniform float fogstructure; + +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 snow_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); + snow_texel = texture2D(snow_texture, gl_TexCoord[0].st); + + +// this is the snow and dust generating part, ger some noise vectors +vec4 noisevec = texture3D(NoiseTex, (rawPos.xyz)*0.003); // small scale noise +//vec4 nvL = texture3D(NoiseTex, (rawPos.xyz)*0.00066); +vec4 nvL = texture3D(NoiseTex, (rawPos.xyz)*0.0001); // large scale noise +vec4 nvR = texture3D(NoiseTex, (rawPos.xyz)*0.00003); // really large scale noise + +//float ns=0.06; + // ns += nvL[0]*0.4; + //ns += nvL[1]*0.6; + //ns += nvL[2]*2.0; + //ns += nvL[3]*4.0; + //ns += noisevec[0]*0.1; + //ns += noisevec[1]*0.4; + + //ns += noisevec[2]*0.8; + //ns += noisevec[3]*2.1; + + // gradient effect for snow + + +// mix dust + vec4 dust_color = vec4 (0.76, 0.71, 0.56, 1.0); + //dust_color.rgb = dust_color.rgb * nvL[1]; + + texel = mix(texel, dust_color, clamp(0.5 * dust_cover_factor + 3.0 * dust_cover_factor * nvL[1],0.0, 1.0) ); + + + float snow_alpha = smoothstep(0.7, 0.8, abs(steepness)); + + //vec4 snow_texel = clamp(ns+nvL[2]*4.1+vec4(0.1, 0.1, nvL[2]*2.2, 1.0), 0.7, 1.0); + //snow_texel.a = snow_alpha * snow_texel.a; + + + + // mix snow + texel = mix(texel, snow_texel, smoothstep(mysnowlevel, mysnowlevel+200.0, snow_alpha * (relPos.z + eye_alt)+ (noisevec[1] * abs(noisevec[1])+ nvL[1])*1500.0)); + +// gradient + //fragColor = mix(vec4(ns-0.30, ns-0.29, ns-0.37, 1.0), fragColor, smoothstep(0.0, 0.40, steepness));// +nvL[2]*1.3)); + + 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; + vAltitude = min(distance_in_layer,min(visibility, avisibility)) * 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;} + 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; + +//float scattering = ground_scattering + (1.0 - ground_scattering) * smoothstep(hazeLayerAltitude -100.0, hazeLayerAltitude + 100.0, relPos.z + eye_alt); + + +if (visibility < avisibility) + { + transmission_arg = transmission_arg + (distance_in_layer/(1.0 * visibility + 0.8 * visibility * fogstructure * (( 0.4 * nvL[1] + 0.6 * nvR[1]) -0.1) )); + //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/(1.0 * avisibility + 0.8 * avisibility * fogstructure * (( 0.4 * nvL[1] + 0.6 * nvR[1]) -0.1) )); + //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)); + +// randomness + +//hazeColor.rgb = hazeColor.rgb + 0.2 * hazeColor.rgb * nvL[1]; + +// determine the right mix of transmission and haze + +//fragColor.xyz = transmission * fragColor.xyz + (1.0-transmission) * eqColorFactor * hazeColor * earthShade; + + +//fragColor.rgb = mix(fragColor.rgb, vec3 (1.0, 1.0, 1.0), overcast ); + + +fragColor.xyz = mix(eqColorFactor * hazeColor * earthShade, fragColor.xyz,transmission); + + +gl_FragColor = fragColor; + + +} +else // if dist < 40.0 no fogging at all +{ +gl_FragColor = fragColor; +} + + +//gl_FragColor.rgb = 5.0 * nvL[1] * vec3 (1.0, 1.0, 1.0); + +} + diff --git a/Shaders/terrain-haze-detailed.vert b/Shaders/terrain-haze-detailed.vert new file mode 100644 index 000000000..7adfb8c66 --- /dev/null +++ b/Shaders/terrain-haze-detailed.vert @@ -0,0 +1,243 @@ +// -*-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 vec4 rawPos; + +varying float earthShade; +//varying float yprime; +//varying float vertex_alt; +varying float yprime_alt; +varying float mie_angle; +varying float steepness; + + + + +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; +uniform float ground_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; + float scattering; + + rawPos = gl_Vertex; + steepness = dot(normalize(gl_Normal), vec3 (0.0, 0.0, 1.0)); + +// 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); + + // 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); + scattering = ground_scattering + (1.0 - ground_scattering) * smoothstep(hazeLayerAltitude -100.0, hazeLayerAltitude + 100.0, vertex_alt); + + // branch dependent on daytime + +if (terminator < 1000000.0) // the full, sunrise and sunset computation +{ + + + // 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/Shaders/terrain-haze.frag b/Shaders/terrain-haze.frag index bf14090b9..54595d5e1 100644 --- a/Shaders/terrain-haze.frag +++ b/Shaders/terrain-haze.frag @@ -20,11 +20,12 @@ varying float earthShade; //varying float vertex_alt; varying float yprime_alt; varying float mie_angle; - + uniform float visibility; uniform float avisibility; uniform float scattering; +//uniform float ground_scattering; uniform float terminator; uniform float terrain_alt; uniform float hazeLayerAltitude; @@ -157,8 +158,7 @@ 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; + vAltitude = min(distance_in_layer,min(visibility, avisibility)) * ct; delta_zv = delta_z - vAltitude; } else // we may look through upper layer edge @@ -166,7 +166,6 @@ if (delta_z > 0.0) // we're inside the layer 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; } @@ -198,6 +197,7 @@ transmission_arg = (dist-distance_in_layer)/avisibility; float eqColorFactor; +//float scattering = ground_scattering + (1.0 - ground_scattering) * smoothstep(hazeLayerAltitude -100.0, hazeLayerAltitude + 100.0, relPos.z + eye_alt); if (visibility < avisibility) { @@ -214,6 +214,7 @@ else } + transmission = fog_func(transmission_arg); // there's always residual intensity, we should never be driven to zero @@ -234,7 +235,7 @@ earthShade = 0.9 * smoothstep(terminator_width+ terminator, -terminator_width + // Mie-like factor -if (lightArg < 5.0) +if (lightArg < 10.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)) ); diff --git a/Shaders/terrain-haze.vert b/Shaders/terrain-haze.vert index f1cd4732d..fde08a6c7 100644 --- a/Shaders/terrain-haze.vert +++ b/Shaders/terrain-haze.vert @@ -38,7 +38,8 @@ uniform float terrain_alt; uniform float avisibility; uniform float visibility; uniform float overcast; -uniform float scattering; +//uniform float scattering; +uniform float ground_scattering; // This is the value used in the skydome scattering shader - use the same here for consistency? @@ -67,6 +68,7 @@ void main() float lightArg; float intensity; float vertex_alt; + float scattering; // this code is copied from default.vert @@ -100,13 +102,16 @@ void main() // 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); - + + // 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); + scattering = ground_scattering + (1.0 - ground_scattering) * smoothstep(hazeLayerAltitude -100.0, hazeLayerAltitude + 100.0, vertex_alt); + // 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 @@ -129,12 +134,14 @@ if (terminator < 1000000.0) // the full, sunrise and sunset computation lightArg = (terminator-yprime_alt)/100000.0; // directional scattering for low sun - if (lightArg < 5.0) + if (lightArg < 10.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); @@ -209,8 +216,6 @@ else // the faster, full-day version without lightfields light_diffuse = light_diffuse * scattering; yprime_alt = -sqrt(2.0 * EarthRadius * hazeLayerAltitude); - - } diff --git a/Shaders/water_lightfield.frag b/Shaders/water_lightfield.frag new file mode 100644 index 000000000..b86b3a4c6 --- /dev/null +++ b/Shaders/water_lightfield.frag @@ -0,0 +1,577 @@ +// This shader is mostly an adaptation of the shader found at +// http://www.bonzaisoftware.com/water_tut.html and its glsl conversion +// available at http://forum.bonzaisoftware.com/viewthread.php?tid=10 +// © Michael Horsch - 2005 +// Major update and revisions - 2011-10-07 +// © Emilian Huminiuc and Vivian Meazza + +#version 120 + +uniform sampler2D water_normalmap; +//uniform sampler2D water_reflection; +uniform sampler2D water_dudvmap; +//uniform sampler2D water_reflection_grey; +uniform sampler2D sea_foam; +uniform sampler2D perlin_normalmap; + +uniform sampler3D Noise; + +uniform float saturation, Overcast, WindE, WindN; +//uniform float CloudCover0, CloudCover1, CloudCover2, CloudCover3, CloudCover4; +uniform float osg_SimulationTime; +//uniform int Status; + +varying vec4 waterTex1; //moving texcoords +varying vec4 waterTex2; //moving texcoords +varying vec4 waterTex4; //viewts +//varying vec4 ecPosition; +varying vec3 viewerdir; +varying vec3 lightdir; +//varying vec3 normal; +varying vec3 specular_light; +varying vec3 relPos; + +varying float earthShade; +varying float yprime_alt; +varying float mie_angle; + +uniform float WaveFreq ; +uniform float WaveAmp ; +uniform float WaveSharp ; +uniform float WaveAngle ; +uniform float WaveFactor ; +uniform float WaveDAngle ; + + +uniform float hazeLayerAltitude; +uniform float terminator; +uniform float terrain_alt; +uniform float avisibility; +uniform float visibility; +uniform float overcast; +uniform float scattering; +uniform float ground_scattering; +uniform float eye_alt; +uniform float sea_r; +uniform float sea_g; +uniform float sea_b; + +const float terminator_width = 200000.0; +const float EarthRadius = 5800000.0; +////fog "include" ///// +//uniform int fogType; + +vec3 fog_Func(vec3 color, int type); +////////////////////// + +/////// functions ///////// + +void rotationmatrix(in float angle, out mat4 rotmat) + { + rotmat = mat4( cos( angle ), -sin( angle ), 0.0, 0.0, + sin( angle ), cos( angle ), 0.0, 0.0, + 0.0 , 0.0 , 1.0, 0.0, + 0.0 , 0.0 , 0.0, 1.0 ); + } + +// wave functions /////////////////////// + +struct Wave { + float freq; // 2*PI / wavelength + float amp; // amplitude + float phase; // speed * 2*PI / wavelength + vec2 dir; + }; + +Wave wave0 = Wave(1.0, 1.0, 0.5, vec2(0.97, 0.25)); +Wave wave1 = Wave(2.0, 0.5, 1.3, vec2(0.97, -0.25)); +Wave wave2 = Wave(1.0, 1.0, 0.6, vec2(0.95, -0.3)); +Wave wave3 = Wave(2.0, 0.5, 1.4, vec2(0.99, 0.1)); + +float evaluateWave(in Wave w, vec2 pos, float t) + { + return w.amp * sin( dot(w.dir, pos) * w.freq + t * w.phase); + } + +// derivative of wave function +float evaluateWaveDeriv(Wave w, vec2 pos, float t) + { + return w.freq * w.amp * cos( dot(w.dir, pos)*w.freq + t*w.phase); + } + +// sharp wave functions +float evaluateWaveSharp(Wave w, vec2 pos, float t, float k) + { + return w.amp * pow(sin( dot(w.dir, pos)*w.freq + t*w.phase)* 0.5 + 0.5 , k); + } + +float evaluateWaveDerivSharp(Wave w, vec2 pos, float t, float k) + { + return k*w.freq*w.amp * pow(sin( dot(w.dir, pos)*w.freq + t*w.phase)* 0.5 + 0.5 , k - 1) * cos( dot(w.dir, pos)*w.freq + t*w.phase); + } + +void sumWaves(float angle, float dangle, float windScale, float factor, out float ddx, float ddy) + { + mat4 RotationMatrix; + float deriv; + vec4 P = waterTex1 * 1024; + + rotationmatrix(radians(angle + dangle * windScale + 0.6 * sin(P.x * factor)), RotationMatrix); + P *= RotationMatrix; + + P.y += evaluateWave(wave0, P.xz, osg_SimulationTime); + deriv = evaluateWaveDeriv(wave0, P.xz, osg_SimulationTime ); + ddx = deriv * wave0.dir.x; + ddy = deriv * wave0.dir.y; + + P.y += evaluateWave(wave1, P.xz, osg_SimulationTime); + deriv = evaluateWaveDeriv(wave1, P.xz, osg_SimulationTime); + ddx += deriv * wave1.dir.x; + ddy += deriv * wave1.dir.y; + + P.y += evaluateWaveSharp(wave2, P.xz, osg_SimulationTime, WaveSharp); + deriv = evaluateWaveDerivSharp(wave2, P.xz, osg_SimulationTime, WaveSharp); + ddx += deriv * wave2.dir.x; + ddy += deriv * wave2.dir.y; + + P.y += evaluateWaveSharp(wave3, P.xz, osg_SimulationTime, WaveSharp); + deriv = evaluateWaveDerivSharp(wave3, P.xz, osg_SimulationTime, WaveSharp); + ddx += deriv * wave3.dir.x; + ddy += deriv * wave3.dir.y; + } + + +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 (eye_alt < 30000.0) + {return exp(-targ - targ * targ * targ * targ);} +else if (eye_alt < 50000.0) + { + fade_mix = (eye_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(void) + { + + float dist = length(relPos); + const vec4 sca = vec4(0.005, 0.005, 0.005, 0.005); + const vec4 sca2 = vec4(0.02, 0.02, 0.02, 0.02); + const vec4 tscale = vec4(0.25, 0.25, 0.25, 0.25); + + mat4 RotationMatrix; + + // compute direction to viewer + vec3 E = normalize(viewerdir); + + // compute direction to light source + vec3 L = lightdir; // normalize(lightdir); + + // half vector + vec3 Hv = normalize(L + E); + + //vec3 Normal = normalize(normal); + vec3 Normal = vec3 (0.0, 0.0, 1.0); + + const float water_shininess = 240.0; + + // approximate cloud cover + //float cover = 0.0; + //bool Status = true; + + float windEffect = sqrt( WindE*WindE + WindN*WindN ) * 0.6; //wind speed in kt + float windScale = 15.0/(3.0 + windEffect); //wave scale + float windEffect_low = 0.3 + 0.7 * smoothstep(0.0, 5.0, windEffect); //low windspeed wave filter + float waveRoughness = 0.01 + smoothstep(0.0, 40.0, windEffect); //wave roughness filter + + float mixFactor = 0.2 + 0.02 * smoothstep(0.0, 50.0, windEffect); + //mixFactor = 0.2; + mixFactor = clamp(mixFactor, 0.3, 0.8); + + // there's no need to do wave patterns or foam for pixels which are so far away that we can't actually see them + // we only need detail in the near zone or where the sun reflection is + + int detail_flag; + if ((dist > 15000.0) && (dot(normalize(vec3 (lightdir.x, lightdir.y, 0.0) ), normalize(relPos)) < 0.7 )) {detail_flag = 0;} + else {detail_flag = 1;} + + + // sine waves + float ddx, ddx1, ddx2, ddx3, ddy, ddy1, ddy2, ddy3; + + if (detail_flag == 1) + { + float angle = 0.0; + + wave0.freq = WaveFreq ; + wave0.amp = WaveAmp; + wave0.dir = vec2(cos(radians(angle)), sin(radians(angle))); + + angle -= 45; + wave1.freq = WaveFreq * 2.0 ; + wave1.amp = WaveAmp * 1.25; + wave1.dir = vec2(cos(radians(angle)), sin(radians(angle))); + + angle += 30; + wave2.freq = WaveFreq * 3.5; + wave2.amp = WaveAmp * 0.75; + wave2.dir = vec2(cos(radians(angle)), sin(radians(angle))); + + angle -= 50; + wave3.freq = WaveFreq * 3.0 ; + wave3.amp = WaveAmp * 0.75; + wave3.dir = vec2(cos(radians(angle)), sin(radians(angle))); + + // sum waves + + ddx = 0.0, ddy = 0.0; + sumWaves(WaveAngle, -1.5, windScale, WaveFactor, ddx, ddy); + + ddx1 = 0.0, ddy1 = 0.0; + sumWaves(WaveAngle, 1.5, windScale, WaveFactor, ddx1, ddy1); + + //reset the waves + angle = 0.0; + float waveamp = WaveAmp * 0.75; + + wave0.freq = WaveFreq ; + wave0.amp = waveamp; + wave0.dir = vec2(cos(radians(angle)), sin(radians(angle))); + + angle -= 20; + wave1.freq = WaveFreq * 2.0 ; + wave1.amp = waveamp * 1.25; + wave1.dir = vec2(cos(radians(angle)), sin(radians(angle))); + + angle += 35; + wave2.freq = WaveFreq * 3.5; + wave2.amp = waveamp * 0.75; + wave2.dir = vec2(cos(radians(angle)), sin(radians(angle))); + + angle -= 45; + wave3.freq = WaveFreq * 3.0 ; + wave3.amp = waveamp * 0.75; + wave3.dir = vec2(cos(radians(angle)), sin(radians(angle))); + + ddx2 = 0.0, ddy2 = 0.0; + sumWaves(WaveAngle + WaveDAngle, -1.5, windScale, WaveFactor, ddx2, ddy2); + + ddx3 = 0.0, ddy3 = 0.0; + sumWaves(WaveAngle + WaveDAngle, 1.5, windScale, WaveFactor, ddx3, ddy3); + } + // end sine stuff + + //cover = 5.0 * smoothstep(0.6, 1.0, scattering); + //cover = 5.0 * ground_scattering; + + vec4 viewt = normalize(waterTex4); + + vec4 disdis = texture2D(water_dudvmap, vec2(waterTex2 * tscale)* windScale) * 2.0 - 1.0; + + vec4 vNorm; + + + //normalmaps + vec4 nmap = texture2D(water_normalmap, vec2(waterTex1 + disdis * sca2) * windScale) * 2.0 - 1.0; + vec4 nmap1 = texture2D(perlin_normalmap, vec2(waterTex1 + disdis * sca2) * windScale) * 2.0 - 1.0; + + rotationmatrix(radians(3.0 * sin(osg_SimulationTime * 0.0075)), RotationMatrix); + nmap += texture2D(water_normalmap, vec2(waterTex2 * RotationMatrix * tscale) * windScale) * 2.0 - 1.0; + nmap1 += texture2D(perlin_normalmap, vec2(waterTex2 * RotationMatrix * tscale) * windScale) * 2.0 - 1.0; + + nmap *= windEffect_low; + nmap1 *= windEffect_low; + + // mix water and noise, modulated by factor + vNorm = normalize(mix(nmap, nmap1, mixFactor) * waveRoughness); + if (detail_flag == 1) {vNorm.r += ddx + ddx1 + ddx2 + ddx3;} + vNorm = -vNorm; + //dds fix + + + + + //load reflection + + vec4 refl ; + + refl.r = sea_r; + refl.g = sea_g; + refl.b = sea_b; + refl.a = 1.0; + + + float intensity; + // de-saturate for reduced light + refl.rgb = mix(refl.rgb, vec3 (0.248, 0.248, 0.248), 1.0 - smoothstep(0.3, 0.7, ground_scattering)); + + // de-saturate light for overcast haze + intensity = length(refl.rgb); + refl.rgb = mix(refl.rgb, intensity * vec3 (1.0, 1.0, 1.0), smoothstep(0.1, 0.8, overcast)); + + vec3 N; + + if (detail_flag == 1) + { + + vec3 N0 = vec3(texture2D(water_normalmap, vec2(waterTex1 + disdis * sca2) * windScale) * 2.0 - 1.0); + vec3 N1 = vec3(texture2D(perlin_normalmap, vec2(waterTex1 + disdis * sca) * windScale) * 2.0 - 1.0); + + N0 += vec3(texture2D(water_normalmap, vec2(waterTex1 * tscale) * windScale) * 2.0 - 1.0); + N1 += vec3(texture2D(perlin_normalmap, vec2(waterTex2 * tscale) * windScale) * 2.0 - 1.0); + + rotationmatrix(radians(2.0 * sin(osg_SimulationTime * 0.005)), RotationMatrix); + N0 += vec3(texture2D(water_normalmap, vec2(waterTex2 * RotationMatrix * (tscale + sca2)) * windScale) * 2.0 - 1.0); + N1 += vec3(texture2D(perlin_normalmap, vec2(waterTex2 * RotationMatrix * (tscale + sca2)) * windScale) * 2.0 - 1.0); + + rotationmatrix(radians(-4.0 * sin(osg_SimulationTime * 0.003)), RotationMatrix); + N0 += vec3(texture2D(water_normalmap, vec2(waterTex1 * RotationMatrix + disdis * sca2) * windScale) * 2.0 - 1.0); + N1 += vec3(texture2D(perlin_normalmap, vec2(waterTex1 * RotationMatrix + disdis * sca) * windScale) * 2.0 - 1.0); + + N0 *= windEffect_low; + N1 *= windEffect_low; + + N0.r += (ddx + ddx1 + ddx2 + ddx3); + N0.g += (ddy + ddy1 + ddy2 + ddy3); + + N = normalize(mix(Normal + N0, Normal + N1, mixFactor) * waveRoughness); + + N = -N; //dds fix + } + else + {N = vec3 (0.0, 0.0, 1.0);} + + //float lightArg = (terminator-yprime_alt)/100000.0; + + + + + vec3 specular_color = vec3(specular_light) + * pow(max(0.0, dot(N, Hv)), water_shininess) * 6.0; + vec4 specular = vec4(specular_color, 0.5); + + specular = specular * saturation * 0.3 * earthShade ; + + //calculate fresnel + vec4 invfres = vec4( dot(vNorm, viewt) ); + vec4 fres = vec4(1.0) + invfres; + refl *= fres; + + + + vec4 ambient_light; + + ambient_light.rgb = specular_light.rgb; + ambient_light.a = 1.0; + + + vec4 finalColor; + + //if(cover >= 1.5) + //if (ground_scattering > 0.4) + // { + // finalColor = refl + specular; + // } else { + // finalColor = refl; + // } + + finalColor = refl + specular * smoothstep(0.3, 0.6, ground_scattering); + + //add foam + + if (dist < 10000.0) + { + float foamSlope = 0.10 + 0.1 * windScale; + + + vec4 foam_texel = texture2D(sea_foam, vec2(waterTex2 * tscale) * 25.0); + float waveSlope = N.g; + + if (windEffect >= 8.0) + if (waveSlope >= foamSlope){ + finalColor = mix(finalColor, max(finalColor, finalColor + foam_texel), smoothstep(0.01, 0.50, N.g)); + } + } + + + + finalColor *= ambient_light; + + + +// here comes the terrain haze model + + +float delta_z = hazeLayerAltitude - eye_alt; + + + +if (dist > 40.0) +{ + + +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,min(visibility,avisibility)) * 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.rgb = specular_light.rgb; +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 +float eShade = 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, eye_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,eShade) )); + +// 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)); + + finalColor.rgb = mix(eqColorFactor * hazeColor * eShade, finalColor.rgb,transmission); + + + } + gl_FragColor = finalColor; + +} diff --git a/Shaders/water_lightfield.vert b/Shaders/water_lightfield.vert new file mode 100644 index 000000000..5da4193c6 --- /dev/null +++ b/Shaders/water_lightfield.vert @@ -0,0 +1,226 @@ +// This shader is mostly an adaptation of the shader found at +// http://www.bonzaisoftware.com/water_tut.html and its glsl conversion +// available at http://forum.bonzaisoftware.com/viewthread.php?tid=10 +// © Michael Horsch - 2005 +// Major update and revisions - 2011-10-07 +// © Emilian Huminiuc and Vivian Meazza + +#version 120 + +varying vec4 waterTex1; +varying vec4 waterTex2; +varying vec4 waterTex4; +//varying vec4 ecPosition; +varying vec3 relPos; +varying vec3 specular_light; + +varying vec3 viewerdir; +varying vec3 lightdir; +//varying vec3 normal; + +varying float earthShade; +varying float yprime_alt; +varying float mie_angle; + +uniform float osg_SimulationTime; +uniform float WindE, WindN; + +uniform float hazeLayerAltitude; +uniform float terminator; +uniform float terrain_alt; +uniform float avisibility; +uniform float visibility; +uniform float overcast; +uniform float ground_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)); +} + + +////fog "include"//////// +// uniform int fogType; +// +// void fog_Func(int type); +///////////////////////// + +/////// functions ///////// + +void rotationmatrix(in float angle, out mat4 rotmat) +{ + rotmat = mat4( cos( angle ), -sin( angle ), 0.0, 0.0, + sin( angle ), cos( angle ), 0.0, 0.0, + 0.0 , 0.0 , 1.0, 0.0, + 0.0 , 0.0 , 0.0, 1.0 ); +} + +void main(void) +{ + + mat4 RotationMatrix; + // vec3 N = normalize(gl_Normal); + // normal = N; + + vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex; + + viewerdir = vec3(gl_ModelViewMatrixInverse[3]) - vec3(gl_Vertex); + lightdir = normalize(vec3(gl_ModelViewMatrixInverse * gl_LightSource[0].position)); + + waterTex4 = vec4( ecPosition.xzy, 0.0 ); + + vec4 t1 = vec4(0.0, osg_SimulationTime * 0.005217, 0.0, 0.0); + vec4 t2 = vec4(0.0, osg_SimulationTime * -0.0012, 0.0, 0.0); + + float Angle; + + float windFactor = sqrt(pow(abs(WindE),2)+pow(abs(WindN),2)) * 0.05; + if (WindN == 0.0 && WindE == 0.0) { + Angle = 0.0; + }else{ + Angle = atan(-WindN, WindE) - atan(1.0); + } + + rotationmatrix(Angle, RotationMatrix); + waterTex1 = gl_MultiTexCoord0 * RotationMatrix - t1 * windFactor; + + rotationmatrix(Angle, RotationMatrix); + waterTex2 = gl_MultiTexCoord0 * RotationMatrix - t2 * windFactor; + +// fog_Func(fogType); + gl_Position = ftransform(); + + + +// here start computations for the haze layer + + + float yprime; + float lightArg; + float intensity; + float vertex_alt; + float scattering; + + // 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); + + +// 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); + scattering = 0.5 + 0.5 * ground_scattering + 0.5* (1.0 - ground_scattering) * smoothstep(hazeLayerAltitude -100.0, hazeLayerAltitude + 100.0, vertex_alt); + + // branch dependent on daytime + +if (terminator < 1000000.0) // the full, sunrise and sunset computation +{ + + + // 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)); + vec3 lightHorizon = normalize(vec3(lightdir.x,lightdir.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; + + specular_light.b = light_func(lightArg, 1.330e-05, 0.264, 3.827, 1.08e-05, 1.0); + specular_light.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0); + specular_light.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0); + + specular_light = specular_light * scattering; + + // correct ambient light intensity and hue before sunrise + if (earthShade < 0.5) + { + intensity = length(specular_light.rgb); + specular_light.xyz = intensity * normalize(mix(specular_light.xyz, vec3 (0.45, 0.6, 0.8), 1.0 -smoothstep(0.1, 0.5,earthShade) )); + } + + // directional scattering for low sun + if (lightArg < 5.0) + //{mie_angle = (0.5 * dot(normalize(relPos), normalize(lightFull)) ) + 0.5;} + {mie_angle = (0.5 * dot(normalize(relPos), lightdir) ) + 0.5;} + else + {mie_angle = 1.0;} + + + + + +// 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) + {specular_light = vec3 (1.0, 1.0, 1.0);} + else + { + + lightArg = (terminator/100000.0 - 10.0)/20.0; + specular_light.b = 0.78 + lightArg * 0.21; + specular_light.g = 0.907 + lightArg * 0.091; + specular_light.r = 0.904 + lightArg * 0.092; + } + + specular_light = specular_light * scattering; + + yprime_alt = -sqrt(2.0 * EarthRadius * hazeLayerAltitude); + +} + + + +} diff --git a/gui/dialogs/local_weather_environment.xml b/gui/dialogs/local_weather_environment.xml new file mode 100644 index 000000000..4836a4456 --- /dev/null +++ b/gui/dialogs/local_weather_environment.xml @@ -0,0 +1,157 @@ + + + + + + local_weather_environment + 400 + 210 + false + + + 5 + 180 + + + + + + 5 + 150 + + + + + 120 + 150 + + + + + 190 + 150 + 90 + 20 + 0.0 + 7500.0 + /environment/mysnow-level-m + + dialog-apply + + + + + 290 + 150 + + + + + + 340 + 150 + + %.fm + true + /environment/mysnow-level-m + + + + + 5 + 120 + + + + + 120 + 120 + + + + + 190 + 120 + 90 + 20 + 0.0 + 0.7 + /environment/surface/dust-cover-factor + + dialog-apply + + + + + 290 + 120 + + + + + + 5 + 90 + + + + + 120 + 90 + + + + + 190 + 90 + 90 + 20 + 0.0 + 12.0 + /environment/fog-structure + + dialog-apply + + + + + 290 + 90 + + + + + + 10 + 10 + + + + + + + + + + diff --git a/gui/dialogs/local_weather_tiles.xml b/gui/dialogs/local_weather_tiles.xml index 9863855c4..a9c5bc0ef 100644 --- a/gui/dialogs/local_weather_tiles.xml +++ b/gui/dialogs/local_weather_tiles.xml @@ -6,20 +6,20 @@ local_weather_tiles 470 - 385 + 410 false 5 - 355 + 380 10 - 330 + 355 280 25 true @@ -53,7 +53,7 @@ 300 - 330 + 355 @@ -61,7 +61,7 @@ 390 - 330 + 355 50 25 /local-weather/tmp/tile-alt-offset-ft @@ -70,13 +70,13 @@ 5 - 295 + 320 67 - 295 + 320 40 25 /local-weather/tmp/tile-orientation-deg @@ -84,13 +84,13 @@ 105 - 295 + 320 125 - 295 + 320 30 25 /local-weather/tmp/windspeed-kt @@ -100,7 +100,7 @@ 157 - 295 + 320 @@ -108,7 +108,7 @@ 225 - 295 + 320 50 20 0.0 @@ -123,14 +123,14 @@ 275 - 295 + 320 333 - 295 + 320 50 20 0.0 @@ -143,14 +143,14 @@ 380 - 295 + 320 410 - 295 + 320 50 20 0.0 @@ -166,14 +166,14 @@ 5 - 265 + 290 150 - 265 + 290 140 25 true @@ -191,7 +191,7 @@ 300 - 265 + 290 @@ -199,7 +199,7 @@ 390 - 265 + 290 50 25 /local-weather/config/temperature-offset-degc @@ -208,13 +208,13 @@ 5 - 235 + 260 150 - 235 + 260 140 25 true @@ -231,7 +231,7 @@ 10 - 205 + 230 15 15 @@ -279,7 +279,7 @@ 150 - 205 + 230 15 15 @@ -291,7 +291,7 @@ 290 - 205 + 230 15 15 @@ -303,7 +303,7 @@ 10 - 180 + 205 15 15 @@ -315,7 +315,7 @@ 150 - 180 + 205 15 15 @@ -328,19 +328,19 @@ 5 - 150 + 175 160 - 150 + 175 230 - 150 + 175 90 20 0.3 @@ -353,26 +353,26 @@ 330 - 150 + 175 5 - 125 + 150 160 - 125 + 150 230 - 125 + 150 90 20 0.1 @@ -385,10 +385,41 @@ 330 - 125 + 150 + + 5 + 125 + + + + + 160 + 125 + + + + + 230 + 125 + 90 + 20 + 0.0 + 1.0 + /environment/air-pollution-norm + + dialog-apply + + + + + 330 + 125 + + + 5 @@ -527,7 +558,7 @@ + +