1
0
Fork 0

WS30: Separate out haze calculations

Previously haze calculations were performed
in the main body of the ws30 shaders (inherited
from the ALS terrain shaders).  This change creates
a common applyHaze function to consistently apply haze.

This is not ws30 specific, and could be used to replace the
haze calculations of all ALS shaders for improved consistency.
This commit is contained in:
Stuart Buchanan 2022-01-18 21:13:29 +00:00
parent d8110f0b38
commit 4564b30eac
7 changed files with 299 additions and 620 deletions

View file

@ -167,6 +167,11 @@
<fragment-shader>Shaders/shadows-include.frag</fragment-shader>
<fragment-shader>Shaders/clustered-include.frag</fragment-shader>
</program>
<uniform>
<name>quality_level</name>
<type>int</type>
<value><use>quality_level</use></value>
</uniform>
<uniform>
<name>grain_strength</name>
<type>float</type>

View file

@ -297,6 +297,11 @@
<fragment-shader>Shaders/shadows-include.frag</fragment-shader>
<fragment-shader>Shaders/clustered-include.frag</fragment-shader>
</program>
<uniform>
<name>quality_level</name>
<type>int</type>
<value><use>quality_level</use></value>
</uniform>
<uniform>
<name>visibility</name>
<type>float</type>
@ -1192,6 +1197,16 @@
<fragment-shader>Shaders/shadows-include.frag</fragment-shader>
<fragment-shader>Shaders/clustered-include.frag</fragment-shader>
</program>
<uniform>
<name>tquality_level</name>
<type>int</type>
<value><use>tquality_level</use></value>
</uniform>
<uniform>
<name>cloud_self_shading</name>
<type>float</type>
<value><use>cloud_self_shading</use></value>
</uniform>
<uniform>
<name>visibility</name>
<type>float</type>

View file

