diff --git a/Effects/tree-grass.eff b/Effects/tree-grass.eff new file mode 100644 index 000000000..d4a111dfe --- /dev/null +++ b/Effects/tree-grass.eff @@ -0,0 +1,9 @@ + + + Effects/tree-grass + Effects/tree + + false + false + + diff --git a/Effects/tree.eff b/Effects/tree.eff index c6fb62716..22ac121e8 100644 --- a/Effects/tree.eff +++ b/Effects/tree.eff @@ -18,6 +18,10 @@ 0 + 200.0 + 1.5 + true + true /environment/ground-visibility-m /environment/visibility-m /environment/ground-haze-thickness-m @@ -96,6 +100,453 @@ + + + + + /sim/rendering/shaders/skydome + /sim/rendering/random-vegetation + /sim/rendering/multi-sample-buffers + /sim/rendering/random-vegetation-shadows + + 1.0 + /sim/rendering/multi-samples + + GL_ARB_shader_objects + GL_ARB_shading_language_100 + GL_ARB_vertex_shader + GL_ARB_fragment_shader + GL_ARB_multisample + + 2.0 + + + + + + + true + + 1.0 1.0 1.0 1.0 + 1.0 1.0 1.0 1.0 + off + + + 0 + 2d + + texture[0]/image + + clamp + clamp + + true + + Shaders/tree-ALS-shadow.vert + Shaders/noise.frag + Shaders/cloud-shadowfunc.frag + Shaders/tree-ALS-shadow.frag + Shaders/secondary_lights.frag + Shaders/hazes.frag + + + visibility + float + visibility + + + avisibility + float + avisibility + + + hazeLayerAltitude + float + lthickness + + + scattering + float + scattering + + + ground_scattering + float + ground_scattering + + + cloud_self_shading + float + cloud_self_shading + + + terminator + float + terminator + + + terrain_alt + float + terrain_alt + + + overcast + float + overcast + + + eye_alt + float + eye_alt + + + dust_cover_factor + float + dust_cover_factor + + + snow_level + float + snow_level + + + season + float + season + + + cseason + float + cseason + + + WindE + float + windE + + + WindN + float + windN + + + air_pollution + float + air_pollution + + + view_pitch_offset + float + view_pitch_offset + + + view_heading_offset + float + view_heading_offset + + + field_of_view + float + view_fov + + + landing_light1_offset + float + landing_light1_offset + + + landing_light2_offset + float + landing_light2_offset + + + cloudpos1_x + float + cloudpos1_x + + + cloudpos1_y + float + cloudpos1_y + + + cloudpos2_x + float + cloudpos2_x + + + cloudpos2_y + float + cloudpos2_y + + + cloudpos3_x + float + cloudpos3_x + + + cloudpos3_y + float + cloudpos3_y + + + cloudpos4_x + float + cloudpos4_x + + + cloudpos4_y + float + cloudpos4_y + + + cloudpos5_x + float + cloudpos5_x + + + cloudpos5_y + float + cloudpos5_y + + + cloudpos6_x + float + cloudpos6_x + + + cloudpos6_y + float + cloudpos6_y + + + cloudpos7_x + float + cloudpos7_x + + + cloudpos7_y + float + cloudpos7_y + + + cloudpos8_x + float + cloudpos8_x + + + cloudpos8_y + float + cloudpos8_y + + + cloudpos9_x + float + cloudpos9_x + + + cloudpos9_y + float + cloudpos9_y + + + cloudpos10_x + float + cloudpos10_x + + + cloudpos10_y + float + cloudpos10_y + + + cloudpos11_x + float + cloudpos11_x + + + cloudpos11_y + float + cloudpos11_y + + + cloudpos12_x + float + cloudpos12_x + + + cloudpos12_y + float + cloudpos12_y + + + cloudpos13_x + float + cloudpos13_x + + + cloudpos13_y + float + cloudpos13_y + + + cloudpos14_x + float + cloudpos14_x + + + cloudpos14_y + float + cloudpos14_y + + + cloudpos15_x + float + cloudpos15_x + + + cloudpos15_y + float + cloudpos15_y + + + cloudpos16_x + float + cloudpos16_x + + + cloudpos16_y + float + cloudpos16_y + + + cloudpos17_x + float + cloudpos17_x + + + cloudpos17_y + float + cloudpos17_y + + + cloudpos18_x + float + cloudpos18_x + + + cloudpos18_y + float + cloudpos18_y + + + cloudpos19_x + float + cloudpos19_x + + + cloudpos19_y + float + cloudpos19_y + + + cloudpos20_x + float + cloudpos20_x + + + cloudpos20_y + float + cloudpos20_y + + + cloud_shadow_flag + int + cloud_shadow_flag + + + use_searchlight + int + use_searchlight + + + use_landing_light + int + use_landing_light + + + use_alt_landing_light + int + use_alt_landing_light + + + display_xsize + int + display_xsize + + + display_ysize + int + display_ysize + + + num_deciduous_trees + int + num_deciduous_trees + + + use_forest_effect + bool + use_forest_effect + + + use_tree_shadows + bool + use_tree_shadows + + + forest_effect_size + float + forest_effect_size + + + forest_effect_shape + float + forest_effect_shape + + + texture + sampler-2d + 0 + + + colorMode + int + 2 + + + quality_level + int + quality_level + + + tquality_level + int + tquality_level + + + wind_effects + int + wind_effects + + + forest_effects + int + forest_effects + + + + @@ -484,6 +935,21 @@ int num_deciduous_trees + + use_forest_effect + bool + use_forest_effect + + + forest_effect_size + float + forest_effect_size + + + forest_effect_shape + float + forest_effect_shape + texture sampler-2d @@ -909,7 +1375,22 @@ num_deciduous_trees int num_deciduous_trees - + + + use_forest_effect + bool + use_forest_effect + + + forest_effect_size + float + forest_effect_size + + + forest_effect_shape + float + forest_effect_shape + texture sampler-2d diff --git a/Shaders/tree-ALS-shadow.frag b/Shaders/tree-ALS-shadow.frag new file mode 100644 index 000000000..03aa45136 --- /dev/null +++ b/Shaders/tree-ALS-shadow.frag @@ -0,0 +1,391 @@ +// -*-C++-*- + +// written by Thorsten Renk, Oct 2011, based on default.frag + + +varying vec3 relPos; + + +uniform sampler2D texture; + + +varying float yprime_alt; + +varying float is_shadow; +varying float autumn_flag; + +uniform float visibility; +uniform float avisibility; +uniform float scattering; +uniform float ground_scattering; +uniform float cloud_self_shading; +uniform float terminator; +uniform float terrain_alt; +uniform float hazeLayerAltitude; +uniform float overcast; +uniform float eye_alt; +uniform float dust_cover_factor; +uniform float air_pollution; +uniform float landing_light1_offset; +uniform float landing_light2_offset; +uniform float cseason; + +uniform int use_searchlight; +uniform int use_landing_light; +uniform int use_alt_landing_light; +uniform int quality_level; +uniform int tquality_level; + + +const float EarthRadius = 5800000.0; +const float terminator_width = 200000.0; + +float alt; +float mie_angle; + + +float light_distance_fading(in float dist); +float fog_backscatter(in float avisibility); +float rayleigh_in_func(in float dist, in float air_pollution, in float avisibility, in float eye_alt, in float vertex_alt); + +vec3 searchlight(); +vec3 landing_light(in float offset); +vec3 get_hazeColor(in float light_arg); + +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 tree_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 * smoothstep(0.07,0.1,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)); + } + +} + +float rand2D(in vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + + +float simple_interpolate(in float a, in float b, in float x) +{ +return a + smoothstep(0.0,1.0,x) * (b-a); +} + +float interpolatedNoise2D(in float x, in float y) +{ + float integer_x = x - fract(x); + float fractional_x = x - integer_x; + + float integer_y = y - fract(y); + float fractional_y = y - integer_y; + + float v1 = rand2D(vec2(integer_x, integer_y)); + float v2 = rand2D(vec2(integer_x+1.0, integer_y)); + float v3 = rand2D(vec2(integer_x, integer_y+1.0)); + float v4 = rand2D(vec2(integer_x+1.0, integer_y +1.0)); + + float i1 = simple_interpolate(v1 , v2 , fractional_x); + float i2 = simple_interpolate(v3 , v4 , fractional_x); + + return simple_interpolate(i1 , i2 , fractional_y); +} + + + +float Noise2D(in vec2 coord, in float wavelength) +{ +return interpolatedNoise2D(coord.x/wavelength, coord.y/wavelength); + +} + +void main() +{ + + if (is_shadow > 1.0) {discard;} + vec3 shadedFogColor = vec3(0.65, 0.67, 0.78); + + + + vec3 lightDir = gl_LightSource[0].position.xyz; + float intensity; + + mie_angle = gl_Color.a; + vec4 texel = texture2D(texture, gl_TexCoord[0].st); + + // angle with horizon + float dist = length(relPos); + float ct = dot(vec3(0.0, 0.0, 1.0), relPos)/dist; + + // determine tree shadow properties + if (is_shadow>0.0) + { + if (ct > -0.1) {discard;} // we eliminate shadows above the camera to avoid artifacts + float illumination = length(gl_Color.rgb); + texel = vec4 (0.1,0.1,0.1,texel.a); + texel.a *= illumination;// * smoothstep(0.0, 0.2, is_shadow); + texel.a *=0.6 * smoothstep(0.5,0.8,scattering); + texel.a = min(0.8, texel.a); + } + + float effective_scattering = min(scattering, cloud_self_shading); + + + if (quality_level > 3) + { + // seasonal color changes + + if ((cseason < 1.5)&& (autumn_flag > 0.0) && (is_shadow <0.0)) + { + texel.r = min(1.0, (1.0 + 5.0 *cseason * autumn_flag ) * texel.r); + texel.b = max(0.0, (1.0 - 8.0 * cseason) * texel.b); + } + + // mix dust + vec4 dust_color = vec4 (0.76, 0.71, 0.56, texel.a); + + texel = mix(texel, dust_color, clamp(0.6 * dust_cover_factor ,0.0, 1.0) ); + } + + +// ALS secondary light sources + + vec3 secondary_light = vec3 (0.0,0.0,0.0); + + if ((quality_level>5) && (tquality_level>5)) + { + if (use_searchlight == 1) + { + secondary_light += searchlight(); + } + if (use_landing_light == 1) + { + secondary_light += landing_light(landing_light1_offset); + } + if (use_alt_landing_light == 1) + { + secondary_light += landing_light(landing_light2_offset); + } + } + + vec4 fragColor = vec4 (gl_Color.rgb +secondary_light * light_distance_fading(dist),1.0) * texel; + + +// Rayleigh haze + +float lightArg = (terminator-yprime_alt)/100000.0; +vec3 hazeColor = get_hazeColor(lightArg); + +// Rayleigh color shift due to in-scattering + + if ((quality_level > 5) && (tquality_level > 5)) + { + float rShade = 1.0 - 0.9 * smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt + 420000.0); + 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; + + +if (dist > max(40.0, 0.07 * min(visibility,avisibility))) +{ + +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; + } + } + + +// 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; +float ctblur = 0.035 ; + +float blur_dist; + +if ((abs(delta_z) < 400.0)&&(quality_level>5)&&(tquality_level>5)) + { + ctlayer = delta_z/dist-0.01 + 0.02 * Noise2D(vec2(cphi,1.0),0.1) -0.01; + 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; + +//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/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 = tree_fog_func(transmission_arg); + +// 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 +float eShade = 0.9 * smoothstep(terminator_width+ terminator, -terminator_width + terminator, yprime_alt) + 0.1; + +// 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 + +hazeColor = intensity * normalize(mix(hazeColor, shadedFogColor, (1.0-smoothstep(0.5,0.9,eqColorFactor)))); + + + +// determine the right mix of transmission and haze + +hazeColor = clamp(hazeColor,0.0,1.0); +fragColor.rgb = mix(eqColorFactor * hazeColor * eShade + secondary_light * fog_backscatter(avisibility), fragColor.rgb,transmission); + +gl_FragColor = fragColor; + +} +else // if dist < 40.0 no fogging at all +{ + +gl_FragColor = fragColor; +} + +//gl_FragColor.rgb = gl_SecondaryColor.rgb; +} + diff --git a/Shaders/tree-ALS-shadow.vert b/Shaders/tree-ALS-shadow.vert new file mode 100644 index 000000000..d8b5307e6 --- /dev/null +++ b/Shaders/tree-ALS-shadow.vert @@ -0,0 +1,329 @@ +// -*-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 vec3 relPos; +varying float yprime_alt; +varying float is_shadow; +varying float autumn_flag; + +uniform int colorMode; +uniform int wind_effects; +uniform int forest_effects; +uniform int num_deciduous_trees; +uniform float hazeLayerAltitude; +uniform float terminator; +uniform float terrain_alt; +uniform float avisibility; +uniform float visibility; +uniform float overcast; +uniform float ground_scattering; +uniform float snow_level; +uniform float season; +uniform float forest_effect_size; +uniform float forest_effect_shape; +uniform float WindN; +uniform float WindE; + +uniform bool use_tree_shadows; +uniform bool use_forest_effect; + +uniform float osg_SimulationTime; + +uniform int cloud_shadow_flag; + +float earthShade; +float mie_angle; + +float shadow_func (in float x, in float y, in float noise, in float dist); +float VoronoiNoise2D(in vec2 coord, in float wavelength, in float xrand, in float yrand); + +// 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; + + vec3 shadedFogColor = vec3(0.65, 0.67, 0.78); + + float yprime; + float lightArg; + float intensity; + float vertex_alt; + float scattering; + is_shadow = -1.0; + + // establish coordinates relative to sun position + + vec3 lightFull = (gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz; + vec3 lightHorizon = normalize(vec3(lightFull.x,lightFull.y, 0.0)); + +// this code is copied from tree.vert + + float numVarieties = gl_Normal.z; + float texFract = floor(fract(gl_MultiTexCoord0.x) * numVarieties) / numVarieties; + +// determine whether the tree changes color in autumn + if (texFract < float(num_deciduous_trees)/float(numVarieties)) {autumn_flag = 0.5 + fract(gl_Color.x);} + else {autumn_flag = 0.0;} + + texFract += floor(gl_MultiTexCoord0.x) / numVarieties; + + // Determine the rotation for the tree. The Fog Coordinate provides rotation information + // to rotate one of the quands by 90 degrees. We then apply an additional position seed + // so that trees aren't all oriented N/S + float sr; + float cr; + sr = sin(gl_FogCoord + gl_Color.x); + cr = cos(gl_FogCoord + gl_Color.x); + + if (gl_FogCoord < 0.0) + { + sr = dot(lightHorizon.xy, vec2 (0.0,1.0)); + cr = dot(lightHorizon.xy, vec2 (-1.0,0.0)); + } + + + gl_TexCoord[0] = vec4(texFract, gl_MultiTexCoord0.y, 0.0, 0.0); + + // Determine the y texture coordinate based on whether it's summer, winter, snowy. + gl_TexCoord[0].y = gl_TexCoord[0].y + 0.25 * step(snow_level, gl_Color.z) + 0.5 * season; + + // scaling + vec3 position = gl_Vertex.xyz * gl_Normal.xxy; + + // Rotation of the generic quad to specific one for the tree. + position.xy = vec2(dot(position.xy, vec2(cr, sr)), dot(position.xy, vec2(-sr, cr))); + + + // Shear by wind. Note that this only applies to the top vertices + if (wind_effects > 0) + { + position.x = position.x + position.z * (sin(osg_SimulationTime * 1.8 + (gl_Color.x + gl_Color.y + gl_Color.z) * 0.01) + 1.0) * 0.0025 * WindN; + position.y = position.y + position.z * (sin(osg_SimulationTime * 1.8 + (gl_Color.x + gl_Color.y + gl_Color.z) * 0.01) + 1.0) * 0.0025 * WindE; + } + + + + + + + // Scale by random domains + float voronoi; + if ((forest_effects > 0)&& use_forest_effect) + { + voronoi = 0.5 + 1.0 * VoronoiNoise2D(gl_Color.xy, forest_effect_size, forest_effect_shape, forest_effect_shape); + position.xyz = position.xyz * voronoi; + } + + // check if this is a shadow quad + if ((gl_FogCoord <0.0)&&(use_tree_shadows)) + { + is_shadow = 1.0; + float sinAlpha = dot(lightFull, vec3 (0.0,0.0,1.0)); + float cosAlpha = sqrt(1.0 - sinAlpha*sinAlpha); + float slope = dot(gl_SecondaryColor.xyz, vec3(0.0,0.0,1.0)); + //float slope = 1.0; + position.x += position.z * clamp(cosAlpha/sinAlpha,-5.0,5.0) * -dot(lightHorizon.xy, vec2(1.0,0.0)); + position.y += position.z * clamp(cosAlpha/sinAlpha,-5.0,5.0) * -dot(lightHorizon.xy, vec2 (0.0,1.0)); + if (position.z > 3.0) // we deal with an upper vertex + { + vec3 terrainNormal = gl_SecondaryColor.xyz; + position.z = 0.4 + 10.0*(1.0 - slope) ; + float sinPhi = dot(terrainNormal, vec3(1.0,0.0,0.0)); + float sinPsi = dot(terrainNormal, vec3(0.0,1.0,0.0)); + position.z -= position.x * sinPhi; + position.z -= position.y * sinPsi; + } + else + {position.z = 0.4 + 10.0* (1.0-slope);} + + } + + + // Move to correct location (stored in gl_Color) + position = position + gl_Color.xyz; + gl_Position = gl_ModelViewProjectionMatrix * vec4(position,1.0); + + vec3 ecPosition = vec3(gl_ModelViewMatrix * vec4(position, 1.0)); + //normal = normalize(-ecPosition); + + //float n = dot(normalize(gl_LightSource[0].position.xyz), normalize(-ecPosition)); + + + //vec4 diffuse_color = gl_FrontMaterial.diffuse * max(0.1, n); + //diffuse_color.a = 1.0; + vec4 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 = position - 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(position.z,100.0); + scattering = ground_scattering + (1.0 - ground_scattering) * smoothstep(hazeLayerAltitude -100.0, hazeLayerAltitude + 100.0, vertex_alt); + + // check whether we should see a shadow + + if (is_shadow >0.0) + { + float view_angle = dot ((gl_SecondaryColor.xyz), normalize(relPos)); + if (view_angle < 0.0) {is_shadow = -view_angle;} + else {is_shadow = 5.0;} + + // the surface element will be in shadow + if (dot(normalize(lightFull),(gl_SecondaryColor.xyz)) < 0.0) + { is_shadow = 5.0;} + } + + // branch dependent on daytime + +if (terminator < 1000000.0) // the full, sunrise and sunset computation +{ + + // 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 < 10.0) + {mie_angle = (0.5 * dot(normalize(relPos), normalize(lightFull)) ) + 0.5;} + else + {mie_angle = 1.0;} + + + light_ambient.r = light_func(lightArg, 0.236, 0.253, 1.073, 0.572, 0.33); + light_ambient.g = light_ambient.r * 0.4/0.33; + light_ambient.b = light_ambient.r * 0.5/0.33; + light_ambient.a = 1.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.rgb); + light_ambient.rgb = intensity * normalize(mix(light_ambient.rgb, shadedFogColor, 1.0 -smoothstep(0.1, 0.8,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 +{ + + + earthShade = 1.0; + mie_angle = 1.0; + + if (terminator > 3000000.0) + {light_ambient = vec4 (0.33, 0.4, 0.5, 1.0); } + else + { + + lightArg = (terminator/100000.0 - 10.0)/20.0; + + light_ambient.r = 0.316 + lightArg * 0.016; + light_ambient.g = light_ambient.r * 0.4/0.33; + light_ambient.b = light_ambient.r * 0.5/0.33; + light_ambient.a = 1.0; + } + + + yprime_alt = -sqrt(2.0 * EarthRadius * hazeLayerAltitude); +} + + light_ambient.rgb = light_ambient.rgb * (1.0 + smoothstep(1000000.0, 3000000.0,terminator)); + +// tree shader lighting + +if (cloud_shadow_flag == 1) + {light_ambient.rgb = light_ambient.rgb * (0.5 + 0.5 * shadow_func(relPos.x, relPos.y, 1.0, dist));} + + + //vec4 ambientColor = gl_FrontLightModelProduct.sceneColor + + //gl_FrontColor = ambientColor; + gl_FrontColor = light_ambient * gl_FrontMaterial.ambient; + gl_FrontColor.a = mie_angle; gl_BackColor.a = mie_angle; + + //gl_FrontSecondaryColor = vec4 (1.0,1.0,1.0,1.0) * 5.0*(1.0-dot(gl_SecondaryColor.rgb, vec3 (0.0,0.0,1.0))); + //gl_BackSecondaryColor = vec4 (1.0,1.0,1.0,1.0) * 5.0 * (1.0-dot(gl_SecondaryColor.rgb, vec3 (0.0,0.0,1.0))); + +} + diff --git a/Shaders/tree-ALS.vert b/Shaders/tree-ALS.vert index 2da7e3a82..1e4daac6d 100644 --- a/Shaders/tree-ALS.vert +++ b/Shaders/tree-ALS.vert @@ -37,6 +37,8 @@ uniform float overcast; uniform float ground_scattering; uniform float snow_level; uniform float season; +uniform float forest_effect_size; +uniform float forest_effect_shape; uniform float WindN; uniform float WindE; @@ -44,6 +46,8 @@ uniform float osg_SimulationTime; uniform int cloud_shadow_flag; +uniform bool use_forest_effect; + float earthShade; float mie_angle; @@ -116,9 +120,9 @@ void main() // Scale by random domains float voronoi; - if (forest_effects > 0) + if ((forest_effects > 0)&& use_forest_effect) { - voronoi = 0.5 + 1.0 * VoronoiNoise2D(gl_Color.xy, 200.0, 1.5, 1.5); + voronoi = 0.5 + 1.0 * VoronoiNoise2D(gl_Color.xy, forest_effect_size, forest_effect_shape, forest_effect_shape); position.xyz = position.xyz * voronoi; } diff --git a/gui/dialogs/rendering.xml b/gui/dialogs/rendering.xml index 0b3e739f2..23340862a 100644 --- a/gui/dialogs/rendering.xml +++ b/gui/dialogs/rendering.xml @@ -363,6 +363,38 @@ + + + + /sim/rendering/shaders/skydome + + 5 + 0 + left + + tree-shadows + /sim/rendering/random-vegetation-shadows + + dialog-apply + tree-shadows + + + + + + /sim/rendering/shaders/skydome + + 5 + 1 + 3 + + 1.0 + 0.6 + 0.6 + + + + @@ -635,7 +667,7 @@ 0 left - + skydome-scattering @@ -798,6 +830,7 @@ "/sim/rendering/random-buildings", "/sim/rendering/random-objects", "/sim/rendering/random-vegetation", + "/sim/rendering/random-vegetation-shadows", "/sim/rendering/vegetation-density", "/sim/rendering/clouds3d-enable", "/sim/rendering/clouds3d-density"]; diff --git a/preferences.xml b/preferences.xml index 37cf11501..e05960f9f 100644 --- a/preferences.xml +++ b/preferences.xml @@ -174,6 +174,8 @@ Started September 2000 by David Megginson, david@megginson.com true true + false + false 1.0 false 1.0