diff --git a/Compositor/HDR/env-capture-pass.xml b/Compositor/HDR/env-capture-pass.xml
index a661e8317..b8fa9ac3c 100644
--- a/Compositor/HDR/env-capture-pass.xml
+++ b/Compositor/HDR/env-capture-pass.xml
@@ -5,9 +5,17 @@
depth
hdr-envmap
depth
-
-
- 0x800
+
+ 0x1801
+
+ 12
+ transmittance
+
13
sky-view
diff --git a/Compositor/HDR/env-prefilter-pass.xml b/Compositor/HDR/env-prefilter-pass.xml
index f32ea3a35..ddecddf18 100644
--- a/Compositor/HDR/env-prefilter-pass.xml
+++ b/Compositor/HDR/env-prefilter-pass.xml
@@ -6,4 +6,7 @@
0
envmap
+
+ /sim/rendering/hdr/envmap/should-prefilter
+
diff --git a/Compositor/HDR/hdr.xml b/Compositor/HDR/hdr.xml
index 1be08eb40..64558e1ca 100644
--- a/Compositor/HDR/hdr.xml
+++ b/Compositor/HDR/hdr.xml
@@ -343,6 +343,9 @@
envmap
0
+
+ /sim/rendering/hdr/envmap/should-render-face-0
+
env-capture1
@@ -352,6 +355,9 @@
envmap
1
+
+ /sim/rendering/hdr/envmap/should-render-face-1
+
env-capture2
@@ -361,6 +367,9 @@
envmap
2
+
+ /sim/rendering/hdr/envmap/should-render-face-2
+
env-capture3
@@ -370,6 +379,9 @@
envmap
3
+
+ /sim/rendering/hdr/envmap/should-render-face-3
+
env-capture4
@@ -379,6 +391,9 @@
envmap
4
+
+ /sim/rendering/hdr/envmap/should-render-face-4
+
env-capture5
@@ -390,6 +405,9 @@
true
+
+ /sim/rendering/hdr/envmap/should-render-face-5
+
transmittance_tex
sampler-2d
diff --git a/Effects/HDR/water-shading.eff b/Effects/HDR/water-shading.eff
index 94659d378..e7dc3bf90 100644
--- a/Effects/HDR/water-shading.eff
+++ b/Effects/HDR/water-shading.eff
@@ -19,6 +19,7 @@
Shaders/HDR/math.glsl
Shaders/HDR/normal_encoding.glsl
Shaders/HDR/pos_from_depth.glsl
+ Shaders/HDR/sun.glsl
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/atmos_spectral.glsl
Shaders/HDR/exposure.glsl
@@ -50,6 +51,7 @@
sampler-2d
11
+
transmittance_tex
sampler-2d
diff --git a/Effects/cloud-impostor.eff b/Effects/cloud-impostor.eff
index 4b4ac6879..7859014b5 100644
--- a/Effects/cloud-impostor.eff
+++ b/Effects/cloud-impostor.eff
@@ -25,6 +25,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -263,9 +300,12 @@
transparent
Shaders/HDR/cloud_static.vert
+ Shaders/HDR/cloud_static_common.vert
+ Shaders/HDR/sun.glsl
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/atmos_spectral.glsl
Shaders/HDR/3dcloud.frag
+ Shaders/HDR/3dcloud_common.frag
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/exposure.glsl
@@ -280,6 +320,7 @@
sampler-2d
11
+
transmittance_tex
sampler-2d
@@ -298,4 +339,92 @@
+
+
+ hdr-envmap
+
+
+ false
+
+
+ 0
+ 2d
+
+ clamp-to-border
+ clamp-to-border
+
+ 1
+ transparent
+
+ Shaders/HDR/cloud_static_envmap.vert
+ Shaders/HDR/cloud_static_common.vert
+ Shaders/HDR/math.glsl
+ Shaders/HDR/sun.glsl
+ Shaders/HDR/aerial_perspective_envmap.glsl
+ Shaders/HDR/atmos.glsl
+ Shaders/HDR/atmos_spectral.glsl
+ Shaders/HDR/3dcloud_envmap.frag
+ Shaders/HDR/3dcloud_common.frag
+ Shaders/HDR/aerial_perspective_envmap.glsl
+
+
+ base_tex
+ sampler-2d
+ 0
+
+
+
+
+ transmittance_tex
+ sampler-2d
+ 12
+
+
+
+ aerosol_absorption_cross_section
+ float-vec4
+
+
+
+ aerosol_scattering_cross_section
+ float-vec4
+
+
+
+ aerosol_base_density
+ float
+
+
+
+ aerosol_relative_background_density
+ float
+
+
+
+ aerosol_scale_height
+ float
+
+
+
+ fog_density
+ float
+
+
+
+ fog_scale_height
+ float
+
+
+
+ ozone_mean_dobson
+ float
+
+
+
+ ground_albedo
+ float-vec4
+
+
+
+
diff --git a/Effects/cloud-noctilucent.eff b/Effects/cloud-noctilucent.eff
index 6ffc58b28..d25bdbdb7 100644
--- a/Effects/cloud-noctilucent.eff
+++ b/Effects/cloud-noctilucent.eff
@@ -12,6 +12,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -183,9 +220,12 @@
transparent
Shaders/HDR/cloud_static.vert
+ Shaders/HDR/cloud_static_common.vert
+ Shaders/HDR/sun.glsl
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/atmos_spectral.glsl
Shaders/HDR/3dcloud.frag
+ Shaders/HDR/3dcloud_common.frag
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/exposure.glsl
@@ -200,6 +240,7 @@
sampler-2d
11
+
transmittance_tex
sampler-2d
@@ -218,4 +259,92 @@
+
+
+ hdr-envmap
+
+
+ false
+
+
+ 0
+ 2d
+
+ clamp-to-border
+ clamp-to-border
+
+ 1
+ transparent
+
+ Shaders/HDR/cloud_static_envmap.vert
+ Shaders/HDR/cloud_static_common.vert
+ Shaders/HDR/math.glsl
+ Shaders/HDR/sun.glsl
+ Shaders/HDR/aerial_perspective_envmap.glsl
+ Shaders/HDR/atmos.glsl
+ Shaders/HDR/atmos_spectral.glsl
+ Shaders/HDR/3dcloud_envmap.frag
+ Shaders/HDR/3dcloud_common.frag
+ Shaders/HDR/aerial_perspective_envmap.glsl
+
+
+ base_tex
+ sampler-2d
+ 0
+
+
+
+
+ transmittance_tex
+ sampler-2d
+ 12
+
+
+
+ aerosol_absorption_cross_section
+ float-vec4
+
+
+
+ aerosol_scattering_cross_section
+ float-vec4
+
+
+
+ aerosol_base_density
+ float
+
+
+
+ aerosol_relative_background_density
+ float
+
+
+
+ aerosol_scale_height
+ float
+
+
+
+ fog_density
+ float
+
+
+
+ fog_scale_height
+ float
+
+
+
+ ozone_mean_dobson
+ float
+
+
+
+ ground_albedo
+ float-vec4
+
+
+
+
diff --git a/Effects/cloud-static.eff b/Effects/cloud-static.eff
index b34feceda..1daf465e2 100644
--- a/Effects/cloud-static.eff
+++ b/Effects/cloud-static.eff
@@ -24,6 +24,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -391,9 +428,12 @@
transparent
Shaders/HDR/cloud_static.vert
+ Shaders/HDR/cloud_static_common.vert
+ Shaders/HDR/sun.glsl
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/atmos_spectral.glsl
Shaders/HDR/3dcloud.frag
+ Shaders/HDR/3dcloud_common.frag
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/exposure.glsl
@@ -408,6 +448,7 @@
sampler-2d
11
+
transmittance_tex
sampler-2d
@@ -426,4 +467,92 @@
+
+
+ hdr-envmap
+
+
+ false
+
+
+ 0
+ 2d
+
+ clamp-to-border
+ clamp-to-border
+
+ 1
+ transparent
+
+ Shaders/HDR/cloud_static_envmap.vert
+ Shaders/HDR/cloud_static_common.vert
+ Shaders/HDR/math.glsl
+ Shaders/HDR/sun.glsl
+ Shaders/HDR/aerial_perspective_envmap.glsl
+ Shaders/HDR/atmos.glsl
+ Shaders/HDR/atmos_spectral.glsl
+ Shaders/HDR/3dcloud_envmap.frag
+ Shaders/HDR/3dcloud_common.frag
+ Shaders/HDR/aerial_perspective_envmap.glsl
+
+
+ base_tex
+ sampler-2d
+ 0
+
+
+
+
+ transmittance_tex
+ sampler-2d
+ 12
+
+
+
+ aerosol_absorption_cross_section
+ float-vec4
+
+
+
+ aerosol_scattering_cross_section
+ float-vec4
+
+
+
+ aerosol_base_density
+ float
+
+
+
+ aerosol_relative_background_density
+ float
+
+
+
+ aerosol_scale_height
+ float
+
+
+
+ fog_density
+ float
+
+
+
+ fog_scale_height
+ float
+
+
+
+ ozone_mean_dobson
+ float
+
+
+
+ ground_albedo
+ float-vec4
+
+
+
+
diff --git a/Effects/cloud.eff b/Effects/cloud.eff
index 0a0b8ae92..e91183bde 100644
--- a/Effects/cloud.eff
+++ b/Effects/cloud.eff
@@ -31,6 +31,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -504,9 +541,12 @@
transparent
Shaders/HDR/3dcloud.vert
+ Shaders/HDR/3dcloud_common.vert
+ Shaders/HDR/sun.glsl
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/atmos_spectral.glsl
Shaders/HDR/3dcloud.frag
+ Shaders/HDR/3dcloud_common.frag
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/exposure.glsl
@@ -539,6 +579,7 @@
sampler-2d
11
+
transmittance_tex
sampler-2d
@@ -557,4 +598,110 @@
+
+
+ hdr-envmap
+
+
+ false
+
+
+ 0
+ 2d
+
+ clamp-to-border
+ clamp-to-border
+
+ 1
+ transparent
+
+ Shaders/HDR/3dcloud_envmap.vert
+ Shaders/HDR/3dcloud_common.vert
+ Shaders/HDR/math.glsl
+ Shaders/HDR/sun.glsl
+ Shaders/HDR/aerial_perspective_envmap.glsl
+ Shaders/HDR/atmos.glsl
+ Shaders/HDR/atmos_spectral.glsl
+ Shaders/HDR/3dcloud_envmap.frag
+ Shaders/HDR/3dcloud_common.frag
+ Shaders/HDR/aerial_perspective_envmap.glsl
+
+ usrAttr1
+ 10
+
+
+ usrAttr2
+ 11
+
+
+
+ base_tex
+ sampler-2d
+ 0
+
+
+ range
+ float
+
+
+
+ detail_range
+ float
+
+
+
+
+
+ transmittance_tex
+ sampler-2d
+ 12
+
+
+
+ aerosol_absorption_cross_section
+ float-vec4
+
+
+
+ aerosol_scattering_cross_section
+ float-vec4
+
+
+
+ aerosol_base_density
+ float
+
+
+
+ aerosol_relative_background_density
+ float
+
+
+
+ aerosol_scale_height
+ float
+
+
+
+ fog_density
+ float
+
+
+
+ fog_scale_height
+ float
+
+
+
+ ozone_mean_dobson
+ float
+
+
+
+ ground_albedo
+ float-vec4
+
+
+
+
diff --git a/Effects/model-pbr-transparent.eff b/Effects/model-pbr-transparent.eff
index 3c4261ace..a07386c5a 100644
--- a/Effects/model-pbr-transparent.eff
+++ b/Effects/model-pbr-transparent.eff
@@ -102,6 +102,7 @@
Shaders/HDR/surface.glsl
Shaders/HDR/ibl.glsl
Shaders/HDR/shadows.glsl
+ Shaders/HDR/sun.glsl
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/atmos_spectral.glsl
Shaders/HDR/clustered.glsl
@@ -185,6 +186,7 @@
sampler-2d
11
+
transmittance_tex
sampler-2d
diff --git a/Effects/model-transparent.eff b/Effects/model-transparent.eff
index 6f716bed1..f1d0dafd4 100644
--- a/Effects/model-transparent.eff
+++ b/Effects/model-transparent.eff
@@ -106,6 +106,7 @@
Shaders/HDR/surface.glsl
Shaders/HDR/ibl.glsl
Shaders/HDR/shadows.glsl
+ Shaders/HDR/sun.glsl
Shaders/HDR/aerial_perspective.glsl
Shaders/HDR/atmos_spectral.glsl
Shaders/HDR/clustered.glsl
@@ -154,6 +155,7 @@
sampler-2d
11
+
transmittance_tex
sampler-2d
diff --git a/Effects/terrain-default.eff b/Effects/terrain-default.eff
index 2e341320a..d6874b926 100644
--- a/Effects/terrain-default.eff
+++ b/Effects/terrain-default.eff
@@ -189,6 +189,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1714,4 +1751,95 @@
+
+
+ hdr-envmap
+
+
+ 0
+
+
+
+
+
+
+ 0
+ opaque
+ back
+
+ Shaders/HDR/terrain_envmap.vert
+ Shaders/HDR/terrain_envmap.frag
+ Shaders/HDR/math.glsl
+ Shaders/HDR/color.glsl
+ Shaders/HDR/sun.glsl
+ Shaders/HDR/aerial_perspective_envmap.glsl
+ Shaders/HDR/atmos.glsl
+ Shaders/HDR/atmos_spectral.glsl
+
+
+ color_tex
+ sampler-2d
+ 0
+
+
+
+ orthophoto_tex
+ sampler-2d
+ 15
+
+
+
+
+ transmittance_tex
+ sampler-2d
+ 12
+
+
+
+ aerosol_absorption_cross_section
+ float-vec4
+
+
+
+ aerosol_scattering_cross_section
+ float-vec4
+
+
+
+ aerosol_base_density
+ float
+
+
+
+ aerosol_relative_background_density
+ float
+
+
+
+ aerosol_scale_height
+ float
+
+
+
+ fog_density
+ float
+
+
+
+ fog_scale_height
+ float
+
+
+
+ ozone_mean_dobson
+ float
+
+
+
+ ground_albedo
+ float-vec4
+
+
+
+
diff --git a/Nasal/hdr.nas b/Nasal/hdr.nas
index 5343e00ca..240f3f5f0 100644
--- a/Nasal/hdr.nas
+++ b/Nasal/hdr.nas
@@ -10,6 +10,9 @@
# by the shaders directly.
#-------------------------------------------------------------------------------
+################################################################################
+# Atmosphere
+################################################################################
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[0]", 2.8722e-24);
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[1]", 4.6168e-24);
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[2]", 7.9706e-24);
@@ -31,3 +34,63 @@ setprop("/sim/rendering/hdr/atmos/ground-albedo[0]", 0.4);
setprop("/sim/rendering/hdr/atmos/ground-albedo[1]", 0.4);
setprop("/sim/rendering/hdr/atmos/ground-albedo[2]", 0.4);
setprop("/sim/rendering/hdr/atmos/ground-albedo[3]", 0.4);
+
+################################################################################
+# Environment map
+################################################################################
+var is_envmap_updating = false;
+var current_envmap_face = 0;
+
+var update_envmap_face = func {
+ if (current_envmap_face < 6) {
+ # Render the current face
+ setprop("/sim/rendering/hdr/envmap/should-render-face-"
+ ~ current_envmap_face, true);
+ }
+ if (current_envmap_face > 0) {
+ # Stop rendering the previous face
+ setprop("/sim/rendering/hdr/envmap/should-render-face-"
+ ~ (current_envmap_face - 1), false);
+ }
+ if (current_envmap_face < 6) {
+ # Go to next face and update it next frame
+ current_envmap_face += 1;
+ settimer(update_envmap_face, 0);
+ } else {
+ # We have finished updating all faces, reset the face counter, end the
+ # update loop and prefilter the envmap.
+ current_envmap_face = 0;
+ setprop("/sim/rendering/hdr/envmap/should-prefilter", true);
+ settimer(func {
+ setprop("/sim/rendering/hdr/envmap/should-prefilter", false);
+ is_envmap_updating = false;
+ }, 0);
+ }
+}
+
+var update_envmap = func {
+ if (!is_envmap_updating) {
+ is_envmap_updating = true;
+ settimer(update_envmap_face, 0);
+ }
+}
+
+var update_envmap_periodically = func {
+ update_envmap();
+ var update_rate = getprop("/sim/rendering/hdr/envmap/update-rate-s");
+ settimer(update_envmap_periodically, update_rate);
+}
+
+# Start updating the envmap on FDM initialization
+setlistener("/sim/signals/fdm-initialized", func {
+ update_envmap_periodically();
+ # Do a single update after 5 seconds when most of the scenery is loaded
+ settimer(update_envmap, 5)
+});
+
+setlistener("/sim/rendering/hdr/envmap/force-update", func(p) {
+ if (p.getValue()) {
+ update_envmap();
+ p.setValue(false);
+ }
+}, 0, 0);
diff --git a/Shaders/HDR/3dcloud.frag b/Shaders/HDR/3dcloud.frag
index a25e76aa4..4c15ee3a1 100644
--- a/Shaders/HDR/3dcloud.frag
+++ b/Shaders/HDR/3dcloud.frag
@@ -2,70 +2,17 @@
layout(location = 0) out vec4 fragColor;
-in vec2 texcoord;
-in vec4 cloud_color;
-in vec4 ap_color;
-
-uniform sampler2D base_tex;
-
-uniform mat4 osg_ProjectionMatrix;
-uniform vec4 fg_Viewport;
-uniform vec3 fg_SunDirection;
-
-uniform float density = 30.0;
-uniform float max_sample_dist = 0.05;
-
-const int STEPS = 8;
-
-// aerial_perspective.glsl
-vec3 mix_aerial_perspective(vec3 color, vec4 ap);
+// 3dcloud_common.frag
+vec4 cloud_common_frag();
// exposure.glsl
vec3 apply_exposure(vec3 color);
void main()
{
- vec4 base = texture(base_tex, texcoord);
+ vec4 color = cloud_common_frag();
- // Directly discard fragments below a threshold
- if (base.a < 0.02)
- discard;
-
- // Pixel position in screen space [-1, 1]
- vec2 screen_uv = ((gl_FragCoord.xy - fg_Viewport.xy) / fg_Viewport.zw) * 2.0 - 1.0;
-
- // XXX: Sun's screen-space position. This should be passed as an uniform
- vec4 sun_dir_screen = osg_ProjectionMatrix * vec4(fg_SunDirection, 0.0);
- sun_dir_screen.xyz /= sun_dir_screen.w;
- sun_dir_screen.xyz = normalize(sun_dir_screen.xyz);
-
- // Direction from pixel to Sun in screen space
- vec2 sun_dir = screen_uv - sun_dir_screen.xy;
- // Flip the x axis
- sun_dir.x = -sun_dir.x;
-
- float dt = max_sample_dist / STEPS;
-
- // 2D ray march along the Sun's direction to estimate the transmittance
- float T = 1.0;
- for (int i = 0; i < STEPS; ++i) {
- float t = (float(i) + 0.5) * dt;
- vec2 uv_t = texcoord - sun_dir * t;
- vec4 texel = texture(base_tex, uv_t);
- // Beer-Lambert's law
- T *= exp(-texel.a * dt * density);
- }
-
- // When the camera is facing perpendicularly to the Sun, the Sun's
- // screen-space location can tend toward infinity. Fade the effect toward
- // the perpendicular.
- float fade = smoothstep(0.1, 0.5, dot(vec3(0.0, 0.0, -1.0), fg_SunDirection));
-
- vec4 color = base * cloud_color;
- color.rgb *= base.a * mix(0.5, T, fade);
-
- color.rgb = mix_aerial_perspective(color.rgb, ap_color);
-
- // Pre-expose
+ // Only pre-expose when not rendering to the environment map.
+ // We want the non-exposed radiance values for IBL.
color.rgb = apply_exposure(color.rgb);
fragColor = color;
diff --git a/Shaders/HDR/3dcloud.vert b/Shaders/HDR/3dcloud.vert
index 74a9bf22e..3921ddb53 100644
--- a/Shaders/HDR/3dcloud.vert
+++ b/Shaders/HDR/3dcloud.vert
@@ -1,116 +1,19 @@
#version 330 core
-layout(location = 0) in vec4 pos;
-layout(location = 2) in vec4 vertex_color;
-layout(location = 3) in vec4 multitexcoord0;
-layout(location = 10) in vec4 usrAttr1;
-layout(location = 11) in vec4 usrAttr2;
-
-out vec2 texcoord;
-out vec4 cloud_color;
out vec4 ap_color;
-uniform float range;
-uniform float detail_range;
-
-uniform mat4 osg_ModelViewMatrix;
-uniform mat4 osg_ModelViewProjectionMatrix;
-uniform mat4 osg_ViewMatrixInverse;
-uniform vec3 fg_SunDirectionWorld;
-
+// 3dcloud_common.vert
+void cloud_common_vert(out vec4 vs_pos, out vec4 ws_pos);
// aerial_perspective.glsl
vec4 get_aerial_perspective(vec2 coord, float depth);
-vec3 get_sun_radiance(vec3 p);
void main()
{
- float alpha_factor = usrAttr1.r;
- float shade_factor = usrAttr1.g;
- float cloud_height = usrAttr1.b;
- float bottom_factor = usrAttr2.r;
- float middle_factor = usrAttr2.g;
- float top_factor = usrAttr2.b;
+ vec4 vs_pos, ws_pos;
+ cloud_common_vert(vs_pos, ws_pos);
- texcoord = multitexcoord0.st;
-
- // XXX: Should be sent as an uniform
- mat4 inverseModelViewMatrix = inverse(osg_ModelViewMatrix);
-
- vec4 ep = inverseModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0);
- vec4 l = inverseModelViewMatrix * vec4(0.0, 0.0, 1.0, 1.0);
- vec3 u = normalize(ep.xyz - l.xyz);
-
- // Find a rotation matrix that rotates 1,0,0 into u. u, r and w are
- // the columns of that matrix.
- vec3 absu = abs(u);
- vec3 r = normalize(vec3(-u.y, u.x, 0.0));
- vec3 w = cross(u, r);
-
- // Do the matrix multiplication by [ u r w pos]. Assume no
- // scaling in the homogeneous component of pos.
- vec4 final_pos = vec4(0.0, 0.0, 0.0, 1.0);
- final_pos.xyz = pos.x * u;
- final_pos.xyz += pos.y * r;
- final_pos.xyz += pos.z * w;
- // Apply Z scaling to allow sprites to be squashed in the z-axis
- final_pos.z = final_pos.z * vertex_color.w;
-
- // Now shift the sprite to the correct position in the cloud.
- final_pos.xyz += vertex_color.xyz;
-
- // Determine the position - used for fog and shading calculations
- float fogCoord = length(vec3(osg_ModelViewMatrix * vec4(vertex_color.xyz, 1.0)));
- float center_dist = length(vec3(osg_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)));
-
- if ((fogCoord > detail_range) && (fogCoord > center_dist) && (shade_factor < 0.7)) {
- // More than detail_range away, so discard all sprites on opposite side of
- // cloud center by shifting them beyond the view fustrum
- gl_Position = vec4(0.0, 0.0, 10.0, 1.0);
- cloud_color = vec4(0.0);
- } else {
- gl_Position = osg_ModelViewProjectionMatrix * final_pos;
-
- vec4 final_view_pos = osg_ModelViewMatrix * final_pos;
- vec4 final_world_pos = osg_ViewMatrixInverse * final_view_pos;
-
- // Determine a lighting normal based on the vertex position from the
- // center of the cloud, so that sprite on the opposite side of the cloud
- // to the sun are darker.
- vec3 n = normalize(vec3(osg_ViewMatrixInverse *
- osg_ModelViewMatrix * vec4(-final_pos.xyz, 0.0)));
- float NdotL = dot(-fg_SunDirectionWorld, n);
-
- // Determine the shading of the vertex. We shade it based on it's position
- // in the cloud relative to the sun, and it's vertical position in the cloud.
- float shade = mix(shade_factor, top_factor, smoothstep(-0.3, 0.3, NdotL));
-
- if (final_pos.z < 0.5 * cloud_height) {
- shade = min(shade, mix(bottom_factor, middle_factor,
- final_pos.z * 2.0 / cloud_height));
- } else {
- shade = min(shade, mix(middle_factor, top_factor,
- final_pos.z * 2.0 / cloud_height - 1.0));
- }
-
- cloud_color.rgb = shade * get_sun_radiance(final_world_pos.xyz);
-
- // Perspective division and scale to [0, 1] to get the screen position
- // of the vertex.
- vec2 coord = (gl_Position.xy / gl_Position.w) * 0.5 + 0.5;
- ap_color = get_aerial_perspective(coord, length(final_view_pos));
-
- if ((fogCoord > (0.9 * detail_range))
- && (fogCoord > center_dist)
- && (shade_factor < 0.7)) {
- // cloudlet is almost at the detail range, so fade it out.
- cloud_color.a = 1.0 - smoothstep(0.9 * detail_range, detail_range, fogCoord);
- } else {
- // As we get within 100m of the sprite, it is faded out.
- // Equally at large distances it also fades out.
- cloud_color.a = min(smoothstep(10.0, 100.0, fogCoord),
- 1.0 - smoothstep(0.9 * range, range, fogCoord));
- }
-
- cloud_color.a *= alpha_factor;
- }
+ // Perspective division and scale to [0, 1] to get the screen position
+ // of the vertex.
+ vec2 coord = (gl_Position.xy / gl_Position.w) * 0.5 + 0.5;
+ ap_color = get_aerial_perspective(coord, length(vs_pos.xyz));
}
diff --git a/Shaders/HDR/3dcloud_common.frag b/Shaders/HDR/3dcloud_common.frag
new file mode 100644
index 000000000..9399c6ce5
--- /dev/null
+++ b/Shaders/HDR/3dcloud_common.frag
@@ -0,0 +1,65 @@
+#version 330 core
+
+in vec2 texcoord;
+in vec4 cloud_color;
+in vec4 ap_color;
+
+uniform sampler2D base_tex;
+
+uniform mat4 osg_ProjectionMatrix;
+uniform vec4 fg_Viewport;
+uniform vec3 fg_SunDirection;
+
+uniform float density = 30.0;
+uniform float max_sample_dist = 0.05;
+
+const int STEPS = 8;
+
+// aerial_perspective.glsl
+vec3 mix_aerial_perspective(vec3 color, vec4 ap);
+
+vec4 cloud_common_frag()
+{
+ vec4 base = texture(base_tex, texcoord);
+
+ // Directly discard fragments below a threshold
+ if (base.a < 0.02)
+ discard;
+
+ // Pixel position in screen space [-1, 1]
+ vec2 screen_uv = ((gl_FragCoord.xy - fg_Viewport.xy) / fg_Viewport.zw) * 2.0 - 1.0;
+
+ // XXX: Sun's screen-space position. This should be passed as an uniform
+ vec4 sun_dir_screen = osg_ProjectionMatrix * vec4(fg_SunDirection, 0.0);
+ sun_dir_screen.xyz /= sun_dir_screen.w;
+ sun_dir_screen.xyz = normalize(sun_dir_screen.xyz);
+
+ // Direction from pixel to Sun in screen space
+ vec2 sun_dir = screen_uv - sun_dir_screen.xy;
+ // Flip the x axis
+ sun_dir.x = -sun_dir.x;
+
+ float dt = max_sample_dist / STEPS;
+
+ // 2D ray march along the Sun's direction to estimate the transmittance
+ float T = 1.0;
+ for (int i = 0; i < STEPS; ++i) {
+ float t = (float(i) + 0.5) * dt;
+ vec2 uv_t = texcoord - sun_dir * t;
+ vec4 texel = texture(base_tex, uv_t);
+ // Beer-Lambert's law
+ T *= exp(-texel.a * dt * density);
+ }
+
+ // When the camera is facing perpendicularly to the Sun, the Sun's
+ // screen-space location can tend toward infinity. Fade the effect toward
+ // the perpendicular.
+ float fade = smoothstep(0.1, 0.5, dot(vec3(0.0, 0.0, -1.0), fg_SunDirection));
+
+ vec4 color = base * cloud_color;
+ color.rgb *= base.a * mix(0.5, T, fade);
+
+ color.rgb = mix_aerial_perspective(color.rgb, ap_color);
+
+ return color;
+}
diff --git a/Shaders/HDR/3dcloud_common.vert b/Shaders/HDR/3dcloud_common.vert
new file mode 100644
index 000000000..5c0539ff6
--- /dev/null
+++ b/Shaders/HDR/3dcloud_common.vert
@@ -0,0 +1,109 @@
+#version 330 core
+
+layout(location = 0) in vec4 pos;
+layout(location = 2) in vec4 vertex_color;
+layout(location = 3) in vec4 multitexcoord0;
+layout(location = 10) in vec4 usrAttr1;
+layout(location = 11) in vec4 usrAttr2;
+
+out vec2 texcoord;
+out vec4 cloud_color;
+
+uniform float range;
+uniform float detail_range;
+
+uniform mat4 osg_ModelViewMatrix;
+uniform mat4 osg_ModelViewProjectionMatrix;
+uniform mat4 osg_ViewMatrixInverse;
+uniform vec3 fg_SunDirectionWorld;
+
+// sun.glsl
+vec3 get_sun_radiance(vec3 p);
+
+void cloud_common_vert(out vec4 vs_pos, out vec4 ws_pos)
+{
+ float alpha_factor = usrAttr1.r;
+ float shade_factor = usrAttr1.g;
+ float cloud_height = usrAttr1.b;
+ float bottom_factor = usrAttr2.r;
+ float middle_factor = usrAttr2.g;
+ float top_factor = usrAttr2.b;
+
+ texcoord = multitexcoord0.st;
+
+ // XXX: Should be sent as an uniform
+ mat4 inverseModelViewMatrix = inverse(osg_ModelViewMatrix);
+
+ vec4 ep = inverseModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0);
+ vec4 l = inverseModelViewMatrix * vec4(0.0, 0.0, 1.0, 1.0);
+ vec3 u = normalize(ep.xyz - l.xyz);
+
+ // Find a rotation matrix that rotates 1,0,0 into u. u, r and w are
+ // the columns of that matrix.
+ vec3 absu = abs(u);
+ vec3 r = normalize(vec3(-u.y, u.x, 0.0));
+ vec3 w = cross(u, r);
+
+ // Do the matrix multiplication by [ u r w pos]. Assume no
+ // scaling in the homogeneous component of pos.
+ vec4 final_pos = vec4(0.0, 0.0, 0.0, 1.0);
+ final_pos.xyz = pos.x * u;
+ final_pos.xyz += pos.y * r;
+ final_pos.xyz += pos.z * w;
+ // Apply Z scaling to allow sprites to be squashed in the z-axis
+ final_pos.z = final_pos.z * vertex_color.w;
+
+ // Now shift the sprite to the correct position in the cloud.
+ final_pos.xyz += vertex_color.xyz;
+
+ // Determine the position - used for fog and shading calculations
+ float fogCoord = length(vec3(osg_ModelViewMatrix * vec4(vertex_color.xyz, 1.0)));
+ float center_dist = length(vec3(osg_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)));
+
+ if ((fogCoord > detail_range) && (fogCoord > center_dist) && (shade_factor < 0.7)) {
+ // More than detail_range away, so discard all sprites on opposite side of
+ // cloud center by shifting them beyond the view fustrum
+ gl_Position = vec4(0.0, 0.0, 10.0, 1.0);
+ cloud_color = vec4(0.0);
+ } else {
+ gl_Position = osg_ModelViewProjectionMatrix * final_pos;
+
+ vs_pos = osg_ModelViewMatrix * final_pos;
+ ws_pos = osg_ViewMatrixInverse * vs_pos;
+
+ // Determine a lighting normal based on the vertex position from the
+ // center of the cloud, so that sprite on the opposite side of the cloud
+ // to the sun are darker.
+ vec3 n = normalize(vec3(osg_ViewMatrixInverse *
+ osg_ModelViewMatrix * vec4(-final_pos.xyz, 0.0)));
+ float NdotL = dot(-fg_SunDirectionWorld, n);
+
+ // Determine the shading of the vertex. We shade it based on it's position
+ // in the cloud relative to the sun, and it's vertical position in the cloud.
+ float shade = mix(shade_factor, top_factor, smoothstep(-0.3, 0.3, NdotL));
+
+ if (final_pos.z < 0.5 * cloud_height) {
+ shade = min(shade, mix(bottom_factor, middle_factor,
+ final_pos.z * 2.0 / cloud_height));
+ } else {
+ shade = min(shade, mix(middle_factor, top_factor,
+ final_pos.z * 2.0 / cloud_height - 1.0));
+ }
+
+ cloud_color.rgb = shade * get_sun_radiance(ws_pos.xyz);
+
+ if ((fogCoord > (0.9 * detail_range))
+ && (fogCoord > center_dist)
+ && (shade_factor < 0.7)) {
+ // cloudlet is almost at the detail range, so fade it out.
+ cloud_color.a = 1.0 - smoothstep(0.9 * detail_range, detail_range, fogCoord);
+ } else {
+ // As we get within 100m of the sprite, it is faded out.
+ // Equally at large distances it also fades out.
+ cloud_color.a = min(smoothstep(10.0, 100.0, fogCoord),
+ 1.0 - smoothstep(0.9 * range, range, fogCoord));
+ }
+
+ cloud_color.a *= alpha_factor;
+ }
+}
diff --git a/Shaders/HDR/3dcloud_envmap.frag b/Shaders/HDR/3dcloud_envmap.frag
new file mode 100644
index 000000000..61ab4ff78
--- /dev/null
+++ b/Shaders/HDR/3dcloud_envmap.frag
@@ -0,0 +1,12 @@
+#version 330 core
+
+layout(location = 0) out vec4 fragColor;
+
+// 3dcloud_common.frag
+vec4 cloud_common_frag();
+
+void main()
+{
+ vec4 color = cloud_common_frag();
+ fragColor = color;
+}
diff --git a/Shaders/HDR/3dcloud_envmap.vert b/Shaders/HDR/3dcloud_envmap.vert
new file mode 100644
index 000000000..40e687afa
--- /dev/null
+++ b/Shaders/HDR/3dcloud_envmap.vert
@@ -0,0 +1,16 @@
+#version 330 core
+
+out vec4 ap_color;
+
+// 3dcloud_common.vert
+void cloud_common_vert(out vec4 vs_pos, out vec4 ws_pos);
+// aerial_perspective_envmap.glsl
+vec4 get_aerial_perspective(vec3 pos);
+
+void main()
+{
+ vec4 vs_pos, ws_pos;
+ cloud_common_vert(vs_pos, ws_pos);
+
+ ap_color = get_aerial_perspective(ws_pos.xyz);
+}
diff --git a/Shaders/HDR/aerial_perspective.glsl b/Shaders/HDR/aerial_perspective.glsl
index f9200f56f..bba108650 100644
--- a/Shaders/HDR/aerial_perspective.glsl
+++ b/Shaders/HDR/aerial_perspective.glsl
@@ -1,12 +1,6 @@
#version 330 core
uniform sampler2D aerial_perspective_tex;
-uniform sampler2D transmittance_tex;
-
-uniform vec3 fg_SunDirectionWorld;
-uniform float fg_CameraDistanceToEarthCenter;
-uniform float fg_SunZenithCosTheta;
-uniform float fg_EarthRadius;
const float AP_SLICE_COUNT = 32.0;
const float AP_MAX_DEPTH = 128000.0;
@@ -14,12 +8,6 @@ const float AP_SLICE_WIDTH_PIXELS = 32.0;
const float AP_SLICE_SIZE = 1.0 / AP_SLICE_COUNT;
const float AP_TEXEL_WIDTH = 1.0 / (AP_SLICE_COUNT * AP_SLICE_WIDTH_PIXELS);
-const float ATMOSPHERE_RADIUS = 6471e3;
-
-// atmos_spectral.glsl
-vec4 get_sun_spectral_irradiance();
-vec3 linear_srgb_from_spectral_samples(vec4 L);
-
vec4 sample_aerial_perspective_slice(sampler2D lut, vec2 coord, float slice)
{
// Sample at the pixel center
@@ -62,33 +50,3 @@ vec3 add_aerial_perspective(vec3 color, vec2 coord, float depth)
{
return mix_aerial_perspective(color, get_aerial_perspective(coord, depth));
}
-
-/*
- * Get the Sun radiance at a point 'p' in world space.
- * We cannot use the Sun extraterrestial irradiance directly because it will be
- * attenuated by the transmittance of the atmospheric medium.
- */
-vec3 get_sun_radiance(vec3 p)
-{
- float distance_to_earth_center = length(p);
- float normalized_altitude = (distance_to_earth_center - fg_EarthRadius)
- / (ATMOSPHERE_RADIUS - fg_EarthRadius);
-
- vec3 zenith_dir = p / distance_to_earth_center;
- float sun_cos_theta = dot(zenith_dir, fg_SunDirectionWorld);
-
- float u = sun_cos_theta * 0.5 + 0.5;
- float v = clamp(normalized_altitude, 0.0, 1.0);
- vec4 transmittance = texture(transmittance_tex, vec2(u, v));
-
- vec4 L = get_sun_spectral_irradiance() * transmittance;
- return linear_srgb_from_spectral_samples(L);
-}
-
-vec3 get_sun_radiance_sea_level()
-{
- vec2 uv = vec2(fg_SunZenithCosTheta * 0.5 + 0.5, 0.0);
- vec4 transmittance = texture(transmittance_tex, uv);
- vec4 L = get_sun_spectral_irradiance() * transmittance;
- return linear_srgb_from_spectral_samples(L);
-}
diff --git a/Shaders/HDR/aerial_perspective_envmap.glsl b/Shaders/HDR/aerial_perspective_envmap.glsl
new file mode 100644
index 000000000..be6e63f57
--- /dev/null
+++ b/Shaders/HDR/aerial_perspective_envmap.glsl
@@ -0,0 +1,60 @@
+#version 330 core
+
+uniform sampler2D transmittance_tex;
+
+uniform vec3 fg_CameraPositionCart;
+uniform vec3 fg_SunDirectionWorld;
+
+const int AERIAL_PERSPECTIVE_ENVMAP_STEPS = 4;
+
+// atmos.glsl
+float get_earth_radius();
+float get_ray_end(vec3 ray_origin, vec3 ray_dir, float t_max);
+vec4 compute_inscattering(in vec3 ray_origin,
+ in vec3 ray_dir,
+ in float t_max,
+ in vec3 sun_dir,
+ in int steps,
+ in sampler2D transmittance_lut,
+ out vec4 transmittance);
+// atmos_spectral.glsl
+vec4 get_sun_spectral_irradiance();
+vec3 linear_srgb_from_spectral_samples(vec4 L);
+
+vec4 get_aerial_perspective(vec3 pos)
+{
+ vec3 ray_origin = fg_CameraPositionCart;
+ vec3 ray_end = pos;
+
+ // Make sure both ray ends are above the ground.
+ // We also apply a small bias to the ray end to prevent both points from
+ // being at the exact same place due to floating point precision.
+ float radius = get_earth_radius();
+ ray_origin += max(0.0, radius - length(ray_origin));
+ ray_end += max(0.0, radius - length(ray_end)) + 1.0;
+
+ vec3 ray_dir = ray_end - ray_origin;
+ float t_d = length(ray_dir);
+ ray_dir /= t_d;
+
+ float t_max = get_ray_end(ray_origin, ray_dir, t_d);
+
+ vec4 transmittance;
+ vec4 L = compute_inscattering(ray_origin,
+ ray_dir,
+ t_max,
+ fg_SunDirectionWorld,
+ AERIAL_PERSPECTIVE_ENVMAP_STEPS,
+ transmittance_tex,
+ transmittance);
+
+ vec4 ap;
+ ap.rgb = linear_srgb_from_spectral_samples(L * get_sun_spectral_irradiance());
+ ap.a = dot(transmittance, vec4(0.25));
+ return ap;
+}
+
+vec3 mix_aerial_perspective(vec3 color, vec4 ap)
+{
+ return color * ap.a + ap.rgb;
+}
diff --git a/Shaders/HDR/atmos.glsl b/Shaders/HDR/atmos.glsl
index c1edb0ecf..a32f7064c 100644
--- a/Shaders/HDR/atmos.glsl
+++ b/Shaders/HDR/atmos.glsl
@@ -203,8 +203,8 @@ void get_atmosphere_collision_coefficients(in float h,
out vec4 molecular_scattering,
out vec4 extinction)
{
+ h = max(h, 1e-3); // In case height is negative
h *= 1e-3; // To km
- h = max(h, 0.0); // In case height is negative
// Molecules
molecular_absorption = get_molecular_absorption_coefficient(h);
diff --git a/Shaders/HDR/cloud_static.vert b/Shaders/HDR/cloud_static.vert
index c774995dd..dd7af6a8d 100644
--- a/Shaders/HDR/cloud_static.vert
+++ b/Shaders/HDR/cloud_static.vert
@@ -1,74 +1,19 @@
#version 330 core
-layout(location = 0) in vec4 pos;
-layout(location = 2) in vec4 vertex_color;
-layout(location = 3) in vec4 multitexcoord0;
-
-out vec2 texcoord;
-out vec4 cloud_color;
out vec4 ap_color;
-uniform mat4 osg_ModelViewMatrix;
-uniform mat4 osg_ModelViewProjectionMatrix;
-uniform mat4 osg_ViewMatrixInverse;
-uniform vec3 fg_SunDirectionWorld;
-
-const float shade = 0.8;
-const float cloud_height = 1000.0;
-
+// cloud_static_common.vert
+void cloud_static_common_vert(out vec4 vs_pos, out vec4 ws_pos);
// aerial_perspective.glsl
vec4 get_aerial_perspective(vec2 coord, float depth);
-vec3 get_sun_radiance(vec3 p);
void main()
{
- texcoord = multitexcoord0.st;
-
- // XXX: Should be sent as an uniform
- mat4 inverseModelViewMatrix = inverse(osg_ModelViewMatrix);
-
- vec4 ep = inverseModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0);
- vec4 l = inverseModelViewMatrix * vec4(0.0, 0.0, 1.0, 1.0);
- vec3 u = normalize(ep.xyz - l.xyz);
-
- vec4 final_pos = vec4(0.0, 0.0, 0.0, 1.0);
- final_pos.x = pos.x;
- final_pos.y = pos.y;
- final_pos.z = pos.z;
- final_pos.xyz += vertex_color.xyz;
-
- gl_Position = osg_ModelViewProjectionMatrix * final_pos;
-
- // Determine a lighting normal based on the vertex position from the
- // center of the cloud, so that sprite on the opposite side of the cloud
- // to the sun are darker.
- vec3 n = normalize(vec3(osg_ViewMatrixInverse *
- osg_ModelViewMatrix * vec4(-final_pos.xyz, 0.0)));
- float NdotL = dot(-fg_SunDirectionWorld, n);
-
- vec4 final_view_pos = osg_ModelViewMatrix * final_pos;
- vec4 final_world_pos = osg_ViewMatrixInverse * final_view_pos;
-
- float fogCoord = abs(final_view_pos.z);
- float fract = smoothstep(0.0, cloud_height, final_pos.z + cloud_height);
-
- vec3 sun_radiance = get_sun_radiance(final_world_pos.xyz);
-
- // Determine the shading of the sprite based on its vertical position and
- // position relative to the sun.
- NdotL = min(smoothstep(-0.5, 0.0, NdotL), fract);
- // Determine the shading based on a mixture from the backlight to the front
- vec3 backlight = shade * sun_radiance;
-
- cloud_color.rgb = mix(backlight, sun_radiance, NdotL);
+ vec4 vs_pos, ws_pos;
+ cloud_static_common_vert(vs_pos, ws_pos);
// Perspective division and scale to [0, 1] to get the screen position
// of the vertex.
vec2 coord = (gl_Position.xy / gl_Position.w) * 0.5 + 0.5;
- ap_color = get_aerial_perspective(coord, length(final_view_pos));
-
- // As we get within 100m of the sprite, it is faded out. Equally at large
- // distances it also fades out.
- cloud_color.a = min(smoothstep(100.0, 250.0, fogCoord),
- 1.0 - smoothstep(70000.0, 75000.0, fogCoord));
+ ap_color = get_aerial_perspective(coord, length(vs_pos));
}
diff --git a/Shaders/HDR/cloud_static_common.vert b/Shaders/HDR/cloud_static_common.vert
new file mode 100644
index 000000000..b57bbd115
--- /dev/null
+++ b/Shaders/HDR/cloud_static_common.vert
@@ -0,0 +1,67 @@
+#version 330 core
+
+layout(location = 0) in vec4 pos;
+layout(location = 2) in vec4 vertex_color;
+layout(location = 3) in vec4 multitexcoord0;
+
+out vec2 texcoord;
+out vec4 cloud_color;
+
+uniform mat4 osg_ModelViewMatrix;
+uniform mat4 osg_ModelViewProjectionMatrix;
+uniform mat4 osg_ViewMatrixInverse;
+uniform vec3 fg_SunDirectionWorld;
+
+const float shade = 0.8;
+const float cloud_height = 1000.0;
+
+// sun.glsl
+vec3 get_sun_radiance(vec3 p);
+
+void cloud_static_common_vert(out vec4 vs_pos, out vec4 ws_pos)
+{
+ texcoord = multitexcoord0.st;
+
+ // XXX: Should be sent as an uniform
+ mat4 inverseModelViewMatrix = inverse(osg_ModelViewMatrix);
+
+ vec4 ep = inverseModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0);
+ vec4 l = inverseModelViewMatrix * vec4(0.0, 0.0, 1.0, 1.0);
+ vec3 u = normalize(ep.xyz - l.xyz);
+
+ vec4 final_pos = vec4(0.0, 0.0, 0.0, 1.0);
+ final_pos.x = pos.x;
+ final_pos.y = pos.y;
+ final_pos.z = pos.z;
+ final_pos.xyz += vertex_color.xyz;
+
+ gl_Position = osg_ModelViewProjectionMatrix * final_pos;
+
+ // Determine a lighting normal based on the vertex position from the
+ // center of the cloud, so that sprite on the opposite side of the cloud
+ // to the sun are darker.
+ vec3 n = normalize(vec3(osg_ViewMatrixInverse *
+ osg_ModelViewMatrix * vec4(-final_pos.xyz, 0.0)));
+ float NdotL = dot(-fg_SunDirectionWorld, n);
+
+ vs_pos = osg_ModelViewMatrix * final_pos;
+ ws_pos = osg_ViewMatrixInverse * vs_pos;
+
+ float fogCoord = abs(vs_pos.z);
+ float fract = smoothstep(0.0, cloud_height, final_pos.z + cloud_height);
+
+ vec3 sun_radiance = get_sun_radiance(ws_pos.xyz);
+
+ // Determine the shading of the sprite based on its vertical position and
+ // position relative to the sun.
+ NdotL = min(smoothstep(-0.5, 0.0, NdotL), fract);
+ // Determine the shading based on a mixture from the backlight to the front
+ vec3 backlight = shade * sun_radiance;
+
+ cloud_color.rgb = mix(backlight, sun_radiance, NdotL);
+
+ // As we get within 100m of the sprite, it is faded out. Equally at large
+ // distances it also fades out.
+ cloud_color.a = min(smoothstep(100.0, 250.0, fogCoord),
+ 1.0 - smoothstep(70000.0, 75000.0, fogCoord));
+}
diff --git a/Shaders/HDR/cloud_static_envmap.vert b/Shaders/HDR/cloud_static_envmap.vert
new file mode 100644
index 000000000..d42357412
--- /dev/null
+++ b/Shaders/HDR/cloud_static_envmap.vert
@@ -0,0 +1,16 @@
+#version 330 core
+
+out vec4 ap_color;
+
+// cloud_static_common.vert
+void cloud_static_common_vert(out vec4 vs_pos, out vec4 ws_pos);
+// aerial_perspective_envmap.glsl
+vec4 get_aerial_perspective(vec3 pos);
+
+void main()
+{
+ vec4 vs_pos, ws_pos;
+ cloud_static_common_vert(vs_pos, ws_pos);
+
+ ap_color = get_aerial_perspective(ws_pos.xyz);
+}
diff --git a/Shaders/HDR/sun.glsl b/Shaders/HDR/sun.glsl
new file mode 100644
index 000000000..8ce653ab2
--- /dev/null
+++ b/Shaders/HDR/sun.glsl
@@ -0,0 +1,44 @@
+#version 330 core
+
+uniform sampler2D transmittance_tex;
+
+uniform float fg_EarthRadius;
+uniform vec3 fg_SunDirectionWorld;
+uniform float fg_CameraDistanceToEarthCenter;
+uniform float fg_SunZenithCosTheta;
+
+const float ATMOSPHERE_RADIUS = 6471e3;
+
+// atmos_spectral.glsl
+vec4 get_sun_spectral_irradiance();
+vec3 linear_srgb_from_spectral_samples(vec4 L);
+
+/*
+ * Get the Sun radiance at a point 'p' in world space.
+ * We cannot use the Sun extraterrestial irradiance directly because it will be
+ * attenuated by the transmittance of the atmospheric medium.
+ */
+vec3 get_sun_radiance(vec3 p)
+{
+ float distance_to_earth_center = length(p);
+ float normalized_altitude = (distance_to_earth_center - fg_EarthRadius)
+ / (ATMOSPHERE_RADIUS - fg_EarthRadius);
+
+ vec3 zenith_dir = p / distance_to_earth_center;
+ float sun_cos_theta = dot(zenith_dir, fg_SunDirectionWorld);
+
+ float u = sun_cos_theta * 0.5 + 0.5;
+ float v = clamp(normalized_altitude, 0.0, 1.0);
+ vec4 transmittance = texture(transmittance_tex, vec2(u, v));
+
+ vec4 L = get_sun_spectral_irradiance() * transmittance;
+ return linear_srgb_from_spectral_samples(L);
+}
+
+vec3 get_sun_radiance_sea_level()
+{
+ vec2 uv = vec2(fg_SunZenithCosTheta * 0.5 + 0.5, 0.0);
+ vec4 transmittance = texture(transmittance_tex, uv);
+ vec4 L = get_sun_spectral_irradiance() * transmittance;
+ return linear_srgb_from_spectral_samples(L);
+}
diff --git a/Shaders/HDR/terrain_envmap.frag b/Shaders/HDR/terrain_envmap.frag
new file mode 100644
index 000000000..94e4fec42
--- /dev/null
+++ b/Shaders/HDR/terrain_envmap.frag
@@ -0,0 +1,52 @@
+#version 330 core
+
+layout(location = 0) out vec4 fragColor;
+
+in VS_OUT {
+ vec2 texcoord;
+ vec2 orthophoto_texcoord;
+ vec3 vertex_normal;
+ vec3 world_vector;
+} fs_in;
+
+uniform sampler2D color_tex;
+uniform sampler2D orthophoto_tex;
+
+uniform bool orthophotoAvailable;
+uniform vec3 fg_SunDirectionWorld;
+uniform vec4 fg_Viewport;
+
+// math.glsl
+float M_1_PI();
+// color.glsl
+vec3 eotf_inverse_sRGB(vec3 srgb);
+// sun.glsl
+vec3 get_sun_radiance_sea_level();
+// aerial_perspective_envmap.glsl
+vec4 get_aerial_perspective(vec3 pos);
+vec3 mix_aerial_perspective(vec3 color, vec4 ap);
+
+void main()
+{
+ vec3 texel = texture(color_tex, fs_in.texcoord).rgb;
+ if (orthophotoAvailable) {
+ vec4 sat_texel = texture(orthophoto_tex, fs_in.orthophoto_texcoord);
+ if (sat_texel.a > 0.0) {
+ texel.rgb = sat_texel.rgb;
+ }
+ }
+
+ vec3 color = eotf_inverse_sRGB(texel);
+ vec3 sun_radiance = get_sun_radiance_sea_level();
+
+ vec3 N = normalize(fs_in.vertex_normal);
+ float NdotL = max(dot(N, fg_SunDirectionWorld), 1e-4);
+
+ // Assume a perfectly diffuse Lambertian surface
+ color = M_1_PI() * color * sun_radiance * NdotL;
+
+ vec4 ap = get_aerial_perspective(fs_in.world_vector);
+ color = mix_aerial_perspective(color, ap);
+
+ fragColor = vec4(color, 1.0);
+}
diff --git a/Shaders/HDR/terrain_envmap.vert b/Shaders/HDR/terrain_envmap.vert
new file mode 100644
index 000000000..47e7a764b
--- /dev/null
+++ b/Shaders/HDR/terrain_envmap.vert
@@ -0,0 +1,28 @@
+#version 330 core
+
+layout(location = 0) in vec4 pos;
+layout(location = 1) in vec3 normal;
+layout(location = 3) in vec4 multitexcoord0;
+layout(location = 5) in vec4 multitexcoord2;
+
+out VS_OUT {
+ vec2 texcoord;
+ vec2 orthophoto_texcoord;
+ vec3 vertex_normal;
+ vec3 world_vector;
+} vs_out;
+
+uniform mat4 osg_ModelViewMatrix;
+uniform mat4 osg_ModelViewProjectionMatrix;
+uniform mat3 osg_NormalMatrix;
+uniform mat4 osg_ViewMatrixInverse;
+
+void main()
+{
+ gl_Position = osg_ModelViewProjectionMatrix * pos;
+ vs_out.texcoord = multitexcoord0.st;
+ vs_out.orthophoto_texcoord = multitexcoord2.st;
+ vs_out.vertex_normal = (osg_ViewMatrixInverse
+ * vec4(osg_NormalMatrix * normal, 0.0)).xyz;
+ vs_out.world_vector = (osg_ViewMatrixInverse * osg_ModelViewMatrix * pos).xyz;
+}
diff --git a/defaults.xml b/defaults.xml
index bb1371f12..cc1b7352b 100644
--- a/defaults.xml
+++ b/defaults.xml
@@ -535,6 +535,17 @@ Started September 2000 by David Megginson, david@megginson.com
2
0.0
+
+ false
+ 90.0
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+
0.01
0.005