@ -2,102 +2,260 @@
#version 120
uniform float air_pollution;
uniform int quality_level;
uniform float fogstructure;
uniform float cloud_self_shading;
uniform float scattering;
uniform float terminator;
uniform float terrain_alt;
uniform float overcast;
uniform float eye_alt;
// standard ALS fog function with exp(-d/D) fading and cutoff at low altitude and exp(-d^2/D^2) at high altitude
const float terminator_width = 200000.0;
const float EarthRadius = 5800000.0;
varying vec3 relPos;
varying vec4 light_diffuse_comp;
varying vec3 normal;
varying vec3 worldPos;
float Noise2D(in vec2 coord, in float wavelength);
vec3 filter_combined (in vec3 color) ;
float Noise3D(in vec3 coord, in float wavelength);
const float AtmosphericScaleHeight = 8500.0;
// Development tools:
// Reduce haze to almost zero, while preserving lighting. Useful for observing distant tiles.
// Keeps the calculation overhead. This can be used for profiling.
// Possible values: 0:Normal, 1:Reduced haze.
const int reduce_haze_without_removing_calculation_overhead = 0;
// standard ALS fog function with exp(-d/D) fading and cutoff at low altitude and exp(-d^2/D^2) at high altitude
float fog_func (in float targ, in float alt)
{
float fade_mix;
targ = 1.25 * targ * smoothstep(0.04,0.06,targ); // need to sync with the distance to which terrain is drawn
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 * smoothstep(0.04,0.06,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));
}
// for large altitude > 30 km, we switch to some component of quadratic distance fading to
// create the illusion of improved visibility range
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));
}
}
// altitude correction for exponential drop in atmosphere density
float alt_factor(in float eye_alt, in float vertex_alt)
{
float h0 = AtmosphericScaleHeight;
float h1 = min(eye_alt,vertex_alt);
float h2 = max(eye_alt,vertex_alt);
float h0 = AtmosphericScaleHeight;
float h1 = min(eye_alt,vertex_alt);
float h2 = max(eye_alt,vertex_alt);
if ((h2-h1) < 200.0) // use a Taylor-expanded version
{
return 0.5 * (exp(-h2/h0) + exp(-h1/h0));
}
else
{
return h0/(h2-h1) * (exp(-h1/h0) - exp(-h2/h0));
}
if ((h2-h1) < 200.0) // use a Taylor-expanded version
{
return 0.5 * (exp(-h2/h0) + exp(-h1/h0));
} else {
return h0/(h2-h1) * (exp(-h1/h0) - exp(-h2/h0));
}
}
// Rayleigh in-scatter function
float rayleigh_in_func(in float dist, in float air_pollution, in float avisibility, in float eye_alt, in float vertex_alt)
{
float fade_length = avisibility * (2.5 - 2.2 * sqrt(air_pollution));
fade_length = fade_length / alt_factor(eye_alt, vertex_alt);
return 1.0-exp(-dist/max(15000.0,fade_length));
float fade_length = avisibility * (2.5 - 2.2 * sqrt(air_pollution));
fade_length = fade_length / alt_factor(eye_alt, vertex_alt);
return 1.0-exp(-dist/max(15000.0,fade_length));
}
// Rayleigh out-scattering color shift
vec3 rayleigh_out_shift(in vec3 color, in float outscatter)
{
color.r = color.r * (1.0 - 0.4 * outscatter);
color.g = color.g * (1.0 - 0.8 * outscatter);
color.b = color.b * (1.0 - 1.6 * outscatter);
return color;
color.r = color.r * (1.0 - 0.4 * outscatter);
color.g = color.g * (1.0 - 0.8 * outscatter);
color.b = color.b * (1.0 - 1.6 * outscatter);
return color;
}
// the generalized logistic function used to compute lightcurves
float light_curve (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));
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));
}
// the haze color function
vec3 get_hazeColor(in float lightArg)
{
vec3 hazeColor;
hazeColor.r = light_curve(lightArg, 8.305e-06, 0.161, 4.827-3.0 *air_pollution, 3.04e-05, 1.0);
hazeColor.g = light_curve(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0);
hazeColor.b = light_curve(lightArg, 1.330e-05, 0.264, 1.527+ 2.0*air_pollution, 1.08e-05, 1.0);
return hazeColor;
vec3 hazeColor;
hazeColor.r = light_curve(lightArg, 8.305e-06, 0.161, 4.827-3.0 *air_pollution, 3.04e-05, 1.0);
hazeColor.g = light_curve(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0);
hazeColor.b = light_curve(lightArg, 1.330e-05, 0.264, 1.527+ 2.0*air_pollution, 1.08e-05, 1.0);
return hazeColor;
}
// Apply the ALS haze model to a given fragment
vec4 applyHaze(inout vec4 fragColor,
inout vec3 hazeColor,
in vec3 secondary_light,
in float ct,
in float hazeLayerAltitude,
in float visibility,
in float avisibility,
in float dist,
in float lightArg,
in float mie_angle)
{
float mvisibility = min(visibility,avisibility);
if (dist > 0.04 * mvisibility)
{
float transmission;
float vAltitude;
float delta_zv;
float H;
float distance_in_layer;
float transmission_arg;
float intensity;
float eShade;
float delta_z = hazeLayerAltitude - eye_alt;
float effective_scattering = min(scattering, cloud_self_shading);
float yprime_alt = light_diffuse_comp.a;
vec3 shadedFogColor = vec3(0.55, 0.67, 0.88);
vec3 lightDir = gl_LightSource[0].position.xyz;
vec3 n = normal;
n = normalize(n);
// 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,mvisibility) * 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;
}
}
if ((quality_level > 4) && (abs(delta_z) < 400.0)) {
float blur_thickness = 50.0;
float cphi = dot(vec3(0.0, 1.0, 0.0), relPos)/dist;
float ctlayer = delta_z/dist-0.01 + 0.02 * Noise2D(vec2(cphi,1.0),0.1) -0.01;
float ctblur = 0.035 ;
float blur_dist;
blur_dist = dist * (1.0-smoothstep(0.0,300.0,-delta_z)) * smoothstep(-400.0,-200.0, -delta_z);
blur_dist = blur_dist * smoothstep(ctlayer-4.0*ctblur, ctlayer-ctblur, ct) * (1.0-smoothstep(ctlayer+0.5*ctblur, ctlayer+ctblur, ct));
distance_in_layer = max(distance_in_layer, blur_dist);
}
// 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 (quality_level > 3) {
float noise_1500m = Noise3D(worldPos.xyz, 1500.0);
float noise_2000m = Noise3D(worldPos.xyz, 2000.0);
transmission_arg = transmission_arg + (distance_in_layer/(1.0 * mvisibility + 1.0 * mvisibility * fogstructure * 0.06 * (noise_1500m + noise_2000m -1.0) ));
} else {
transmission_arg = transmission_arg + (distance_in_layer/mvisibility);
}
// this combines the Weber-Fechner intensity
eqColorFactor = 1.0 - 0.1 * delta_zv/mvisibility - (1.0 - effective_scattering);
transmission = fog_func(transmission_arg, eye_alt);
// there's always residual intensity, we should never be driven to zero
if (eqColorFactor < 0.2) eqColorFactor = 0.2;
// now dim the light for haze
eShade = 1.0 - 0.9 * smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt);
// Mie-like factor
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)) );
}
intensity = length(hazeColor);
if (intensity > 0.0) // this needs to be a condition, because otherwise hazeColor doesn't come out correctly
{
// high altitude desaturation of the haze color
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* shadedFogColor, 1.0 -smoothstep(0.25, fade_out,eShade) ));
// change haze color to blue hue for strong fogging
hazeColor = intensity * normalize(mix(hazeColor, shadedFogColor, (1.0-smoothstep(0.5,0.9,eqColorFactor))));
// reduce haze intensity when looking at shaded surfaces, only in terminator region
float shadow = mix( min(1.0 + dot(n,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));
}
// don't let the light fade out too rapidly
lightArg = (terminator + 200000.0)/100000.0;
float minLightIntensity = min(0.2,0.16 * lightArg + 0.5);
vec3 minLight = minLightIntensity * vec3 (0.2, 0.3, 0.4);
hazeColor.rgb *= eqColorFactor * eShade;
hazeColor.rgb = max(hazeColor.rgb, minLight.rgb);
// Testing phase controls
if (reduce_haze_without_removing_calculation_overhead == 1)
{
transmission = 1.0 - (transmission/1000000.0);
}
// finally, mix fog in
if (quality_level > 4) {
float backscatter = 0.5* min(1.0,10000.0/(mvisibility*mvisibility));
fragColor.rgb = mix(hazeColor+secondary_light * backscatter , fragColor.rgb,transmission);
} else {
fragColor.rgb = mix(clamp(hazeColor,0.0,1.0) , clamp(fragColor.rgb,0.0,1.0),transmission);
}
} // end if (dist > 0.04 * mvisibility)
fragColor.rgb = filter_combined(fragColor.rgb);
return fragColor;
}

View file

@ -197,6 +197,18 @@ void get_material(in int landclass,
out vec2 st
);
// Apply the ALS haze model to a specific fragment
vec4 applyHaze(inout vec4 fragColor,
inout vec3 hazeColor,
in vec3 secondary_light,
in float ct,
in float hazeLayerAltitude,
in float visibility,
in float avisibility,
in float dist,
in float lightArg,
in float mie_angle);
// End Test-phase code
@ -555,185 +567,12 @@ if ((dist < 5000.0)&& (quality_level > 3) && (wetness>0.0))
// is closer to what the OpenGL fixed function pipeline does.
color = clamp(color, 0.0, 1.0);
fragColor = color * texel + specular;
fragColor.rgb += getClusteredLightsContribution(eyePos.xyz, n, texel.rgb);
// here comes the terrain haze model
float delta_z = hazeLayerAltitude - eye_alt;
if (dist > 0.04 * min(visibility,avisibility))
//if ((gl_FragCoord.y > ylimit) || (gl_FragCoord.x < zlimit1) || (gl_FragCoord.x > zlimit2))
//if (dist > 40.0)
{
alt = eye_alt;
float transmission;
float vAltitude;
float delta_zv;
float H;
float distance_in_layer;
float transmission_arg;
// 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;
if (visibility < avisibility)
{
if (quality_level > 3)
{
transmission_arg = transmission_arg + (distance_in_layer/(1.0 * visibility + 1.0 * visibility * fogstructure * 0.06 * (noise_1500m + noise_2000m -1.0) ));
}
else
{
transmission_arg = transmission_arg + (distance_in_layer/visibility);
}
// this combines the Weber-Fechner intensity
eqColorFactor = 1.0 - 0.1 * delta_zv/visibility - (1.0 - effective_scattering);
}
else
{
if (quality_level > 3)
{
transmission_arg = transmission_arg + (distance_in_layer/(1.0 * avisibility + 1.0 * avisibility * fogstructure * 0.06 * (noise_1500m + noise_2000m - 1.0) ));
}
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 - effective_scattering);
}
transmission = fog_func(transmission_arg, alt);
// 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 = get_hazeColor(lightArg);
// now dim the light for haze
eShade = 1.0 - 0.9 * smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt);
// Mie-like factor
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)) );
}
intensity = length(hazeColor);
if (intensity > 0.0) // this needs to be a condition, because otherwise hazeColor doesn't come out correctly
{
// high altitude desaturation of the haze color
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* shadedFogColor, 1.0 -smoothstep(0.25, fade_out,eShade) ));
// change haze color to blue hue for strong fogging
hazeColor = intensity * normalize(mix(hazeColor, shadedFogColor, (1.0-smoothstep(0.5,0.9,eqColorFactor))));
// reduce haze intensity when looking at shaded surfaces, only in terminator region
float shadow = mix( min(1.0 + dot(n,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));
// don't let the light fade out too rapidly
lightArg = (terminator + 200000.0)/100000.0;
float minLightIntensity = min(0.2,0.16 * lightArg + 0.5);
vec3 minLight = minLightIntensity * vec3 (0.2, 0.3, 0.4);
hazeColor *= eqColorFactor * eShade;
hazeColor.rgb = max(hazeColor.rgb, minLight.rgb);
}
// Testing phase controls
if (reduce_haze_without_removing_calculation_overhead == 1)
{
transmission = 1.0 - (transmission/1000000.0);
}
fragColor.rgb = mix(clamp(hazeColor,0.0,1.0) , clamp(fragColor.rgb,0.0,1.0),transmission);
}
fragColor.rgb = filter_combined(fragColor.rgb);
gl_FragColor = fragColor;
gl_FragColor = applyHaze(fragColor, hazeColor, vec3(0.0), ct, hazeLayerAltitude, visibility, avisibility, dist, lightArg, mie_angle);
// Testing phase controls:

View file

@ -10,12 +10,6 @@
// TEST PHASE TOGGLES AND CONTROLS
//
// Development tools:
// Reduce haze to almost zero, while preserving lighting. Useful for observing distant tiles.
// Keeps the calculation overhead. This can be used for profiling.
// Possible values: 0:Normal, 1:Reduced haze.
const int reduce_haze_without_removing_calculation_overhead = 0;
// Remove haze and lighting and shows just the texture.
// Useful for checking texture rendering and scenery.
// The compiler will likely optimise out the haze and lighting calculations.
@ -36,19 +30,6 @@
// End of test phase controls
//////////////////////////////////////////////////////////////////
// written by Thorsten Renk, Oct 2011, based on default.frag
// Ambient term comes in gl_Color.rgb.
varying vec4 light_diffuse_comp;
varying vec3 normal;
@ -60,19 +41,13 @@ varying vec2 rawPos;
//vec3 worldPos = vec3(5000.0, 6000.0, 7000.0) + vec3(vec2(rawPos), 600.0); // vec3(100.0, 10.0, 3.0);
varying vec3 ecViewdir;
varying vec2 grad_dir;
//varying vec2 orthoTexCoord;
varying vec4 ecPosition;
varying float steepness;
uniform sampler2D landclass;
uniform sampler2DArray textureArray;
uniform sampler2D perlin;
varying float steepness;
uniform float visibility;
uniform float avisibility;
uniform float scattering;
@ -130,15 +105,8 @@ uniform vec4 fg_materialParams2[128];
uniform mat4 fg_zUpTransform;
uniform vec3 fg_modelOffset;
const float EarthRadius = 5800000.0;
const float terminator_width = 200000.0;
// Testing phase: Why are these in global scope in WS2 shaders?
//float alt;
float eShade;
float yprime_alt;
float mie_angle;
float shadow_func (in float x, in float y, in float noise, in float dist);
float DotNoise2D(in vec2 coord, in float wavelength, in float fractionalMaxDotSize, in float dot_density);
float Noise2D(in vec2 coord, in float wavelength);
@ -277,6 +245,17 @@ void get_material(in int landclass,
out vec2 st
);
// Apply the ALS haze model to a specific fragment
vec4 applyHaze(inout vec4 fragColor,
inout vec3 hazeColor,
in vec3 secondary_light,
in float ct,
in float hazeLayerAltitude,
in float visibility,
in float avisibility,
in float dist,
in float lightArg,
in float mie_angle);
// End Test-phase code
////////////////////////
@ -286,13 +265,12 @@ void main()
{
float alt;
yprime_alt = light_diffuse_comp.a;
float yprime_alt = light_diffuse_comp.a;
//diffuse_term.a = 1.0;
mie_angle = gl_Color.a;
float mie_angle = gl_Color.a;
float effective_scattering = min(scattering, cloud_self_shading);
// distance to fragment
float dist = length(relPos);
// angle of view vector with horizon
float ct = dot(vec3(0.0, 0.0, 1.0), relPos)/dist;
@ -678,8 +656,6 @@ void main()
if (mix_flag == 1)
{
nSum = 0.167 * (noise_4000m + 2.0 * noise_2000m + 2.0 * noise_1500m + noise_500m);
nSum = mix(nSum, 0.5, max(0.0, 2.0 * (transition_model - 0.5)));
nSum = nSum + 0.4 * (1.0 -smoothstep(0.9,0.95, abs(steepness)+ 0.05 * (noise_50m - 0.5))) * min(1.0, 2.0 * transition_model);
@ -701,8 +677,7 @@ void main()
texel = mix(texel, detail_texel,mix_factor);
}
// rock for very steep gradients
// rock for very steep gradients
if (gradient_texel.a > 0.0)
{
texel = mix(texel, gradient_texel, 1.0 - smoothstep(0.75,0.8,abs(steepness)+ 0.00002* msl_altitude + 0.05 * (noise_50m - 0.5)));
@ -711,7 +686,6 @@ void main()
// strata noise
float stratnoise_50m;
float stratnoise_10m;
@ -726,20 +700,16 @@ void main()
}
// the dot vegetation texture overlay
texel.rgb = mix(texel.rgb, dot_texel.rgb, dot_texel.a * (dotnoise_10m + dotnoise_15m) * detail_fade(1.0 * (dot_size * (1.0 +0.1*dot_size)), view_angle,dist));
texel.rgb = mix(texel.rgb, dot_texel.rgb, dot_texel.a * dotnoise_2m * detail_fade(0.1 * dot_size, view_angle,dist));
// then the grain texture overlay
texel.rgb = mix(texel.rgb, grain_texel.rgb, grain_strength * grain_texel.a * (1.0 - mix_factor) * (1.0-smoothstep(2000.0,5000.0, dist)));
// for really hires, add procedural noise overlay
texel.rgb = texel.rgb * (1.0 + 0.4 * (noise_01m-0.5) * detail_fade(0.1, view_angle, dist)) ;
// autumn colors
// autumn colors
float autumn_factor = season * 2.0 * (1.0 - local_autumn_factor) ;
@ -767,7 +737,6 @@ void main()
// mix dust
texel = mix(texel, dust_color, clamp(0.5 * dust_cover_factor *dust_resistance + 3.0 * dust_cover_factor * dust_resistance *(((noise_1500m - 0.5) * 0.125)+0.125 ),0.0, 1.0) );
// mix snow
float snow_mix_factor = 0.0;
@ -778,17 +747,12 @@ void main()
texel = mix(texel, snow_texel, snow_mix_factor);
}
// get distribution of water when terrain is wet
float combined_wetness = min(1.0, wetness + intrinsic_wetness);
float water_threshold1;
float water_threshold2;
float water_factor =0.0;
if ((dist < 5000.0) && (combined_wetness>0.0))
{
water_threshold1 = 1.0-0.5* combined_wetness;
@ -797,11 +761,8 @@ void main()
}
// darken wet terrain
texel.rgb = texel.rgb * (1.0 - 0.6 * combined_wetness);
// light computations
vec4 light_specular = gl_LightSource[0].specular;
@ -851,32 +812,26 @@ void main()
vec3 secondary_light = vec3 (0.0,0.0,0.0);
if (use_searchlight == 1)
{
if (use_searchlight == 1) {
secondary_light += searchlight();
}
if (use_landing_light == 1)
{
if (use_landing_light == 1) {
secondary_light += landing_light(landing_light1_offset, landing_light3_offset);
}
if (use_alt_landing_light == 1)
{
if (use_alt_landing_light == 1) {
secondary_light += landing_light(landing_light2_offset, landing_light3_offset);
}
color.rgb +=secondary_light * light_distance_fading(dist);
color.rgb += secondary_light * light_distance_fading(dist);
fragColor = color * texel + specular;
fragColor.rgb += getClusteredLightsContribution(ecPosition.xyz, n, texel.rgb);
float lightArg = (terminator-yprime_alt)/100000.0;
vec3 hazeColor = get_hazeColor(lightArg);
// Rayleigh color shift due to out-scattering
float rayleigh_length = 0.5 * avisibility * (2.5 - 1.9 * air_pollution)/alt_factor(eye_alt, eye_alt+relPos.z);
float outscatter = 1.0-exp(-dist/rayleigh_length);
@ -884,184 +839,18 @@ void main()
// Rayleigh color shift due to in-scattering
float rShade = 1.0 - 0.9 * smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt + 420000.0);
//float lightIntensity = length(diffuse_term.rgb)/1.73 * rShade;
float lightIntensity = length(hazeColor * effective_scattering) * rShade;
vec3 rayleighColor = vec3 (0.17, 0.52, 0.87) * lightIntensity;
float rayleighStrength = rayleigh_in_func(dist, air_pollution, avisibility/max(lightIntensity,0.05), eye_alt, eye_alt + relPos.z);
float rShade = 1.0 - 0.9 * smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt + 420000.0);
//float lightIntensity = length(diffuse_term.rgb)/1.73 * rShade;
float lightIntensity = length(hazeColor * effective_scattering) * rShade;
vec3 rayleighColor = vec3 (0.17, 0.52, 0.87) * lightIntensity;
float rayleighStrength = rayleigh_in_func(dist, air_pollution, avisibility/max(lightIntensity,0.05), eye_alt, eye_alt + relPos.z);
fragColor.rgb = mix(fragColor.rgb, rayleighColor,rayleighStrength);
// here comes the terrain haze model
float delta_z = hazeLayerAltitude - eye_alt;
float mvisibility = min(visibility,avisibility);
if (dist > 0.04 * mvisibility)
{
alt = eye_alt;
float transmission;
float vAltitude;
float delta_zv;
float H;
float distance_in_layer;
float transmission_arg;
// 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,mvisibility) * 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;
}
}
// blur of the haze layer edge
float blur_thickness = 50.0;
float cphi = dot(vec3(0.0, 1.0, 0.0), relPos)/dist;
float ctlayer = delta_z/dist-0.01 + 0.02 * Noise2D(vec2(cphi,1.0),0.1) -0.01;
float ctblur = 0.035 ;
float blur_dist;
if (abs(delta_z) < 400.0)
{
blur_dist = dist * (1.0-smoothstep(0.0,300.0,-delta_z)) * smoothstep(-400.0,-200.0, -delta_z);
blur_dist = blur_dist * smoothstep(ctlayer-4.0*ctblur, ctlayer-ctblur, ct) * (1.0-smoothstep(ctlayer+0.5*ctblur, ctlayer+ctblur, ct));
distance_in_layer = max(distance_in_layer, blur_dist);
}
// 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/(1.0 * visibility + 1.0 * visibility * fogstructure * 0.06 * (noise_1500m + noise_2000m -1.0) ));
eqColorFactor = 1.0 - 0.1 * delta_zv/visibility - (1.0 - effective_scattering);
}
else
{
transmission_arg = transmission_arg + (distance_in_layer/(1.0 * avisibility + 1.0 * avisibility * fogstructure * 0.06 * (noise_1500m + noise_2000m - 1.0) ));
eqColorFactor = 1.0 - 0.1 * delta_zv/avisibility - (1.0 - effective_scattering);
}
transmission = fog_func(transmission_arg, alt);
// there's always residual intensity, we should never be driven to zero
if (eqColorFactor < 0.2) eqColorFactor = 0.2;
// now dim the light for haze
eShade = 1.0 - 0.9 * smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt);
// Mie-like factor
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)) );
}
intensity = length(hazeColor);
if (intensity > 0.0) // this needs to be a condition, because otherwise hazeColor doesn't come out correctly
{
// high altitude desaturation of the haze color
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* shadedFogColor, 1.0 -smoothstep(0.25, fade_out,eShade) ));
// change haze color to blue hue for strong fogging
hazeColor = intensity * normalize(mix(hazeColor, shadedFogColor, (1.0-smoothstep(0.5,0.9,eqColorFactor))));
// reduce haze intensity when looking at shaded surfaces, only in terminator region
float shadow = mix( min(1.0 + dot(n,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));
}
// don't let the light fade out too rapidly
lightArg = (terminator + 200000.0)/100000.0;
float minLightIntensity = min(0.2,0.16 * lightArg + 0.5);
vec3 minLight = minLightIntensity * vec3 (0.2, 0.3, 0.4);
hazeColor.rgb *= eqColorFactor * eShade;
hazeColor.rgb = max(hazeColor.rgb, minLight.rgb);
// finally, mix fog in
// Testing phase controls
if (reduce_haze_without_removing_calculation_overhead == 1)
{
transmission = 1.0 - (transmission/1000000.0);
}
fragColor.rgb = mix(hazeColor+secondary_light * fog_backscatter(mvisibility) , fragColor.rgb,transmission);
} // end if (dist > 0.04 * mvisibility)
fragColor.rgb = filter_combined(fragColor.rgb);
gl_FragColor = fragColor;
gl_FragColor = applyHaze(fragColor, hazeColor, secondary_light, ct, hazeLayerAltitude, visibility, avisibility, dist, lightArg, mie_angle);
// Testing phase controls:
if (remove_haze_and_lighting == 1)
{
gl_FragColor = texel;
}
}

View file

@ -184,6 +184,18 @@ void get_material(in int landclass,
out vec2 st
);
// Apply the ALS haze model to a specific fragment
vec4 applyHaze(inout vec4 fragColor,
inout vec3 hazeColor,
in vec3 secondary_light,
in float ct,
in float hazeLayerAltitude,
in float visibility,
in float avisibility,
in float dist,
in float lightArg,
in float mie_angle);
// End Test-phase code
////////////////////////
@ -299,155 +311,14 @@ void main()
fragColor = color * texel + specular;
fragColor.rgb += getClusteredLightsContribution(ecPosition.xyz, n, texel.rgb);
// here comes the terrain haze model
float delta_z = hazeLayerAltitude - eye_alt;
float dist = length(relPos);
float mvisibility = min(visibility,avisibility);
if (dist > 0.04 * mvisibility)
{
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,mvisibility) * 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;
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 -effective_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 -effective_scattering);
}
transmission = fog_func(transmission_arg, alt);
// 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 = get_hazeColor(lightArg);
// now dim the light for haze
eShade = 1.0 - 0.9 * smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt);
// Mie-like factor
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)) );
}
// 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* shadedFogColor, 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, shadedFogColor, (1.0-smoothstep(0.5,0.9,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));
// don't let the light fade out too rapidly
lightArg = (terminator + 200000.0)/100000.0;
float minLightIntensity = min(0.2,0.16 * lightArg + 0.5);
vec3 minLight = minLightIntensity * vec3 (0.2, 0.3, 0.4);
hazeColor *= eqColorFactor * eShade;
hazeColor.rgb = max(hazeColor.rgb, minLight.rgb);
// determine the right mix of transmission and haze
// Testing phase controls
if (reduce_haze_without_removing_calculation_overhead == 1)
{
transmission = 1.0 - (transmission/1000000.0);
}
fragColor.rgb = mix(hazeColor, fragColor.rgb,transmission);
}
fragColor.rgb = filter_combined(fragColor.rgb);
gl_FragColor = fragColor;
gl_FragColor = applyHaze(fragColor, hazeColor, vec3(0.0), ct, hazeLayerAltitude, visibility, avisibility, dist, lightArg, mie_angle);
// Testing phase controls:

View file

@ -232,8 +232,10 @@ else // the faster, full-day version without lightfields
vec4 constant_term = gl_LightModel.ambient + light_ambient;
// 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;
gl_FrontColor.rgb = constant_term.rgb;
gl_BackColor.rgb = constant_term.rgb;
gl_FrontColor.a = mie_angle;
gl_BackColor.a = mie_angle;
setupShadows(ecPosition);
}