diff --git a/Effects/ws30-overlay.eff b/Effects/ws30-overlay.eff new file mode 100644 index 000000000..1980af783 --- /dev/null +++ b/Effects/ws30-overlay.eff @@ -0,0 +1,962 @@ + + + + Effects/ws30-overlay + Effects/ws30 + + + + + + Textures/Terrain/mixedforest-hires.png + 2d + nearest-mipmap-nearest + nearest + repeat + repeat + normalized + + + + + Textures/Terrain/grass_hires.png + 2d + nearest-mipmap-nearest + nearest + repeat + repeat + normalized + + + 1.5 + 1.0 + 1.0 + 0.5 + 0.5 + 0.5 + 0.5 + 0.8 + 0.5 + 0 + 1 + + + + + + + + + + + /sim/rendering/shaders/skydome + + + 6.0 + /sim/rendering/shaders/landmass + + + 6.0 + /sim/rendering/shaders/transition + + + 1.0 + /sim/rendering/shaders/vegetation-effects + + + + + 2.0 + + + + GL_ARB_shader_objects + GL_ARB_shading_language_100 + GL_ARB_vertex_shader + GL_ARB_fragment_shader + + + GL_EXT_geometry_shader4 + + + + + true + + material/ambient + material/diffuse + material/specular + material/emissive + material/shininess + ambient-and-diffuse + + transparent + transparent + smooth + back + + render-bin/bin-number + render-bin/bin-name + + + + + + 1 + texture[1]/image + nearest-mipmap-nearest + nearest-mipmap-nearest + texture[0]/wrap-s + texture[0]/wrap-t + texture[0]/internal-format + + + + 2 + texture[2]/image + texture[2]/filter + texture[2]/wrap-s + texture[2]/wrap-t + texture[2]/internal-format + + + + 3 + texture[3]/image + texture[3]/filter + texture[3]/wrap-s + texture[3]/wrap-t + texture[3]/internal-format + + + + 4 + texture[4]/image + texture[4]/filter + texture[4]/wrap-s + texture[4]/wrap-t + texture[4]/internal-format + + + + 6 + texture[6]/image + texture[6]/filter + texture[6]/wrap-s + texture[6]/wrap-t + texture[6]/internal-format + + + + Shaders/ws30-ALS-ultra.vert + Shaders/filters-ALS.vert + Shaders/shadows-include.vert + Shaders/ws30-ALS-ultra.frag + Shaders/ws30-ALS-landclass-search-functions.frag + Shaders/noise.frag + Shaders/cloud-shadowfunc.frag + Shaders/hazes.frag + Shaders/secondary_lights.frag + Shaders/filters-ALS.frag + Shaders/shadows-include.frag + Shaders/clustered-include.frag + + + grain_strength + float + grain_strength + + + intrinsic_wetness + float + intrinsic_wetness + + + transition_model + float + transition_model + + + hires_overlay_bias + float + hires_overlay_bias + + + dot_density + float + dot_density + + + dot_size + float + dot_size + + + dust_resistance + float + dust_resistance + + + visibility + float + visibility + + + avisibility + float + avisibility + + + hazeLayerAltitude + float + lthickness + + + scattering + float + scattering + + + ground_scattering + float + ground_scattering + + + terminator + float + terminator + + + terrain_alt + float + terrain_alt + + + overcast + float + overcast + + + eye_alt + float + eye_alt + + + eye_lat + float + eye_lat + + + eye_lon + float + eye_lon + + + snowlevel + float + snow_level + + + snow_thickness_factor + float + snow_thickness_factor + + + dust_cover_factor + float + dust_cover_factor + + + lichen_cover_factor + float + lichen_cover_factor + + + wetness + float + wetness + + + fogstructure + float + fogstructure + + + cloud_self_shading + float + cloud_self_shading + + + moonlight + float + moonlight + + + season + float + season + + + 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 + + + landing_light3_offset + float + landing_light3_offset + + + + gamma + float + gamma + + + brightness + float + brightness + + + use_night_vision + bool + use_night_vision + + + use_IR_vision + bool + use_IR_vision + + + use_filtering + bool + use_filtering + + + delta_T + float + delta_T + + + fact_grey + float + fact_grey + + + fact_black + float + fact_black + + + + 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 + + + WindE + float + windE + + + WindN + float + windN + + + 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 + + + wind_effects + int + wind_effects + + + cloud_shadow_flag + int + cloud_shadow_flag + + + rock_strata + int + rock_strata + + + raise_vertex + bool + raise_vertex + + + landclass + sampler-2d + 0 + + + textureArray + sampler-2d + 1 + + + perlin + sampler-2d + 6 + + + swatch_size + int + + 2000 + + + colorMode + int + 2 + + + + + shadow_tex + sampler-2d + 10 + + + shadows_enabled + bool + + shadows_enabled + + + + sun_atlas_size + int + + sun_atlas_size + + + + + + + true + + material/ambient + material/diffuse + material/specular + material/emissive + material/shininess + ambient-and-diffuse + + transparent + smooth + + + back + + + + render-bin/bin-number + render-bin/bin-name + + + + 7 + texture[20]/type + texture[20]/image + texture[20]/filter + texture[20]/mag-filter + texture[20]/wrap-s + texture[20]/wrap-t + texture[20]/internal-format + + + 8 + texture[21]/type + texture[21]/image + texture[21]/filter + texture[21]/mag-filter + texture[21]/wrap-s + texture[21]/wrap-t + texture[21]/internal-format + + + Shaders/ws30-overlay-ALS.vert + Shaders/ws30-overlay-ALS.geom + Shaders/terrain-overlay-ALS.frag + Shaders/noise.frag + Shaders/filters-ALS.frag + Shaders/cloud-shadowfunc.frag + Shaders/shadows-include.frag + 96 + triangles + triangle-strip + + + overlayPrimaryTex + sampler-2d + 7 + + + overlaySecondaryTex + sampler-2d + 8 + + + visibility + float + visibility + + + avisibility + float + avisibility + + + scattering + float + scattering + + + overlay_bias + float + overlay_bias + + + overlay_max_height + float + max_overlay_height + + + overlay_hardness + float + overlay_hardness + + + overlay_secondary_hardness + float + overlay_secondary_hardness + + + overlay_density + float + overlay_density + + + overlay_secondary_density + float + overlay_secondary_density + + + overlay_scale + float + overlay_scale + + + overlay_brightness_top + float + overlay_brightness_top + + + overlay_brightness_bottom + float + overlay_brightness_bottom + + + overlay_steepness_factor + float + overlay_steepness_factor + + + season + float + season + + + dust_cover_factor + float + dust_cover_factor + + + wetness + float + wetness + + + snowlevel + float + snow_level + + + snow_thickness_factor + float + snow_thickness_factor + + + + + cloudpos_n_x + float + cloudpos_n_x + + + cloudpos_n_y + float + cloudpos_n_y + + + + + + gamma + float + gamma + + + brightness + float + brightness + + + use_night_vision + bool + use_night_vision + + + use_IR_vision + bool + use_IR_vision + + + use_filtering + bool + use_filtering + + + delta_T + float + delta_T + + + fact_grey + float + fact_grey + + + fact_black + float + fact_black + + + + display_xsize + int + display_xsize + + + display_ysize + int + display_ysize + + + overlay_autumn_flag + int + overlay_autumn_flag + + + overlay_secondary_flag + int + overlay_secondary_flag + + + cloud_shadow_flag + int + cloud_shadow_flag + + + + shadow_tex + sampler-2d + 10 + + + shadows_enabled + bool + + shadows_enabled + + + + sun_atlas_size + int + + sun_atlas_size + + + + + + true + src-alpha + one-minus-src-alpha + + + + false + + + + diff --git a/Effects/ws30.eff b/Effects/ws30.eff index fee8ac9bd..2ec0c7f08 100644 --- a/Effects/ws30.eff +++ b/Effects/ws30.eff @@ -182,7 +182,11 @@ insert their own techniques first. --> - + + diff --git a/Materials/base/materials-base.xml b/Materials/base/materials-base.xml index 57da4c70c..46f00f5b7 100644 --- a/Materials/base/materials-base.xml +++ b/Materials/base/materials-base.xml @@ -635,7 +635,8 @@ ws30Road osm2city/roads.png - + Effects/terrain-default + 0.25 0.375 0.75 @@ -664,6 +665,7 @@ ws30Freeway osm2city/roads.png Effects/terrain-default + 0.625 0.75 1.0 diff --git a/Shaders/ws30-ALS-detailed.frag b/Shaders/ws30-ALS-detailed.frag index fb6782c8a..cab8c569b 100644 --- a/Shaders/ws30-ALS-detailed.frag +++ b/Shaders/ws30-ALS-detailed.frag @@ -43,7 +43,8 @@ varying vec4 light_diffuse_comp; varying vec3 normal; varying vec3 relPos; -varying vec3 rawPos; +varying vec2 ground_tex_coord; +varying vec2 rawPos; varying vec3 worldPos; // Testing code: //vec3 worldPos = vec3(5000.0, 6000.0, 7000.0) + vec3(vec2(rawPos), 600.0); // vec3(100.0, 10.0, 3.0); @@ -157,21 +158,33 @@ int get_random_landclass(in vec2 co, in vec2 tile_size); // The partial derivatives of the tile_coord at the fragment is needed to adjust for // the stretching of different textures, so that the correct mip-map level is looked // up and there are no seams. +// Texture types: 0: base texture, 1: grain texture, 2: gradient texture, 3 dot texture, +// 4: mix texture, 5: detail texture. -vec4 lookup_ground_texture_array(in vec2 tile_coord, in int landclass_id, in vec2 dx, in vec2 dy); +vec4 lookup_ground_texture_array(in int texture_type, in vec2 ground_texture_coord, in int landclass_id, + in vec4 dFdx_and_dFdy); // Look up the landclass id [0 .. 255] for this particular fragment. // Lookup id of any neighbouring landclass that is within the search distance. // Searches are performed in upto 4 directions right now, but only one landclass is looked up -// Create a mix factor werighting the influences of nearby landclasses -void get_landclass_id(in vec2 tile_coord, - const in float landclass_texel_size_m, in vec2 dx, in vec2 dy, +// Create a mix factor weighting the influences of nearby landclasses +void get_landclass_id(in vec2 tile_coord, in vec4 dFdx_and_dFdy, out int landclass_id, out ivec4 neighbor_landclass_ids, out int num_unique_neighbors,out vec4 mix_factor ); +// Look up the texel of the specified texture type (e.g. grain or detail textures) for this fragment +// and any neighbor texels, then mix. + +vec4 get_mixed_texel(in int texture_type, in vec2 g_texture_coord, + in int landclass_id, in int num_unique_neighbors, + in ivec4 neighbor_texel_landclass_ids, in vec4 neighbor_mix_factors, + in vec4 dFdx_and_dFdy + ); + + // End Test-phase code //////////////////////// @@ -270,16 +283,15 @@ float noise_2000m = Noise3D(worldPos.xyz, 2000.0); vec4 mfact; - const float landclass_texel_size_m = 25.0; - // Partial derivatives of s and t for this fragment, + // Partial derivatives of s and t of ground texture coords for this fragment, // with respect to window (screen space) x and y axes. // Used to pick mipmap LoD levels, and turn off unneeded procedural detail - vec2 dx = dFdx(tile_coord); - vec2 dy = dFdy(tile_coord); + // dFdx and dFdy are packed in a vec4 so multiplying everything + // to scale takes 1 instruction slot. + vec4 dxdy_gc = vec4(dFdx(ground_tex_coord) , dFdy(ground_tex_coord)); - get_landclass_id(tile_coord, landclass_texel_size_m, dx, dy, - lc, lc_n, num_unique_neighbors, mfact); + get_landclass_id(tile_coord, dxdy_gc, lc, lc_n, num_unique_neighbors, mfact); // The landclass id is used to index into arrays containing // material parameters and textures for the landclass as @@ -291,13 +303,23 @@ float noise_2000m = Noise3D(worldPos.xyz, 2000.0); vec4 mat_ambient = fg_ambientArray[lc]; vec4 mat_diffuse = fg_diffuseArray[lc]; vec4 mat_specular = fg_specularArray[lc]; - vec2 st = gl_TexCoord[0].st; // Testing code: // Use rlc even when looking up textures to recreate the extra performance hit // so any performance difference between the two is due to the texture lookup // color.rgb = color.rgb+0.00001*float(get_random_landclass(tile_coord.st, tile_size)); + // Calculate texture coords for ground textures + // Textures are stretched along the ground to different + // lengths along each axes as set by and + // regional definitions parameters. + vec2 stretch_dimensions = fg_dimensionsArray[lc].st; + vec2 tileSize = vec2(fg_tileWidth, fg_tileHeight); + vec2 texture_scaling = tileSize.xy / stretch_dimensions.st; + vec2 st = texture_scaling.st * ground_tex_coord.st; + + // Scale partial derivatives + vec4 dxdy = vec4(texture_scaling.st, texture_scaling.st) * dxdy_gc; if (fg_photoScenery) { // In the photoscenery case we don't have landclass or materials available, so we @@ -305,51 +327,25 @@ float noise_2000m = Noise3D(worldPos.xyz, 2000.0); mat_ambient = vec4(0.2,0.2,0.2,1.0); mat_diffuse = vec4(0.8,0.8,0.8,1.0); mat_specular = vec4(0.0,0.0,0.0,1.0); + mat_shininess = 1.2; texel = texture(landclass, vec2(gl_TexCoord[0].s, 1.0 - gl_TexCoord[0].t)); - } else { - // Color Mode is always AMBIENT_AND_DIFFUSE, which means - // using a base colour of white for ambient/diffuse, - // rather than the material color from ambientArray/diffuseArray. - mat_ambient = vec4(1.0,1.0,1.0,1.0); - mat_diffuse = vec4(1.0,1.0,1.0,1.0); - mat_specular = fg_specularArray[lc]; - mat_shininess = fg_dimensionsArray[lc].z; + } else + { - // Different textures have different have different dimensions. - vec2 atlas_dimensions = fg_dimensionsArray[lc].st; - vec2 atlas_scale = vec2(fg_tileWidth / atlas_dimensions.s, fg_tileHeight / atlas_dimensions.t ); - st = atlas_scale * gl_TexCoord[0].st; + // Color Mode is always AMBIENT_AND_DIFFUSE, which means + // using a base colour of white for ambient/diffuse, + // rather than the material color from ambientArray/diffuseArray. + mat_ambient = vec4(1.0,1.0,1.0,1.0); + mat_diffuse = vec4(1.0,1.0,1.0,1.0); + mat_specular = fg_specularArray[lc]; + mat_shininess = fg_dimensionsArray[lc].z; - // Look up ground textures by indexing into the texture array. - // Different textures are stretched along the ground to different - // lengths along each axes as set by and - // regional definitions parameters + // Lookup the base texture texel for this fragment and any neighbors, with mixing + texel = get_mixed_texel(0, ground_tex_coord, lc, num_unique_neighbors, lc_n, mfact, dxdy_gc); - // Look up texture coordinates and scale of ground textures - // Landclass for this fragment - texel = lookup_ground_texture_array(tile_coord, lc, dx, dy); + //if (ground_tex_coord.x > 0.0) texel = vec4(1.0); - // Mix texels - to work consistently it needs a more preceptual interpolation than mix() - if (num_unique_neighbors != 0) - { - // Closest neighbor landclass - vec4 texel_closest = lookup_ground_texture_array(tile_coord, lc_n[0], dx, dy); - - // Neighbor contributions - vec4 texel_nc=texel_closest; - - if (num_unique_neighbors > 1) - { - // 2nd Closest neighbor landclass - vec4 texel_2nd_closest = lookup_ground_texture_array(tile_coord, lc_n[1], - dx, dy); - - texel_nc = mix(texel_closest, texel_2nd_closest, mfact[1]); - } - - texel = mix(texel, texel_nc, mfact[0]); - } } vec4 color = gl_Color * mat_ambient; @@ -359,6 +355,9 @@ float noise_2000m = Noise3D(worldPos.xyz, 2000.0); //vec4 green = vec4(0.0, 0.5, 0.0, 0.0); //texel = mix(texel, green, (mfact[2])); + //mix_texel = texel; + //detail_texel = texel; + vec4 t = texel; int flag = 1; int mix_flag = 1; @@ -378,7 +377,7 @@ float noise_2000m = Noise3D(worldPos.xyz, 2000.0); //float view_angle = abs(dot(normal, normalize(ecViewdir))); - if ((quality_level > 3)&&(rawPos.z +500.0 > snowlevel)) { + if ((quality_level > 3)&&(relPos.z +500.0 > snowlevel)) { float sfactor; snow_texel = vec4 (0.95, 0.95, 0.95, 1.0) * (0.9 + 0.1* noise_500m + 0.1* (1.0 - noise_10m) ); snow_texel.r = snow_texel.r * (0.9 + 0.05 * (noise_10m + noise_5m)); @@ -393,17 +392,21 @@ float noise_2000m = Noise3D(worldPos.xyz, 2000.0); noise_term = noise_term + 0.3 * (noise_5m -0.5) * (1.0 - smoothstep(1000.0 * sfactor, 3000.0 *sfactor, dist) ); } - snow_texel.a = snow_texel.a * 0.2+0.8* smoothstep(0.2,0.8, 0.3 +noise_term + snow_thickness_factor +0.0001*(rawPos.z -snowlevel) ); + snow_texel.a = snow_texel.a * 0.2+0.8* smoothstep(0.2,0.8, 0.3 +noise_term + snow_thickness_factor +0.0001*(relPos.z -snowlevel) ); } if ((tquality_level > 2) && (mix_flag == 1)) - { + { // Mix texture is material texture 15, which is mapped to the b channel of fg_textureLookup1 - int tex2 = int(fg_textureLookup1[lc].b * 255.0 + 0.5); - mix_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); + //int tex2 = int(fg_textureLookup1[lc].b * 255.0 + 0.5); + //mix_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); if (mix_texel.a < 0.1) { mix_flag = 0;} - } + //WS2: mix_texel = texture2D(mix_texture, gl_TexCoord[0].st * 1.3); // temp + + mix_texel = lookup_ground_texture_array(4, st * 1.3, lc, dxdy * 1.3); + if (mix_texel.a <0.1) {mix_flag = 0;} + } if (tquality_level > 3 && (flag == 1)) { @@ -417,9 +420,13 @@ float noise_2000m = Noise3D(worldPos.xyz, 2000.0); } // Detail texture is material texture 11, which is mapped to the g channel of fg_textureLookup1 - int tex3 = int(fg_textureLookup1[lc].g * 255.0 + 0.5); - detail_texel = texture(textureArray, vec3(stprime, tex3)); + //int tex3 = int(fg_textureLookup1[lc].g * 255.0 + 0.5); + //detail_texel = texture(textureArray, vec3(stprime, tex3)); if (detail_texel.a < 0.1) { flag = 0;} + //WS2: detail_texel = texture2D(detail_texture, stprime); // temp + + vec4 dxdy_prime = vec4(dFdx(stprime), dFdy(stprime)); + detail_texel = lookup_ground_texture_array(5, stprime, lc, dxdy_prime); } // texture preparation according to detail level @@ -505,18 +512,18 @@ if (quality_level > 3) texel = mix(texel, dust_color, clamp(0.5 * dust_cover_factor + 3.0 * dust_cover_factor * (((noise_1500m - 0.5) * 0.125)+0.125 ),0.0, 1.0) ); // mix snow - if (rawPos.z +500.0 > snowlevel) + if (relPos.z +500.0 > snowlevel) { snow_alpha = smoothstep(0.75, 0.85, abs(steepness)); //texel = mix(texel, snow_texel, texel_snow_fraction); - texel = mix(texel, snow_texel, snow_texel.a* smoothstep(snowlevel, snowlevel+200.0, snow_alpha * (rawPos.z)+ (noise_2000m + 0.1 * noise_10m -0.55) *400.0)); + texel = mix(texel, snow_texel, snow_texel.a* smoothstep(snowlevel, snowlevel+200.0, snow_alpha * (relPos.z)+ (noise_2000m + 0.1 * noise_10m -0.55) *400.0)); } } -else if (rawPos.z +500.0 > snowlevel) +else if (relPos.z +500.0 > snowlevel) { - float snow_alpha = 0.5+0.5* smoothstep(0.2,0.8, 0.3 + snow_thickness_factor +0.0001*(rawPos.z -snowlevel) ); + float snow_alpha = 0.5+0.5* smoothstep(0.2,0.8, 0.3 + snow_thickness_factor +0.0001*(relPos.z -snowlevel) ); // texel = vec4(dot(vec3(0.2989, 0.5870, 0.1140), texel.rgb)); - texel = mix(texel, vec4(1.0), snow_alpha* smoothstep(snowlevel, snowlevel+200.0, (rawPos.z))); + texel = mix(texel, vec4(1.0), snow_alpha* smoothstep(snowlevel, snowlevel+200.0, (relPos.z))); } diff --git a/Shaders/ws30-ALS-detailed.vert b/Shaders/ws30-ALS-detailed.vert index 0eb906e96..ec0bea957 100644 --- a/Shaders/ws30-ALS-detailed.vert +++ b/Shaders/ws30-ALS-detailed.vert @@ -25,7 +25,8 @@ attribute vec2 orthophotoTexCoord; varying vec4 light_diffuse_comp; varying vec3 normal; varying vec3 relPos; -varying vec3 rawPos; +varying vec2 ground_tex_coord; +varying vec2 rawPos; varying vec3 worldPos; //varying vec2 orthoTexCoord; varying vec4 eyePos; @@ -95,7 +96,7 @@ void main() float vertex_alt; float scattering; - rawPos = (fg_zUpTransform * gl_Vertex).xyz; + rawPos = (fg_zUpTransform * gl_Vertex).xy; worldPos = fg_modelOffset + gl_Vertex.xyz; eyePos = gl_ModelViewMatrix * gl_Vertex; steepness = dot(normalize(vec3(fg_zUpTransform * vec4(gl_Normal,1.0))), vec3 (0.0, 0.0, 1.0)); @@ -110,6 +111,9 @@ void main() normal = gl_NormalMatrix * gl_Normal; //nvec = (gl_NormalMatrix * gl_Normal).xy; + // Temporary value: + ground_tex_coord = gl_TexCoord[0].st; + // here start computations for the haze layer // we need several geometrical quantities @@ -126,7 +130,7 @@ void main() 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(rawPos.z,100.0); + vertex_alt = max(relPos.z,100.0); scattering = ground_scattering + (1.0 - ground_scattering) * smoothstep(hazeLayerAltitude -100.0, hazeLayerAltitude + 100.0, vertex_alt); diff --git a/Shaders/ws30-ALS-landclass-search-functions.frag b/Shaders/ws30-ALS-landclass-search-functions.frag index 4fb579074..deb9ac580 100644 --- a/Shaders/ws30-ALS-landclass-search-functions.frag +++ b/Shaders/ws30-ALS-landclass-search-functions.frag @@ -110,7 +110,7 @@ // Enable large scale transitions: 1=on, 0=off // Disable use landclass texel scale transition, if using this. - const int enable_large_scale_transition_search = 0; + const int enable_large_scale_transition_search = 1; // The search pattern is center + n points in four directions forming a cross. @@ -124,7 +124,7 @@ // Note: transitions occur on both sides of the landclass borders. // The width of the transition is equal to 2x this value. // Default: 100m - const float transition_search_distance_in_m = 100.0; + const float transition_search_distance_in_m = 130.0; // Number of points to search in any direction, in addition to this fragment // Default:4 points. Fewer points results in a less smooth transition (more banding) @@ -158,7 +158,7 @@ // This works by changing the weighting in the transition region using a // noise lookup // Possibe values: 0=off, 1=on. Default:0 - const int grow_landclass_borders_with_large_scale_transition = 0; + const int grow_landclass_borders_with_large_scale_transition = 1; @@ -181,7 +181,7 @@ // Possible values: 0 = texture source, 1 = math source // The texture source still shows some tiling. The math source detiles better, but might // be slightly slower. - const int detiling_noise_type = 0; + const int detiling_noise_type = 1; // Development tools - 2 controls, now located at the top of WS30-ALS-ultra.frag: // 1. Reduce haze to almost zero, while preserving lighting. Useful for observing distant tiles. @@ -190,6 +190,15 @@ // Useful for checking texture rendering and scenery. // The compiler will likely optimise out the haze and lighting calculations. // + +// Debugging: ground texture array lookup function +// Possible values: +// 0: Normal: TextureGrad() with partial derivatives. GLSL 1.30. +// 1: textureLod() using partial derivatives to manually calculate LoD. GLSL 1.20 +// 2: texture() without partial derivatives. GLSL 1.20 + const int tex_lookup_type = 0; + +// // End of test phase controls ////////////////////////////////////////////////////////////////// @@ -225,6 +234,7 @@ // Uniforms used by landclass search functions. // If any uniforms change name or form, remember to update here and in fragment shaders. + uniform sampler2D landclass; uniform sampler2DArray textureArray; uniform sampler2D perlin; @@ -253,6 +263,33 @@ vec2 tile_size = vec2(fg_tileHeight , fg_tileWidth); float rand2D(in vec2 co); float Noise2D(in vec2 coord, in float wavelength); +// Generates a full precision 32 bit random number from 2 seeds +// as well as 6 random integers between 0 and factor that are rescaled 0.0-1.0 +// by re-using the significant figures from the full precision number. +// This avoids having to generate 6 random numbers when +// limited variation is needed: say 6 numbers with 100 levels (i.e between 0 and 100). +// Seed 2 is incremented so the function can be called again to generate +// a different set of numbers +float get6_rand_nums(in float PRNGseed1, inout float PRNGseed2, float factor, out float [6] random_integers) +{ + + float r = fract(sin(dot(vec2(PRNGseed1,PRNGseed2),vec2(12.9898,78.233))) * 43758.5453); + + // random number left over after extracting some decimal places + float rlo = r; + // To look at: can this be made simd friendly? + for (int i=0;i<6;i++) + { + rlo = (rlo*factor); + random_integers[i] = floor(rlo)/factor; + rlo = fract(rlo); + } + + PRNGseed2+=1.0; + return r; +} + + // Create random landclasses without a texture lookup to stress test. // Each square of square_size in m is assigned a random landclass value. int get_random_landclass(in vec2 co, in vec2 tile_size) @@ -263,17 +300,32 @@ int get_random_landclass(in vec2 co, in vec2 tile_size) } -// Look up texture coordinates and stretching scale of ground textures -void get_ground_texture_data(in int lc, in vec2 tile_coord, - out vec2 st, out vec2 g_texture_scale, inout vec2 dx, inout vec2 dy) +/* +// Look up stretching scale of ground textures for the base texture. +// Note terrain default effect only has controls for the texture stretching dimensions for the base texture. +// Non-base textures use hardcoded stretching of the ground texture coords, which are in units of meters. +vec2 get_ground_texture_scale(in int lc) { // Look up stretching dimensions of ground textures in m - scaled to // fit in [0..1], so rescale vec2 g_texture_stretch_dim = fg_dimensionsArray[lc].st; - g_texture_scale = tile_size.xy / g_texture_stretch_dim.xy; + return (tile_size.xy / g_texture_stretch_dim.xy); +} +*/ + + +// Look up texture coordinates and stretching scale of ground textures for the base texture. +// Note terrain default effect only has controls for the texture stretching dimensions for the base texture. +// Non-base textures use hardcoded stretching of the ground texture coords, which are in units of meters. +void get_ground_texture_data(in int lc, in vec2 tile_coord, + out vec2 st, out vec2 g_texture_scale, inout vec4 dFdx_and_dFdy) +{ + // Look up stretching dimensions of ground textures in m - scaled to + // fit in [0..1], so rescale + vec2 g_texture_stretch_dim = fg_dimensionsArray[lc].st; + g_texture_scale = tile_size.xy / g_texture_stretch_dim.xy; // Correct partial derivatives to account for stretching of different textures - dx = dx * g_texture_scale; - dy = dy * g_texture_scale; + dFdx_and_dFdy = dFdx_and_dFdy * vec4(g_texture_scale.st, g_texture_scale.st); // Ground texture coords st = g_texture_scale * tile_coord.st; } @@ -284,10 +336,12 @@ void get_ground_texture_data(in int lc, in vec2 tile_coord, // Testing: if this or get_ground_texture_data used in final WS3 to handle // many base texture lookups, see if optimising to handle many inputs helps // (vectorising Noise2D versus just many texture calls) - +// To do: adjust for non-tile based ground coords. vec2 detile_texcoords_with_perlin_noise(in vec2 st, in vec2 ground_texture_scale, - in vec2 tile_coord, inout vec2 dx, inout vec2 dy) + in vec2 tile_coord, inout vec4 dFdx_and_dFdy) { + vec4 dxdy = dFdx_and_dFdy; + vec2 pnoise; // Ratio tile dimensions are stretched relative to s. @@ -315,21 +369,25 @@ vec2 detile_texcoords_with_perlin_noise(in vec2 st, in vec2 ground_texture_scale if (pnoise[0] >= 0.5) { + // To do: fix once ground coords are no longer tile based st = ground_texture_scale.st * (tile_coord * stretch_r).ts; // Get back original partial derivatives by undoing // previous texture stretching adjustment done in get_ground_data - dx = dx / ground_texture_scale.st; - dy = dy / ground_texture_scale.st; + dxdy = dxdy / vec4(ground_texture_scale.st, ground_texture_scale.st); + // Recalculate new derivatives - dx = dx.ts * ground_texture_scale.st * stretch_r.ts; - dy = dy.ts * ground_texture_scale.st * stretch_r.ts; + vec2 factor = ground_texture_scale.st * stretch_r.ts; + dxdy.st = dxdy.ts * factor; + dxdy.pq = dxdy.qp * factor; } if (pnoise[1] >= 0.5) { - st = -st; dx = -dx; dy = -dy; + st = -st; dxdy = -dxdy; } + + dFdx_and_dFdy = dxdy; return st; } @@ -339,35 +397,127 @@ vec2 detile_texcoords_with_perlin_noise(in vec2 st, in vec2 ground_texture_scale // The partial derivatives of the tile_coord at the fragment is needed to adjust for // the stretching of different textures, so that the correct mip-map level is looked // up and there are no seams. +// Texture types: 0: base texture, 1: grain texture, 2: gradient texture, 3 dot texture, +// 4: mix texture, 5: detail texture. -vec4 lookup_ground_texture_array(in vec2 tile_coord, in int landclass_id, - in vec2 dx, in vec2 dy) +vec4 lookup_ground_texture_array(in int texture_type, in vec2 ground_texture_coord, in int landclass_id, + in vec4 dFdx_and_dFdy) { // Testing: may be able to save 1 or 2 op slots by combining dx/dy in a vec4 and // using swizzles which are free, but mostly operations are working independenly on s and t. // Only 1 place so far that just multiplies everything by a scalar. vec2 st; + vec2 g_tex_coord = ground_texture_coord; vec2 g_texture_scale; vec4 texel; int lc = landclass_id; + vec4 dxdy = dFdx_and_dFdy; + + // Find the index of the specified texture type (e.g. mix or gradient texture ) in + // the ground texture lookup array. + // Since texture_type is a constant in the fragment shader, there should be no performance hit for branching. - get_ground_texture_data(lc, tile_coord, st, g_texture_scale, dx, dy); + int tex_idx = 0; + int type = texture_type; + + // Index for the base texture is contained fg_textureLookup1[lc].r + if (type == 0) tex_idx = int(uint(fg_textureLookup1[lc].r * 255.0 + 0.5)); + + // Grain texture is material texture slot 14, the index of which is mapped to the r channel of fg_textureLookup2 + else if (type == 1) tex_idx = int(fg_textureLookup2[lc].r * 255.0 + 0.5); + + // Gradient texture is material texture 13, the index of which is mapped to the a channel of fg_textureLookup1 + else if (type == 2) tex_idx = int(fg_textureLookup1[lc].a * 255.0 + 0.5); + + // Dot texture is material texture 15, the index of which is mapped to the g channel of fg_textureLookup2 + else if (type == 3) tex_idx = int(fg_textureLookup2[lc].g * 255.0 + 0.5); + + // Mix texture is material texture 12, the index of which is mapped to the b channel of fg_textureLookup1 + else if (type == 4) tex_idx = int(fg_textureLookup1[lc].b * 255.0 + 0.5); + + // Detail texture is material texture 11, the index of which is mapped to the g channel of fg_textureLookup1 + else if (type == 5) tex_idx = int(fg_textureLookup1[lc].g * 255.0 + 0.5); - st = detile_texcoords_with_perlin_noise(st, g_texture_scale, tile_coord, dx, dy); + if (type == 0) + { + // Scale normalised tile coords by stretching factor, and get info + vec2 tile_coord = g_tex_coord; + get_ground_texture_data(lc, tile_coord, st, g_texture_scale, dxdy); + st = detile_texcoords_with_perlin_noise(st, g_texture_scale, tile_coord, dxdy); + } + else + { + st = g_tex_coord; + } - //texel = texture(textureArray, vec3(st, lc)); - //texel = textureLod(textureArray, vec3(st, lc), 12.0); - uint tex1 = uint(fg_textureLookup1[lc].r * 255.0 + 0.5); - texel = textureGrad(textureArray, vec3(st, tex1), dx, dy); + + // Debugging: multiple texture lookup functions if there are issues + // with old GPUs and compilers. + if (tex_lookup_type == 0) + { + texel = textureGrad(textureArray, vec3(st, tex_idx), dxdy.st, dxdy.pq); + } + else if (tex_lookup_type == 1) + { + float lod = max(length(dxdy.sp), length(dxdy.tq)); + lod = log2(lod); + texel = textureLod(textureArray, vec3(st, tex_idx), lod); + } + else texel = texture(textureArray, vec3(st, tex_idx)); + + + //texel = textureGrad(textureArray, vec3(st, tex_idx), dxdy.st, dxdy.pq); return texel; } + +// Look up the texel of the specified texture type (e.g. grain or detail textures) for this fragment +// and any neighbor texels, then mix. + +vec4 get_mixed_texel(in int texture_type, in vec2 g_texture_coord, + in int landclass_id, in int num_unique_neighbors, + in ivec4 neighbor_texel_landclass_ids, in vec4 neighbor_mix_factors, + in vec4 dFdx_and_dFdy + ) +{ + vec2 st = g_texture_coord; + int lc = landclass_id; + ivec4 lc_n = neighbor_texel_landclass_ids; + // Not implemented yet + int type = texture_type; + vec4 dxdy = dFdx_and_dFdy; + vec4 mfact = neighbor_mix_factors; + + vec4 texel = lookup_ground_texture_array(0, st, lc, dxdy); + + + // Mix texels - to work consistently it needs a more preceptual interpolation than mix() + if (num_unique_neighbors != 0) + { + // Closest neighbor landclass + vec4 texel_closest = lookup_ground_texture_array(0, st, lc_n[0], dxdy); + + // Neighbor contributions + vec4 texel_nc=texel_closest; + + if (num_unique_neighbors > 1) + { + // 2nd Closest neighbor landclass + vec4 texel_2nd_closest = lookup_ground_texture_array(0, st, lc_n[1], dxdy); + + texel_nc = mix(texel_closest, texel_2nd_closest, mfact[1]); + } + + texel = mix(texel, texel_nc, mfact[0]); + } + return texel; +} + + // Landclass sources: texture or random int read_landclass_id(in vec2 tile_coord) { - vec2 dx = dFdx(tile_coord.st); - vec2 dy = dFdy(tile_coord.st); int lc; if (landclass_source == 0) lc = (int(texture2D(landclass, tile_coord.st).g * 255.0 + 0.5)); @@ -411,13 +561,14 @@ float get_growth_priority(in int current_landclass, in int neighbor_landclass1, } - -int lookup_landclass_id(in vec2 tile_coord, in vec2 dx, in vec2 dy, +int lookup_landclass_id(in vec2 tile_coord, in vec4 dFdx_and_dFdy, out ivec4 neighbor_texel_landclass_ids, out int number_of_unique_neighbors_found, out vec4 landclass_neighbor_texel_weights) { - // To do: fix landclass border artifacts, with all shaders. do small scale texel mixing for 2 neighbors + // To do: fix landclass border artifacts, with all shaders. + + vec4 dxdy = dFdx_and_dFdy; // Number of unique neighbours found int num_n = 0; @@ -622,7 +773,9 @@ if (remove_squareness_from_landclass_texture == 1) // Turn neighbor growth off at longer ranges, otherwise there is flickering noise // Testing: The exact cutoff could be done sooner to save some performance - needs // to be part of a larger solution to similar issues. User should set a tolerance factor. - float lod_factor = min(length(vec2(dx.s, dy.s)),length(vec2(dx.t, dy.t))); + // Effectively: lod_factor = min(length(vec2(dFdx(..).s, dFdy(..).s)),length(vec2(dFdx(..).t, dFdy(..).t))); + float lod_factor = min(length(vec2(dxdy.s, dxdy.p)),length(vec2(dxdy.t, dxdy.q))); + // Estimate of frequency of growth noise in texels - i.e. how many peaks and troughs fit in one texel const float frequency_g_n = 1000.0; const float cutoff = 1.0/frequency_g_n; @@ -732,19 +885,20 @@ if ( (use_landclass_texel_scale_transition_only == 1) && // Searches are performed in upto 4 directions right now, but only one landclass is looked up // Create a mix factor werighting the influences of nearby landclasses -void get_landclass_id(in vec2 tile_coord, - const in float landclass_texel_size_m, in vec2 dx, in vec2 dy, +void get_landclass_id(in vec2 tile_coord, in vec4 dFdx_and_dFdy, out int landclass_id, out ivec4 neighbor_landclass_ids, out int num_unique_neighbors,out vec4 mix_factor ) + { // Each tile has 1 texture containing landclass ids stetched over it // Landclass source type: 0=texture, 1=random squares - // Controls are defined at global scope. const int landclass_source - float ts = landclass_texel_size_m; + // Controls are defined at global scope. vec2 sz = tile_size; + vec4 dxdy = dFdx_and_dFdy; + // Number of unique neighbors found int num_n = 0; @@ -756,7 +910,7 @@ void get_landclass_id(in vec2 tile_coord, // Number of unique neighbors in neighboring texels int num_n_tx = 0; - int lc = lookup_landclass_id(tile_coord, dx, dy, lc_n_tx, num_n_tx, lc_n_w); + int lc = lookup_landclass_id(tile_coord, dxdy, lc_n_tx, num_n_tx, lc_n_w); // Neighbor landclass ids ivec4 lc_n = ivec4(lc); @@ -818,6 +972,11 @@ if ( (enable_large_scale_transition_search == 1) && // landclass. + // Testing: breaking the loop once the closest neighbour is found + // results in very slightly lower FPS on a 10 series GPU for 100m search + // distance and 4 points. May be faster on old GPUs with slow caching. + + // +s direction vec2 dir = vec2(steps.s, 0.0); @@ -982,7 +1141,7 @@ if (grow_landclass_borders_with_large_scale_transition == 1) // Decide whether to extrude furthest neighbor or closest neighbor onto lc float grow_n1 = get_growth_priority(lc_n[0],lc_n[1]); - mfact[1] = mfact[1]+((grow_n > 0.0)?neighbor_growth_mixf:+neighbor_growth_mixf); + mfact[1] = mfact[1]+((grow_n > 0.0)?neighbor_growth_mixf:-neighbor_growth_mixf); mfact[1] = clamp(mfact[1],0.0,1.0); diff --git a/Shaders/ws30-ALS-ultra.frag b/Shaders/ws30-ALS-ultra.frag index 3e174814a..593fab158 100644 --- a/Shaders/ws30-ALS-ultra.frag +++ b/Shaders/ws30-ALS-ultra.frag @@ -22,6 +22,16 @@ // Possible values: 0:Normal, 1:Just the texture. const int remove_haze_and_lighting = 0; +// Randomise texture lookups for 5 non-base textures e.g. mix_texture, detaile_texture etc. +// Each landclass is assigned 5 random textures from the ground texture array. +// This simulates a worst case possible texture lookup scenario, without needing access to material parameters. +// This does not simulate multiple texture sets, of which there may be up-to 4. +// The performance will likely be worse than in a real situation - there might be fewer textures +// for mix, detail and other textures. This might be easier on the GPUs texture caches. +// Possible values: 0: disabled (default), +// 1: enabled, +// 2: remove texture array lookups for 5 textures - only base texture + neighbour base textures + const int randomise_texture_lookups = 0; // // End of test phase controls ////////////////////////////////////////////////////////////////// @@ -43,8 +53,9 @@ varying vec4 light_diffuse_comp; varying vec3 normal; varying vec3 relPos; -varying vec3 rawPos; +varying vec2 ground_tex_coord; varying vec3 worldPos; +varying vec2 rawPos; // Testing code: //vec3 worldPos = vec3(5000.0, 6000.0, 7000.0) + vec3(vec2(rawPos), 600.0); // vec3(100.0, 10.0, 3.0); varying vec3 ecViewdir; @@ -89,7 +100,6 @@ uniform float osg_SimulationTime; uniform int wind_effects; uniform int cloud_shadow_flag; -uniform int rock_strata; uniform int use_searchlight; uniform int use_landing_light; uniform int use_alt_landing_light; @@ -100,12 +110,20 @@ uniform int swatch_size; //in metres, typically 1000 or 2000 uniform float fg_tileWidth; uniform float fg_tileHeight; uniform bool fg_photoScenery; -uniform vec4 fg_dimensionsArray[128]; +// Material parameters, from material definitions and effect defaults, for each landclass. +// xsize and ysize +uniform vec4 fg_dimensionsArray[128]; +// RGBA ambient color uniform vec4 fg_ambientArray[128]; -uniform vec4 fg_diffuseArray[128]; +// RGBA diffuse color +uniform vec4 fg_diffuseArray[128]; +// RGBA specular color uniform vec4 fg_specularArray[128]; +// Indicies of textures in the ground texture array for different +// texture slots (grain, gradient, dot, mix, detail) for each landclass uniform vec4 fg_textureLookup1[128]; uniform vec4 fg_textureLookup2[128]; +// Each element of a vec4 contains a different materials parameter. uniform vec4 fg_materialParams1[128]; uniform vec4 fg_materialParams2[128]; @@ -147,9 +165,9 @@ vec3 getClusteredLightsContribution(vec3 p, vec3 n, vec3 texel); float detail_fade (in float scale, in float angle, in float dist) { -float fade_dist = 2000.0 * scale * angle/max(pow(steepness,4.0), 0.1); - -return 1.0 - smoothstep(0.5 * fade_dist, fade_dist, dist); + float fade_dist = 2000.0 * scale * angle/max(pow(steepness,4.0), 0.1); + + return 1.0 - smoothstep(0.5 * fade_dist, fade_dist, dist); } ////////////////////////// @@ -159,15 +177,53 @@ return 1.0 - smoothstep(0.5 * fade_dist, fade_dist, dist); // These should be sent as uniforms // Tile dimensions in meters -// vec2 tile_size = vec2(tile_width , tile_height); +// vec2 tile_size = vec2(fg_tileWidth , fg_tileHeight); // Testing: texture coords are sent flipped right now: // Note tile_size is defined in the shader include: ws30-landclass-search-functions.frag. -// vec2 tile_size = vec2(tile_height , tile_width); +//vec2 tile_size = vec2(fg_tileHeight , fg_tileWidth); + + +// Uniform array lookup functions example: +// Access data[] as if it was a 1-d array of floats +// with data sorted as rows of data values for each row of texture variants +// using index for the relevant value +/* +float getFloatFromArrayData(int i) +{ + int n = int(floor(float(i/4.0))); + vec4 v4 = someArray[n]; + int index_within_v4 = int(mod(float(i),4.0)); + float value = v4[index_within_v4]; + return value; +} + + +vec4 getVec4FromArrayData(int i) +{ + return (vec4(getFloatFromArrayData(i), getFloatFromArrayData(i+1), getFloatFromArrayData(i+2), getFloatFromArrayData(i+3))); +} +*/ + + // From noise.frag float rand2D(in vec2 co); + +// Generates a full precision 32 bit random number from 2 seeds +// as well as 6 random integers between 0 and factor that are rescaled 0.0-1.0 +// by re-using the significant figures from the full precision number. +// This avoids having to generate 6 random numbers when +// limited variation is needed: say 6 numbers with 100 levels (i.e between 0 and 100). +// Seed 2 is incremented so the function can be called again to generate +// a different set of numbers +float get6_rand_nums(in float PRNGseed1, + inout float PRNGseed2, float factor, out float [6] random_integers + ); + + + // These functions, and other function they depend on, are defined // in ws30-ALS-landclass-search.frag. @@ -182,296 +238,292 @@ int get_random_landclass(in vec2 co, in vec2 tile_size); // The partial derivatives of the tile_coord at the fragment is needed to adjust for // the stretching of different textures, so that the correct mip-map level is looked // up and there are no seams. +// Texture types: 0: base texture, 1: grain texture, 2: gradient texture, 3 dot texture, +// 4: mix texture, 5: detail texture. -vec4 lookup_ground_texture_array(in vec2 tile_coord, in int landclass_id, - in vec2 dx, in vec2 dy); +vec4 lookup_ground_texture_array(in int texture_type, in vec2 ground_texture_coord, in int landclass_id, + in vec4 dFdx_and_dFdy); // Look up the landclass id [0 .. 255] for this particular fragment. // Lookup id of any neighbouring landclass that is within the search distance. // Searches are performed in upto 4 directions right now, but only one landclass is looked up // Create a mix factor werighting the influences of nearby landclasses -void get_landclass_id(in vec2 tile_coord, - const in float landclass_texel_size_m, in vec2 dx, in vec2 dy, +void get_landclass_id(in vec2 tile_coord, in vec4 dFdx_and_dFdy, out int landclass_id, out ivec4 neighbor_landclass_ids, out int num_unique_neighbors,out vec4 mix_factor ); +// Look up the texel of the specified texture type (e.g. grain or detail textures) for this fragment +// and any neighbor texels, then mix. + +vec4 get_mixed_texel(in int texture_type, in vec2 g_texture_coord, + in int landclass_id, in int num_unique_neighbors, + in ivec4 neighbor_texel_landclass_ids, in vec4 neighbor_mix_factors, + in vec4 dFdx_and_dFdy + ); + + // End Test-phase code //////////////////////// void main() { -float alt; - -yprime_alt = light_diffuse_comp.a; -//diffuse_term.a = 1.0; -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; -// float altitude of fragment above sea level -float msl_altitude = (relPos.z + eye_alt); - - -// vec3 shadedFogColor = vec3(0.65, 0.67, 0.78); + float alt; + + yprime_alt = light_diffuse_comp.a; + //diffuse_term.a = 1.0; + 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; + // float altitude of fragment above sea level + float msl_altitude = (relPos.z + eye_alt); + + + // vec3 shadedFogColor = vec3(0.65, 0.67, 0.78); vec3 shadedFogColor = vec3(0.55, 0.67, 0.88); // this is taken from default.frag vec3 n; float NdotL, NdotHV, fogFactor; vec3 lightDir = gl_LightSource[0].position.xyz; - vec3 halfVector = normalize(normalize(lightDir) + normalize(ecViewdir)); - + vec3 halfVector = normalize(normalize(lightDir) + normalize(ecViewdir)); + vec4 texel; - vec4 snow_texel; + vec4 snow_texel; vec4 detail_texel; vec4 mix_texel; - vec4 grain_texel; - vec4 dot_texel; - vec4 gradient_texel; - //vec4 foam_texel; - + vec4 grain_texel; + vec4 dot_texel; + vec4 gradient_texel; + //vec4 foam_texel; + vec4 fragColor; vec4 specular = vec4(0.0); float intensity; + + + + // Wind motion of the overlay noise simulating movement of vegetation and loose debris + + vec2 windPos; + + if (wind_effects > 1) + { + float windSpeed = length(vec2 (WindE,WindN)) /3.0480; + // interfering sine wave wind pattern + float sineTerm = sin(0.35 * windSpeed * osg_SimulationTime + 0.05 * (rawPos.x + rawPos.y)); + sineTerm = sineTerm + sin(0.3 * windSpeed * osg_SimulationTime + 0.04 * (rawPos.x + rawPos.y)); + sineTerm = sineTerm + sin(0.22 * windSpeed * osg_SimulationTime + 0.05 * (rawPos.x + rawPos.y)); + sineTerm = sineTerm/3.0; + // non-linear amplification to simulate gusts + sineTerm = sineTerm * sineTerm;//smoothstep(0.2, 1.0, sineTerm); + + // wind starts moving dust and leaves at around 8 m/s + float timeArg = 0.01 * osg_SimulationTime * windSpeed * smoothstep(8.0, 15.0, windSpeed); + timeArg = timeArg + 0.02 * sineTerm; + + windPos = vec2 (rawPos.x + WindN * timeArg, rawPos.y + WindE * timeArg); + } + else + { + windPos = rawPos.xy; + } + // get noise at different wavelengths in units of swatch_size + // original assumed 4km texture. + + // used: 5m, 5m gradient, 10m, 10m gradient: heightmap of the closeup terrain, 10m also snow + // 50m: detail texel + // 250m: detail texel + // 500m: distortion and overlay + // 1500m: overlay, detail, dust, fog + // 2000m: overlay, detail, snow, fog + + // Perlin noise + + float noise_10m = Noise2D(rawPos.xy, 10.0); + float noise_5m = Noise2D(rawPos.xy ,5.0); + float noise_2m = Noise2D(rawPos.xy ,2.0); + float noise_1m = Noise2D(rawPos.xy ,1.0); + float noise_01m = Noise2D(windPos.xy, 0.1); + + float noisegrad_10m; + float noisegrad_5m; + float noisegrad_2m; + float noisegrad_1m; + + // Noise relative to swatch size + + float noise_25m = Noise2D(rawPos.xy, swatch_size*0.000625); + float noise_50m = Noise2D(rawPos.xy, swatch_size*0.00125); + + + float noise_250m = Noise3D(worldPos.xyz,swatch_size*0.0625); + float noise_500m = Noise3D(worldPos.xyz, swatch_size*0.125); + float noise_1500m = Noise3D(worldPos.xyz, swatch_size*0.3750); + float noise_2000m = Noise3D(worldPos.xyz, swatch_size*0.5); + float noise_4000m = Noise3D(worldPos.xyz, swatch_size); -// Wind motion of the overlay noise simulating movement of vegetation and loose debris + //WS2: uniforms aren't looked up until later in WS3 + // dot noise + //float dotnoise_2m = DotNoise2D(rawPos.xy, 2.0 * dot_size,0.5, dot_density); + //float dotnoise_10m = DotNoise2D(rawPos.xy, 10.0 * dot_size, 0.5, dot_density); + //float dotnoise_15m = DotNoise2D(rawPos.xy, 15.0 * dot_size, 0.33, dot_density); + + float dotnoisegrad_10m; + -vec2 windPos; + // slope noise + + float slopenoise_50m = SlopeLines2D(rawPos.xy, grad_dir, 50.0, steepness); + float slopenoise_100m = SlopeLines2D(rawPos.xy, grad_dir, 100.0, steepness); + + float snownoise_25m = mix(noise_25m, slopenoise_50m, clamp(3.0*(1.0-steepness),0.0,1.0)); + float snownoise_50m = mix(noise_50m, slopenoise_100m, clamp(3.0*(1.0-steepness),0.0,1.0)); + + // get the texels + + -if (wind_effects > 1) - { - float windSpeed = length(vec2 (WindE,WindN)) /3.0480; - // interfering sine wave wind pattern - float sineTerm = sin(0.35 * windSpeed * osg_SimulationTime + 0.05 * (rawPos.x + rawPos.y)); - sineTerm = sineTerm + sin(0.3 * windSpeed * osg_SimulationTime + 0.04 * (rawPos.x + rawPos.y)); - sineTerm = sineTerm + sin(0.22 * windSpeed * osg_SimulationTime + 0.05 * (rawPos.x + rawPos.y)); - sineTerm = sineTerm/3.0; - // non-linear amplification to simulate gusts - sineTerm = sineTerm * sineTerm;//smoothstep(0.2, 1.0, sineTerm); - - // wind starts moving dust and leaves at around 8 m/s - float timeArg = 0.01 * osg_SimulationTime * windSpeed * smoothstep(8.0, 15.0, windSpeed); - timeArg = timeArg + 0.02 * sineTerm; - - windPos = vec2 (rawPos.x + WindN * timeArg, rawPos.y + WindE * timeArg); - } -else - { - windPos = rawPos.xy; - } - - -// get noise at different wavelengths in units of swatch_size -// original assumed 4km texture. - -// used: 5m, 5m gradient, 10m, 10m gradient: heightmap of the closeup terrain, 10m also snow -// 50m: detail texel -// 250m: detail texel -// 500m: distortion and overlay -// 1500m: overlay, detail, dust, fog -// 2000m: overlay, detail, snow, fog - -// Perlin noise - -float noise_10m = Noise2D(rawPos.xy, 10.0); -float noise_5m = Noise2D(rawPos.xy ,5.0); -float noise_2m = Noise2D(rawPos.xy ,2.0); -float noise_1m = Noise2D(rawPos.xy ,1.0); -float noise_01m = Noise2D(windPos.xy, 0.1); - -float noisegrad_10m; -float noisegrad_5m; -float noisegrad_2m; -float noisegrad_1m; - -// Noise relative to swatch size - -float noise_25m = Noise2D(rawPos.xy, swatch_size*0.000625); -float noise_50m = Noise2D(rawPos.xy, swatch_size*0.00125); - - -float noise_250m = Noise3D(worldPos.xyz,swatch_size*0.0625); -float noise_500m = Noise3D(worldPos.xyz, swatch_size*0.125); -float noise_1500m = Noise3D(worldPos.xyz, swatch_size*0.3750); -float noise_2000m = Noise3D(worldPos.xyz, swatch_size*0.5); -float noise_4000m = Noise3D(worldPos.xyz, swatch_size); - - -float dotnoisegrad_10m; - - -// slope noise - -float slopenoise_50m = SlopeLines2D(rawPos.xy, grad_dir, 50.0, steepness); -float slopenoise_100m = SlopeLines2D(rawPos.xy, grad_dir, 100.0, steepness); - -float snownoise_25m = mix(noise_25m, slopenoise_50m, clamp(3.0*(1.0-steepness),0.0,1.0)); -float snownoise_50m = mix(noise_50m, slopenoise_100m, clamp(3.0*(1.0-steepness),0.0,1.0)); - -// get the texels - - - - float distortion_factor = 1.0; - vec2 stprime; - int flag = 1; - int mix_flag = 1; - float noise_term; - float snow_alpha; + float distortion_factor = 1.0; + vec2 stprime; + int flag = 1; + int mix_flag = 1; + float noise_term; + float snow_alpha; // Oct 27 2021: // Geometry is in the form of roughly rectangular 'tiles' // with a mesh forming a grid with regular spacing. // Each vertex in the mesh is given an elevation - + // Tile dimensions in m // Testing: created from two float uniforms in global scope. Should be sent as a vec2 // vec2 tile_size - + // Tile texture coordinates range [0..1] over the tile 'rectangle' vec2 tile_coord = gl_TexCoord[0].st; + // Testing code: Coordinate used by ground texture arrays + //vec2 ground_tex_coord = gl_TexCoord[0].st; + // Test phase: Constants and toggles for transitions between landlcasses are defined at - // the top of this file. - + // the top landclass-search-functions.frag. + // There are some controls for haze and lighting at the top of this file. + // Look up the landclass id [0 .. 255] for this particular fragment // and any neighbouring landclass that is close. // Each tile has 1 texture containing landclass ids stetched over it. - + // Landclass for current fragment, and up-to 4 neighboring landclasses - 2 used currently int lc; ivec4 lc_n; - + int num_unique_neighbors = 0; - + // Mix factor of base textures for 2 neighbour landclass(es) vec4 mfact; - - - const float landclass_texel_size_m = 25.0; - - // Partial derivatives of s and t for this fragment, + + // Partial derivatives of s and t of ground texture coords for this fragment, // with respect to window (screen space) x and y axes. // Used to pick mipmap LoD levels, and turn off unneeded procedural detail - vec2 dx = dFdx(tile_coord); - vec2 dy = dFdy(tile_coord); - - get_landclass_id(tile_coord, landclass_texel_size_m, dx, dy, - lc, lc_n, num_unique_neighbors, mfact); - + // dFdx and dFdy are packed in a vec4 so multiplying everything + // to scale takes 1 instruction slot. + vec4 dxdy_gc = vec4(dFdx(ground_tex_coord) , dFdy(ground_tex_coord)); + + get_landclass_id(tile_coord, dxdy_gc, lc, lc_n, num_unique_neighbors, mfact); + + // The landclass id is used to index into arrays containing // material parameters and textures for the landclass as // defined in the regional definitions float index = float(lc)/512.0; vec4 index_n = vec4(lc_n)/512.0; - + float mat_shininess = fg_dimensionsArray[lc].z; vec4 mat_ambient = fg_ambientArray[lc]; vec4 mat_diffuse = fg_diffuseArray[lc]; vec4 mat_specular = fg_specularArray[lc]; - vec2 st = gl_TexCoord[0].st; // Testing code: // Use rlc even when looking up textures to recreate the extra performance hit // so any performance difference between the two is due to the texture lookup // color.rgb = color.rgb+0.00001*float(get_random_landclass(tile_coord.st, tile_size)); + + + // Look up ground textures by indexing into the texture array. + + // Calculate texture coords for ground textures + // Textures are stretched along the ground to different + // lengths along each axes as set by and + // regional definitions parameters. + vec2 stretch_dimensions = fg_dimensionsArray[lc].st; + vec2 tileSize = vec2(fg_tileWidth, fg_tileHeight); + vec2 texture_scaling = tileSize.yx / stretch_dimensions.st; + vec2 st = texture_scaling.st * ground_tex_coord.st; + + // Scale partial derivatives + vec4 dxdy = vec4(texture_scaling.st, texture_scaling.st) * dxdy_gc; + + if (fg_photoScenery) { // In the photoscenery case we don't have landclass or materials available, so we // just use constants for the material properties. mat_ambient = vec4(0.2,0.2,0.2,1.0); mat_diffuse = vec4(0.8,0.8,0.8,1.0); mat_specular = vec4(0.0,0.0,0.0,1.0); - - texel = texture(landclass, vec2(gl_TexCoord[0].s, 1.0 - gl_TexCoord[0].t)); - + mat_shininess = 1.2; + + // The photoscenery orthophots are stored in the landclass texture + // and use normalised tile coordinates + texel = texture(landclass, vec2(tile_coord.s, 1.0 - tile_coord.t)); + // Do not attempt any mixing flag = 0; mix_flag = 0; - } else { - // Color Mode is always AMBIENT_AND_DIFFUSE, which means - // using a base colour of white for ambient/diffuse, - // rather than the material color from ambientArray/diffuseArray. - mat_ambient = vec4(1.0,1.0,1.0,1.0); - mat_diffuse = vec4(1.0,1.0,1.0,1.0); - mat_specular = fg_specularArray[lc]; - mat_shininess = fg_dimensionsArray[lc].z; + } + else + { + + // Color Mode is always AMBIENT_AND_DIFFUSE, which means + // using a base colour of white for ambient/diffuse, + // rather than the material color from ambientArray/diffuseArray. + mat_ambient = vec4(1.0,1.0,1.0,1.0); + mat_diffuse = vec4(1.0,1.0,1.0,1.0); + mat_specular = fg_specularArray[lc]; + mat_shininess = fg_dimensionsArray[lc].z; - // Look up ground textures by indexing into the texture array. - // Different textures are stretched along the ground to different - // lengths along each axes as set by and - // regional definitions parameters - vec2 atlas_dimensions = fg_dimensionsArray[lc].st; - vec2 atlas_scale = vec2(fg_tileWidth / atlas_dimensions.s, fg_tileHeight / atlas_dimensions.t ); - st = atlas_scale * gl_TexCoord[0].st; + // Lookup the base texture texel for this fragment and any neighbors, with mixing + texel = get_mixed_texel(0, ground_tex_coord, lc, num_unique_neighbors, lc_n, mfact, dxdy_gc); - // Look up texture coordinates and scale of ground textures - - // Landclass for this fragment - - texel = lookup_ground_texture_array(tile_coord, lc, dx, dy); - - // Mix texels - to work consistently it needs a more preceptual interpolation than mix() - if (num_unique_neighbors != 0) - { - // Closest neighbor landclass - vec4 texel_closest = lookup_ground_texture_array(tile_coord, lc_n[0], dx, dy); - - // Neighbor contributions - vec4 texel_nc=texel_closest; - - if (num_unique_neighbors > 1) - { - // 2nd Closest neighbor landclass - vec4 texel_2nd_closest = lookup_ground_texture_array(tile_coord, lc_n[1], dx, dy); - - texel_nc = mix(texel_closest, texel_2nd_closest, mfact[1]); - } - - texel = mix(texel, texel_nc, mfact[0]); - } } - + vec4 color = gl_Color * mat_ambient; color.a = 1.0; - + // Testing code: mix with green to show values of variables at each point //vec4 green = vec4(0.0, 0.5, 0.0, 0.0); //texel = mix(texel, green, (mfact[2])); - // Mix texture is material texture 12, which is mapped to the b channel of fg_textureLookup1 - int tex2 = int(fg_textureLookup1[lc].b * 255.0 + 0.5); - mix_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); - if (mix_texel.a < 0.1) { mix_flag = 0;} - // Dot texture is material texture 15, which is mapped to the g channel of fg_textureLookup2 - tex2 = int(fg_textureLookup2[lc].g * 255.0 + 0.5); - dot_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); - // Detail texture is material texture 11, which is mapped to the g channel of fg_textureLookup1 - tex2 = int(fg_textureLookup1[lc].g * 255.0 + 0.5); - detail_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); - if (detail_texel.a < 0.1) { flag = 0;} - // Grain texture is material texture 14, which is mapped to the r channel of fg_textureLookup2 - tex2 = int(fg_textureLookup2[lc].r * 255.0 + 0.5); - grain_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); - - // Gradient texture is material texture 13, which is mapped to the a channel of fg_textureLookup1 - tex2 = int(fg_textureLookup1[lc].a * 255.0 + 0.5); - gradient_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); - - // Other material parameters, which are mapped to various channels from fg_materialParams1 and fg_materialParams2 + // Lookup material parameters for the landclass at this fragment. + // Material parameters are from material definitions XML files (e.g. regional definitions in data/Materials/regions). They have the same names. + // These parameters are contained in arrays of uniforms fg_materialParams1 and fg_materialParams2. + // The uniforms are vec4s, and each parameter is mapped to a vec4 element (rgba channels). + // In WS2 these parameters were available as uniforms of the same name. + // Testing: The mapping is hardcoded at the moment. float transition_model = fg_materialParams1[lc].r; float hires_overlay_bias = fg_materialParams1[lc].g; float grain_strength = fg_materialParams1[lc].b; @@ -480,66 +532,188 @@ float snownoise_50m = mix(noise_50m, slopenoise_100m, clamp(3.0*(1.0-steepness), float dot_density = fg_materialParams2[lc].r; float dot_size = fg_materialParams2[lc].g; float dust_resistance = fg_materialParams2[lc].b; - float rock_strata = fg_materialParams2[lc].a; + int rock_strata = int(fg_materialParams2[lc].a); // dot noise float dotnoise_2m = DotNoise2D(rawPos.xy, 2.0 * dot_size,0.5, dot_density); float dotnoise_10m = DotNoise2D(rawPos.xy, 10.0 * dot_size, 0.5, dot_density); float dotnoise_15m = DotNoise2D(rawPos.xy, 15.0 * dot_size, 0.33, dot_density); - // Testing: WS2 code after this - float local_autumn_factor = texel.a; + // Testing code - set randomise_texture_lookups = 2 to only look up the base texture with no extra transitions. + detail_texel = texel; + mix_texel = texel; + grain_texel = texel; + dot_texel = texel; + gradient_texel = texel; - - // we need to fade procedural structures when they get smaller than a single pixel, for this we need - // to know under what angle we see the surface - - float view_angle = abs(dot(normalize(normal), normalize(ecViewdir))); - float sfactor = sqrt(2.0 * (1.0-steepness)/0.03) + abs(ct)/0.15; +/* + // Texture lookup testing code: + // To test this block, uncomment it and turn off normal and random texture lookups + // by setting randomise_texture_lookups = 2 or more. + + int tex2; - // the snow texel is generated procedurally - if (msl_altitude +500.0 > snowlevel) - { - snow_texel = vec4 (0.95, 0.95, 0.95, 1.0) * (0.9 + 0.1* noise_500m + 0.1* (1.0 - noise_10m) ); - snow_texel.r = snow_texel.r * (0.9 + 0.05 * (noise_10m + noise_5m)); - snow_texel.g = snow_texel.g * (0.9 + 0.05 * (noise_10m + noise_5m)); - snow_texel.a = 1.0; - noise_term = 0.1 * (noise_500m-0.5) ; - noise_term = noise_term + 0.2 * (snownoise_50m -0.5) * detail_fade(50.0, view_angle, 0.5*dist) ; - noise_term = noise_term + 0.2 * (snownoise_25m -0.5) * detail_fade(25.0, view_angle, 0.5*dist) ; - noise_term = noise_term + 0.3 * (noise_10m -0.5) * detail_fade(10.0, view_angle, 0.8*dist) ; - noise_term = noise_term + 0.3 * (noise_5m - 0.5) * detail_fade(5.0, view_angle, dist); - noise_term = noise_term + 0.15 * (noise_2m -0.5) * detail_fade(2.0, view_angle, dist); - noise_term = noise_term + 0.08 * (noise_1m -0.5) * detail_fade(1.0, view_angle, dist); - snow_texel.a = snow_texel.a * 0.2+0.8* smoothstep(0.2,0.8, 0.3 +noise_term + snow_thickness_factor +0.0001*(msl_altitude -snowlevel) ); - } + // Grain texture is material texture 14, which is mapped to the r channel of fg_textureLookup2 + tex2 = int(fg_textureLookup2[lc].r * 255.0 + 0.5); + grain_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); + + // Gradient texture is material texture 13, which is mapped to the a channel of fg_textureLookup1 + tex2 = int(fg_textureLookup1[lc].a * 255.0 + 0.5); + gradient_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); + + // Dot texture is material texture 15, which is mapped to the g channel of fg_textureLookup2 + tex2 = int(fg_textureLookup2[lc].g * 255.0 + 0.5); + dot_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); - // the hires overlay texture is loaded with parallax mapping - - if (flag == 1) { - stprime = vec2 (0.86*gl_TexCoord[0].s + 0.5*gl_TexCoord[0].t, 0.5*gl_TexCoord[0].s - 0.86*gl_TexCoord[0].t); - distortion_factor = 0.97 + 0.06 * noise_500m; - stprime = stprime * distortion_factor * 15.0; - stprime = stprime + normalize(relPos).xy * 0.022 * (noise_10m + 0.5 * noise_5m +0.25 * noise_2m - 0.875 ); - - //detail_texel = texture2D(detail_texture, stprime); // temp - } + // Mix texture is material texture 12, which is mapped to the b channel of fg_textureLookup1 + tex2 = int(fg_textureLookup1[lc].b * 255.0 + 0.5); + mix_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); + if (mix_texel.a < 0.1) { mix_flag = 0;} // Disable if no index found + + // Detail texture is material texture 11, which is mapped to the g channel of fg_textureLookup1 + tex2 = int(fg_textureLookup1[lc].g * 255.0 + 0.5); + detail_texel = texture(textureArray, vec3(gl_TexCoord[0].st * 1.3, tex2)); + if (detail_texel.a < 0.1) { flag = 0;} // Disable if no index found + + //Examples of how lookup_ground_texture array is used with the above grain/gradient texture lookups: + //grain_texel = lookup_ground_texture_array(1, st * 1.3, lc, dxdy * 1.3); + //gradient_texel = lookup_ground_texture_array(2, st * 1.3, lc, dxdy * 1.3); +*/ -// texture preparation according to detail level -// mix in hires texture patches + // Generate 6 random numbers + + float pseed2 = 1.0; + int tex_id_lc[6]; + float rn[6]; + if (randomise_texture_lookups == 1) + { + + get6_rand_nums(float(lc)*33245.31, pseed2, 47.0, rn); + for (int i=0;i<6;i++) tex_id_lc[i] = int(mod( (float(lc)+(rn[i]*47.0)+1.0) , 48.0)); + } + + //texel = mix(vec4(vec3(0.0),1.0), vec4(0.0,0.5,0.0,1.0), float(tex_id_lc[2])/48.0); + + // WS2: + //grain_texel = texture2D(grain_texture, gl_TexCoord[0].st * 25.0); + //gradient_texel = texture2D(gradient_texture, gl_TexCoord[0].st * 4.0); + //stprime = gl_TexCoord[0].st * 80.0; + //stprime = stprime + normalize(relPos).xy * 0.01 * (dotnoise_10m + dotnoise_15m); + //dot_texel = texture2D(dot_texture, vec2 (stprime.y, stprime.x) ); + -float dist_fact; -float nSum; -float mix_factor; + if (randomise_texture_lookups == 0) + { + grain_texel = lookup_ground_texture_array(1, st * 25.0, lc, dxdy * 25.0); + gradient_texel = lookup_ground_texture_array(2, st * 4.0, lc, dxdy * 4.0); + } + else if (randomise_texture_lookups == 1) + { + grain_texel = lookup_ground_texture_array(0, st * 25.0, tex_id_lc[0], dxdy * 25.0); + gradient_texel = lookup_ground_texture_array(0, st * 4.0, tex_id_lc[1], dxdy * 4.0); + } + + stprime = st * 80.0; + stprime = stprime + normalize(relPos).xy * 0.01 * (dotnoise_10m + dotnoise_15m); + vec4 dxdy_prime = vec4(dFdx(stprime), dFdy(stprime)); + + if (randomise_texture_lookups == 0) + { + dot_texel = lookup_ground_texture_array(3, stprime.ts, lc, dxdy_prime.tsqp); + } + else if (randomise_texture_lookups == 1) + { + dot_texel = lookup_ground_texture_array(0, stprime.ts, tex_id_lc[2], dxdy_prime.tsqp); + } + + // Testing: WS2 code after this, except for random texture lookups and partial derivatives + + float local_autumn_factor = texel.a; + // we need to fade procedural structures when they get smaller than a single pixel, for this we need + // to know under what angle we see the surface + + float view_angle = abs(dot(normalize(normal), normalize(ecViewdir))); + float sfactor = sqrt(2.0 * (1.0-steepness)/0.03) + abs(ct)/0.15; + + + // the snow texel is generated procedurally + if (msl_altitude +500.0 > snowlevel) + { + snow_texel = vec4 (0.95, 0.95, 0.95, 1.0) * (0.9 + 0.1* noise_500m + 0.1* (1.0 - noise_10m) ); + snow_texel.r = snow_texel.r * (0.9 + 0.05 * (noise_10m + noise_5m)); + snow_texel.g = snow_texel.g * (0.9 + 0.05 * (noise_10m + noise_5m)); + snow_texel.a = 1.0; + noise_term = 0.1 * (noise_500m-0.5) ; + noise_term = noise_term + 0.2 * (snownoise_50m -0.5) * detail_fade(50.0, view_angle, 0.5*dist) ; + noise_term = noise_term + 0.2 * (snownoise_25m -0.5) * detail_fade(25.0, view_angle, 0.5*dist) ; + noise_term = noise_term + 0.3 * (noise_10m -0.5) * detail_fade(10.0, view_angle, 0.8*dist) ; + noise_term = noise_term + 0.3 * (noise_5m - 0.5) * detail_fade(5.0, view_angle, dist); + noise_term = noise_term + 0.15 * (noise_2m -0.5) * detail_fade(2.0, view_angle, dist); + noise_term = noise_term + 0.08 * (noise_1m -0.5) * detail_fade(1.0, view_angle, dist); + snow_texel.a = snow_texel.a * 0.2+0.8* smoothstep(0.2,0.8, 0.3 +noise_term + snow_thickness_factor +0.0001*(msl_altitude -snowlevel) ); + } + + + if (mix_flag == 1) + { + //WS2: mix_texel = texture2D(mix_texture, gl_TexCoord[0].st * 1.3); + + if (randomise_texture_lookups == 0) + { + mix_texel = lookup_ground_texture_array(4, st * 1.3, lc, dxdy * 1.3); + } + else if (randomise_texture_lookups == 1) + { + mix_texel = lookup_ground_texture_array(0, st * 1.3, tex_id_lc[3], dxdy * 1.3); + } + if (mix_texel.a <0.1) {mix_flag = 0;} + } + + // the hires overlay texture is loaded with parallax mapping + + if (flag == 1) + { + stprime = vec2 (0.86*st.s + 0.5*st.t, 0.5*st.s - 0.86*st.t); + distortion_factor = 0.97 + 0.06 * noise_500m; + stprime = stprime * distortion_factor * 15.0; + stprime = stprime + normalize(relPos).xy * 0.022 * (noise_10m + 0.5 * noise_5m +0.25 * noise_2m - 0.875 ); + + //WS2: detail_texel = texture2D(detail_texture, stprime); // temp + + dxdy_prime = vec4(dFdx(stprime), dFdy(stprime)); + if (randomise_texture_lookups == 0) + { + detail_texel = lookup_ground_texture_array(5, stprime , lc, dxdy_prime); + } + else if (randomise_texture_lookups == 1) + { + detail_texel = lookup_ground_texture_array(0, stprime, tex_id_lc[4], dxdy_prime); + } + if (detail_texel.a <0.1) {flag = 0;} + } // End if (flag == 1) + + + // texture preparation according to detail level + + // mix in hires texture patches + + float dist_fact; + float nSum; + float mix_factor; + // first the second texture overlay // transition model 0: random patch overlay without any gradient information // transition model 1: only gradient-driven transitions, no randomness - if (mix_flag == 1) { + + 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); @@ -547,192 +721,203 @@ float mix_factor; texel = mix(texel, mix_texel, mix_factor); local_autumn_factor = texel.a; } - + // then the detail texture overlay mix_factor = 0.0; - if ((flag == 1) && (dist < 40000.0)) { + //WS2: condition was broken up - does it matter for dynamic branching? + if ((flag == 1) && (dist < 40000.0)) + { dist_fact = 0.1 * smoothstep(15000.0,40000.0, dist) - 0.03 * (1.0 - smoothstep(500.0,5000.0, dist)); nSum = ((1.0 -noise_2000m) + noise_1500m + 2.0 * noise_250m +noise_50m)/5.0; nSum = nSum - 0.08 * (1.0 -smoothstep(0.9,0.95, abs(steepness))); mix_factor = smoothstep(0.47, 0.54, nSum +hires_overlay_bias- dist_fact); if (mix_factor > 0.8) {mix_factor = 0.8;} texel = mix(texel, detail_texel,mix_factor); - } - + } + // rock for very steep gradients - if (gradient_texel.a > 0.0) { + + 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))); local_autumn_factor = texel.a; } - // strata noise + // strata noise + + float stratnoise_50m; + float stratnoise_10m; - float stratnoise_50m; - float stratnoise_10m; - - if (rock_strata > 0.99) { + // Testing: if rock_strata parameter is not cast into int, need (rock_strata > 0.99) + if (rock_strata==1) + { stratnoise_50m = Strata3D(vec3 (rawPos.x, rawPos.y, msl_altitude), 50.0, 0.2); stratnoise_10m = Strata3D(vec3 (rawPos.x, rawPos.y, msl_altitude), 10.0, 0.2); stratnoise_50m = mix(stratnoise_50m, 1.0, smoothstep(0.8,0.9, steepness)); stratnoise_10m = mix(stratnoise_10m, 1.0, smoothstep(0.8,0.9, steepness)); texel *= (0.4 + 0.4 * stratnoise_50m + 0.2 * stratnoise_10m); } - - // 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)); - + + // 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 - -float autumn_factor = season * 2.0 * (1.0 - local_autumn_factor) ; + 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 + + float autumn_factor = season * 2.0 * (1.0 - local_autumn_factor) ; + + + texel.r = min(1.0, (1.0 + 2.5 * autumn_factor) * texel.r); + texel.g = texel.g; + texel.b = max(0.0, (1.0 - 4.0 * autumn_factor) * texel.b); -texel.r = min(1.0, (1.0 + 2.5 * autumn_factor) * texel.r); -texel.g = texel.g; -texel.b = max(0.0, (1.0 - 4.0 * autumn_factor) * texel.b); + if (local_autumn_factor < 1.0) + { + intensity = length(texel.rgb) * (1.0 - 0.5 * smoothstep(1.1,2.0,season)); + texel.rgb = intensity * normalize(mix(texel.rgb, vec3(0.23,0.17,0.08), smoothstep(1.1,2.0, season))); + } + // slope line overlay + texel.rgb = texel.rgb * (1.0 - 0.12 * slopenoise_50m - 0.08 * slopenoise_100m); + + //const vec4 dust_color = vec4 (0.76, 0.71, 0.56, 1.0); + const vec4 dust_color = vec4 (0.76, 0.65, 0.45, 1.0); + const vec4 lichen_color = vec4 (0.17, 0.20, 0.06, 1.0); + + // mix vegetation + float gradient_factor = smoothstep(0.5, 1.0, steepness); + texel = mix(texel, lichen_color, gradient_factor * (0.4 * lichen_cover_factor + 0.8 * lichen_cover_factor * 0.5 * (noise_10m + (1.0 - noise_5m))) ); + // 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; -if (local_autumn_factor < 1.0) - { - intensity = length(texel.rgb) * (1.0 - 0.5 * smoothstep(1.1,2.0,season)); - texel.rgb = intensity * normalize(mix(texel.rgb, vec3(0.23,0.17,0.08), smoothstep(1.1,2.0, season))); - } - - // slope line overlay - texel.rgb = texel.rgb * (1.0 - 0.12 * slopenoise_50m - 0.08 * slopenoise_100m); - -//const vec4 dust_color = vec4 (0.76, 0.71, 0.56, 1.0); -const vec4 dust_color = vec4 (0.76, 0.65, 0.45, 1.0); -const vec4 lichen_color = vec4 (0.17, 0.20, 0.06, 1.0); - -// mix vegetation -float gradient_factor = smoothstep(0.5, 1.0, steepness); -texel = mix(texel, lichen_color, gradient_factor * (0.4 * lichen_cover_factor + 0.8 * lichen_cover_factor * 0.5 * (noise_10m + (1.0 - noise_5m))) ); -// 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; - -if (msl_altitude +500.0 > snowlevel) - { - snow_alpha = smoothstep(0.75, 0.85, abs(steepness)); - snow_mix_factor = snow_texel.a* smoothstep(snowlevel, snowlevel+200.0, snow_alpha * msl_altitude+ (noise_2000m + 0.1 * noise_10m -0.55) *400.0); - texel = mix(texel, snow_texel, snow_mix_factor); - } + if (msl_altitude +500.0 > snowlevel) + { + snow_alpha = smoothstep(0.75, 0.85, abs(steepness)); + snow_mix_factor = snow_texel.a* smoothstep(snowlevel, snowlevel+200.0, snow_alpha * msl_altitude+ (noise_2000m + 0.1 * noise_10m -0.55) *400.0); + texel = mix(texel, snow_texel, snow_mix_factor); + } -// get distribution of water when terrain is wet + // 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; + 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; - water_threshold2 = 1.0 - 0.3 * combined_wetness; - water_factor = smoothstep(water_threshold1, water_threshold2 , (0.3 * (2.0 * (1.0-noise_10m) + (1.0 -noise_5m)) * (1.0 - smoothstep(2000.0, 5000.0, dist))) - 5.0 * (1.0 -steepness)); - } + if ((dist < 5000.0) && (combined_wetness>0.0)) + { + water_threshold1 = 1.0-0.5* combined_wetness; + water_threshold2 = 1.0 - 0.3 * combined_wetness; + water_factor = smoothstep(water_threshold1, water_threshold2 , (0.3 * (2.0 * (1.0-noise_10m) + (1.0 -noise_5m)) * (1.0 - smoothstep(2000.0, 5000.0, dist))) - 5.0 * (1.0 -steepness)); + } -// darken wet terrain + // darken wet terrain - texel.rgb = texel.rgb * (1.0 - 0.6 * combined_wetness); + texel.rgb = texel.rgb * (1.0 - 0.6 * combined_wetness); -// light computations + // light computations vec4 light_specular = gl_LightSource[0].specular; - // If gl_Color.a == 0, this is a back-facing polygon and the - // normal should be reversed. - //n = (2.0 * gl_Color.a - 1.0) * normal; - n = normal;//vec3 (nvec.x, nvec.y, sqrt(1.0 -pow(nvec.x,2.0) - pow(nvec.y,2.0) )); - n = normalize(n); + // If gl_Color.a == 0, this is a back-facing polygon and the + // normal should be reversed. + //n = (2.0 * gl_Color.a - 1.0) * normal; + n = normal;//vec3 (nvec.x, nvec.y, sqrt(1.0 -pow(nvec.x,2.0) - pow(nvec.y,2.0) )); + n = normalize(n); - NdotL = dot(n, lightDir); + NdotL = dot(n, lightDir); + + noisegrad_10m = (noise_10m - Noise2D(rawPos.xy+ 0.05 * normalize(lightDir.xy),10.0))/0.05; + noisegrad_5m = (noise_5m - Noise2D(rawPos.xy+ 0.05 * normalize(lightDir.xy),5.0))/0.05; + noisegrad_2m = (noise_2m - Noise2D(rawPos.xy+ 0.05 * normalize(lightDir.xy),2.0))/0.05; + noisegrad_1m = (noise_1m - Noise2D(rawPos.xy+ 0.05 * normalize(lightDir.xy),1.0))/0.05; + + dotnoisegrad_10m = (dotnoise_10m - DotNoise2D(rawPos.xy+ 0.05 * normalize(lightDir.xy),10.0 * dot_size,0.5, dot_density))/0.05; + + + NdotL = NdotL + (noisegrad_10m * detail_fade(10.0, view_angle,dist) + 0.5* noisegrad_5m * detail_fade(5.0, view_angle,dist)) * mix_factor/0.8; + NdotL = NdotL + 0.15 * noisegrad_2m * mix_factor/0.8 * detail_fade(2.0,view_angle,dist); + NdotL = NdotL + 0.1 * noisegrad_2m * detail_fade(2.0,view_angle,dist); + NdotL = NdotL + 0.05 * noisegrad_1m * detail_fade(1.0, view_angle,dist); + NdotL = NdotL + (1.0-snow_mix_factor) * 0.3* dot_texel.a * (0.5* dotnoisegrad_10m * detail_fade(1.0 * dot_size, view_angle, dist) +0.5 * dotnoisegrad_10m * noise_01m * detail_fade(0.1, view_angle, dist)) ; + + // Testing: Very temporary - reduce procedural normal map features with photoscenery active without breaking profiling as the controls are default (by request) + if (fg_photoScenery) NdotL = mix(dot(n, lightDir), NdotL, 0.00001); - noisegrad_10m = (noise_10m - Noise2D(rawPos.xy+ 0.05 * normalize(lightDir.xy),10.0))/0.05; - noisegrad_5m = (noise_5m - Noise2D(rawPos.xy+ 0.05 * normalize(lightDir.xy),5.0))/0.05; - noisegrad_2m = (noise_2m - Noise2D(rawPos.xy+ 0.05 * normalize(lightDir.xy),2.0))/0.05; - noisegrad_1m = (noise_1m - Noise2D(rawPos.xy+ 0.05 * normalize(lightDir.xy),1.0))/0.05; + if (NdotL > 0.0) + { + float shadowmap = getShadowing(); + if (cloud_shadow_flag == 1) {NdotL = NdotL * shadow_func(relPos.x, relPos.y, 0.3 * noise_250m + 0.5 * noise_500m+0.2 * noise_1500m, dist);} + vec4 diffuse_term = light_diffuse_comp * mat_diffuse; + color += diffuse_term * NdotL * shadowmap; + NdotHV = max(dot(n, halfVector), 0.0); + if (mat_shininess > 0.0) + specular.rgb = ((mat_specular.rgb * 0.1 + (water_factor * vec3 (1.0, 1.0, 1.0))) + * light_specular.rgb + * pow(NdotHV, mat_shininess + (20.0 * water_factor)) + * shadowmap); + } + color.a = 1.0;//diffuse_term.a; // as gl_Color.a and light_diffuse.comp.a were packed with other values + // This shouldn't be necessary, but our lighting becomes very + // saturated. Clamping the color before modulating by the texture + // is closer to what the OpenGL fixed function pipeline does. + color = clamp(color, 0.0, 1.0); - dotnoisegrad_10m = (dotnoise_10m - DotNoise2D(rawPos.xy+ 0.05 * normalize(lightDir.xy),10.0 * dot_size,0.5, dot_density))/0.05; + vec3 secondary_light = vec3 (0.0,0.0,0.0); - - NdotL = NdotL + (noisegrad_10m * detail_fade(10.0, view_angle,dist) + 0.5* noisegrad_5m * detail_fade(5.0, view_angle,dist)) * mix_factor/0.8; - NdotL = NdotL + 0.15 * noisegrad_2m * mix_factor/0.8 * detail_fade(2.0,view_angle,dist); - NdotL = NdotL + 0.1 * noisegrad_2m * detail_fade(2.0,view_angle,dist); - NdotL = NdotL + 0.05 * noisegrad_1m * detail_fade(1.0, view_angle,dist); - NdotL = NdotL + (1.0-snow_mix_factor) * 0.3* dot_texel.a * (0.5* dotnoisegrad_10m * detail_fade(1.0 * dot_size, view_angle, dist) +0.5 * dotnoisegrad_10m * noise_01m * detail_fade(0.1, view_angle, dist)) ; - - if (NdotL > 0.0) { - float shadowmap = getShadowing(); - if (cloud_shadow_flag == 1) {NdotL = NdotL * shadow_func(relPos.x, relPos.y, 0.3 * noise_250m + 0.5 * noise_500m+0.2 * noise_1500m, dist);} - vec4 diffuse_term = light_diffuse_comp * mat_diffuse; - color += diffuse_term * NdotL * shadowmap; - NdotHV = max(dot(n, halfVector), 0.0); - if (mat_shininess > 0.0) - specular.rgb = ((mat_specular.rgb * 0.1 + (water_factor * vec3 (1.0, 1.0, 1.0))) - * light_specular.rgb - * pow(NdotHV, mat_shininess + (20.0 * water_factor)) - * shadowmap); - } - color.a = 1.0;//diffuse_term.a; // as gl_Color.a and light_diffuse.comp.a were packed with other values - // This shouldn't be necessary, but our lighting becomes very - // saturated. Clamping the color before modulating by the texture - // is closer to what the OpenGL fixed function pipeline does. - color = clamp(color, 0.0, 1.0); - - vec3 secondary_light = vec3 (0.0,0.0,0.0); - - if (use_searchlight == 1) - { - secondary_light += searchlight(); - } - if (use_landing_light == 1) - { - secondary_light += landing_light(landing_light1_offset, landing_light3_offset); - } - if (use_alt_landing_light == 1) - { - secondary_light += landing_light(landing_light2_offset, landing_light3_offset); - } - color.rgb +=secondary_light * light_distance_fading(dist); + if (use_searchlight == 1) + { + secondary_light += searchlight(); + } + if (use_landing_light == 1) + { + secondary_light += landing_light(landing_light1_offset, landing_light3_offset); + } + if (use_alt_landing_light == 1) + { + secondary_light += landing_light(landing_light2_offset, landing_light3_offset); + } + 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); - 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); - fragColor.rgb = rayleigh_out_shift(fragColor.rgb,outscatter); - -// Rayleigh color shift due to in-scattering + // 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); + fragColor.rgb = rayleigh_out_shift(fragColor.rgb,outscatter); + // 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; @@ -741,179 +926,177 @@ if ((dist < 5000.0) && (combined_wetness>0.0)) fragColor.rgb = mix(fragColor.rgb, rayleighColor,rayleighStrength); -// here comes the terrain haze model - + // 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 + 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 { - distance_in_layer = dist; - vAltitude = min(distance_in_layer,mvisibility) * ct; - delta_zv = delta_z - vAltitude; + 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 may look through upper layer edge + 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) { - 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; + 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); } - } - 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); - - } - + + + // 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; + + + + // Testing phase controls: + if (remove_haze_and_lighting == 1) + { + gl_FragColor = texel; + } - -// Testing phase controls: -if (remove_haze_and_lighting == 1) -{ - gl_FragColor = texel; -} - } diff --git a/Shaders/ws30-ALS-ultra.vert b/Shaders/ws30-ALS-ultra.vert index 15b7bc6a0..2f5361c12 100644 --- a/Shaders/ws30-ALS-ultra.vert +++ b/Shaders/ws30-ALS-ultra.vert @@ -16,7 +16,6 @@ #define MODE_DIFFUSE 1 #define MODE_AMBIENT_AND_DIFFUSE 2 -//attribute vec2 orthophotoTexCoord; // The constant term of the lighting equation that doesn't depend on // the surface normal is passed in gl_{Front,Back}Color. The alpha @@ -25,11 +24,11 @@ varying vec4 light_diffuse_comp; varying vec3 normal; varying vec3 relPos; -varying vec3 rawPos; +varying vec2 ground_tex_coord; +varying vec2 rawPos; varying vec3 worldPos; varying vec3 ecViewdir; varying vec2 grad_dir; -//varying vec2 orthoTexCoord; varying vec4 ecPosition; // Sent packed into alpha channels @@ -76,227 +75,290 @@ 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)); + //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.55, 0.67, 0.88); vec3 moonLightColor = vec3 (0.095, 0.095, 0.15) * moonlight + vec3 (0.005, 0.005, 0.005); - + moonLightColor = moonlight_perception (moonLightColor); - - + + //float yprime_alt; float yprime; float lightArg; float intensity; float vertex_alt; float scattering; + + // The ALS code assumes that units are in meters - e.g. model space vertices (gl_Vertex) are in meters + + // WS30 model space, Nov 21, 2021: + // Coordinate axes are the same for geocentric, but not the origin. + // +z direction points from the Earth center to North pole. + // +x direction points from the Earth center to longitude = 0 on the equator. + // +y direction points from the Earth center to logntitude = East on the equator. + // Model space origin is at sea level. Units are in meters. + // Each tile, for each LoD level, its own model origin + // modelOffset is the model origin relative to the Earth center. It is in a geocentric + // space with the same axes, but with the Earth center as the origin. Units are in meters. - rawPos = (fg_zUpTransform * gl_Vertex).xyz; + + vec4 pos = gl_Vertex; + if (raise_vertex) + { + pos.z+=0.1; + gl_Position = gl_ModelViewProjectionMatrix * pos; + } + else gl_Position = ftransform(); + + + // this code is copied from default.vert + + ecPosition = gl_ModelViewMatrix * gl_Vertex; + //gl_Position = ftransform(); + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + normal = gl_NormalMatrix * gl_Normal; + +/////////////////////////////////////////// +// Test phase code: +// + // Coords for ground textures + // Due to precision issues coordinates should restart (i.e. go to zero) every 5000m or so. + const float restart_dist_m = 5000.0; + + // Model position + vec3 mp = gl_Vertex.xyz; + + // Temporary approximation to get shaders to compile: + ground_tex_coord = gl_TexCoord[0].st; + +// +// End test phase code +/////////////////////////////////////////// + + // WS2: + // first current altitude of eye position in model space + // vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0); + // and relative position to vector + //relPos = gl_Vertex.xyz - ep.xyz; + + + // Transform for frame of reference where: + // +z is in the up direction. + // The orientation of x and y axes are unknown currently. + // The origin is at the same position as the model space origin. + // The units are in meters. + mat4 viewSpaceToZUpSpace = fg_zUpTransform * gl_ModelViewMatrixInverse; + + vec4 vertexZUp = fg_zUpTransform * gl_Vertex; + + // WS2: rawPos = gl_Vertex.xy; + rawPos = vertexZUp.xy; + + // WS2: worldPos = (osg_ViewMatrixInverse *gl_ModelViewMatrix * gl_Vertex).xyz; worldPos = fg_modelOffset + gl_Vertex.xyz; - - - steepness = dot(normalize(vec3(fg_zUpTransform * vec4(gl_Normal,1.0))), vec3 (0.0, 0.0, 1.0)); - grad_dir = normalize(gl_Normal.xy); + - vec4 pos = gl_Vertex; - if (raise_vertex) - { - pos.z+=0.1; - gl_Position = gl_ModelViewProjectionMatrix * pos; - } - else gl_Position = ftransform(); + steepness = dot(normalize(vec3(fg_zUpTransform * vec4(gl_Normal,1.0))), vec3 (0.0, 0.0, 1.0)); + // Gradient direction used for small scale noise. In the same space as noise coords, rawpos.xy. + grad_dir = normalize(gl_Normal.xy); + + // here start computations for the haze layer + // we need several geometrical quantities + + + // Eye position in z up space + vec4 epZUp = viewSpaceToZUpSpace * vec4(0.0,0.0,0.0,1.0); + + // Position of vertex relative to the eye position in z up space + vec3 relPosZUp = (vertexZUp - epZUp).xyz; + + + // first current altitude of eye position in model space + vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0); + + + // Eye position in model space + vec4 epMS = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0); + + /* + //old: and relative position to vector. This is also used for cloud shadow positioning. + relPosOld = (fg_zUpTransform * vec4(gl_Vertex - ep)).xyz; + if (any(notEqual(relPosOld, relPosZUp))) relPos = vec3(1000000.0); + */ + relPos = relPosZUp; + + ecViewdir = (gl_ModelViewMatrix * (epMS - gl_Vertex)).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 above mean sea level in meters. + // This is equal to vertexZUp.z as the model space origin is at mean sea level. + // Somehow zero leads to artefacts, so ensure it is at least 100m. + //WS2: vertex_alt = max(gl_Vertex.z,100.0); + vertex_alt = max(vertexZUp.z,100.0); + scattering = ground_scattering + (1.0 - ground_scattering) * smoothstep(hazeLayerAltitude -100.0, hazeLayerAltitude + 100.0, vertex_alt); + -// this code is copied from default.vert - - ecPosition = gl_ModelViewMatrix * gl_Vertex; - //gl_Position = ftransform(); - gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; - //orthoTexCoord = orthophotoTexCoord; - normal = gl_NormalMatrix * gl_Normal; - - // 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 = (fg_zUpTransform * vec4(gl_Vertex - ep)).xyz; - - ecViewdir = (gl_ModelViewMatrix * (ep - gl_Vertex)).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(rawPos.z,100.0); - scattering = ground_scattering + (1.0 - ground_scattering) * smoothstep(hazeLayerAltitude -100.0, hazeLayerAltitude + 100.0, vertex_alt); - - - // branch dependent on daytime + // branch dependent on daytime if (terminator < 1000000.0) // the full, sunrise and sunset computation { - - // establish coordinates relative to sun position - + vec3 lightFull = (gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz; vec3 lightHorizon = normalize(vec3(lightFull.x,lightFull.y, 0.0)); - - // yprime is the distance of the vertex into sun direction yprime = -dot(relPos, lightHorizon); - + // this gets an altitude correction, higher terrain gets to see the sun earlier yprime_alt = yprime - sqrt(2.0 * EarthRadius * vertex_alt); - + // two times terminator width governs how quickly light fades into shadow // now the light-dimming factor earthShade = 0.6 * (1.0 - smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt)) + 0.4; - - // parametrized version of the Flightgear ground lighting function + + // 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;} + {mie_angle = (0.5 * dot(normalize(relPos), normalize(lightFull)) ) + 0.5;} else - {mie_angle = 1.0;} + {mie_angle = 1.0;} + + + light_diffuse.b = light_func(lightArg, 1.330e-05, 0.264, 3.827, 1.08e-05, 1.0); + light_diffuse.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0); + light_diffuse.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0); + light_diffuse.a = 1.0; + light_diffuse = light_diffuse * scattering; + + //light_ambient.b = light_func(lightArg, 0.000506, 0.131, -3.315, 0.000457, 0.5); + //light_ambient.g = light_func(lightArg, 2.264e-05, 0.134, 0.967, 3.66e-05, 0.4); + light_ambient.r = light_func(lightArg, 0.236, 0.253, 1.073, 0.572, 0.33); + light_ambient.g = light_ambient.r * 0.4/0.33; //light_func(lightArg, 0.236, 0.253, 1.073, 0.572, 0.4); + light_ambient.b = light_ambient.r * 0.5/0.33; //light_func(lightArg, 0.236, 0.253, 1.073, 0.572, 0.5); + light_ambient.a = 1.0; - light_diffuse.b = light_func(lightArg, 1.330e-05, 0.264, 3.827, 1.08e-05, 1.0); - light_diffuse.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0); - light_diffuse.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0); - light_diffuse.a = 1.0; - light_diffuse = light_diffuse * scattering; - - //light_ambient.b = light_func(lightArg, 0.000506, 0.131, -3.315, 0.000457, 0.5); - //light_ambient.g = light_func(lightArg, 2.264e-05, 0.134, 0.967, 3.66e-05, 0.4); - light_ambient.r = light_func(lightArg, 0.236, 0.253, 1.073, 0.572, 0.33); - light_ambient.g = light_ambient.r * 0.4/0.33; //light_func(lightArg, 0.236, 0.253, 1.073, 0.572, 0.4); - light_ambient.b = light_ambient.r * 0.5/0.33; //light_func(lightArg, 0.236, 0.253, 1.073, 0.572, 0.5); - light_ambient.a = 1.0; + // correct ambient light intensity and hue before sunrise + if (earthShade < 0.5) + { + intensity = length(light_ambient.rgb); + light_ambient.rgb = intensity * normalize(mix(light_ambient.rgb, shadedFogColor, 1.0 -smoothstep(0.4, 0.8,earthShade) )); + light_ambient.rgb = light_ambient.rgb + moonLightColor * (1.0 - smoothstep(0.4, 0.5, earthShade)); + + intensity = length(light_diffuse.rgb); + light_diffuse.rgb = intensity * normalize(mix(light_diffuse.rgb, shadedFogColor, 1.0 -smoothstep(0.4, 0.7,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); - -// correct ambient light intensity and hue before sunrise -if (earthShade < 0.5) - { - intensity = length(light_ambient.rgb); - light_ambient.rgb = intensity * normalize(mix(light_ambient.rgb, shadedFogColor, 1.0 -smoothstep(0.4, 0.8,earthShade) )); - light_ambient.rgb = light_ambient.rgb + moonLightColor * (1.0 - smoothstep(0.4, 0.5, earthShade)); - - intensity = length(light_diffuse.rgb); - light_diffuse.rgb = intensity * normalize(mix(light_diffuse.rgb, shadedFogColor, 1.0 -smoothstep(0.4, 0.7,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 -{ + 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); + } + + } // End if (terminator < 1000000.0) + else // the faster, full-day version without lightfields + { //vertex_alt = max(gl_Vertex.z,100.0); - + earthShade = 1.0; mie_angle = 1.0; if (terminator > 3000000.0) - {light_diffuse = vec4 (1.0, 1.0, 1.0, 1.0); - light_ambient = vec4 (0.33, 0.4, 0.5, 1.0); } + { + light_diffuse = vec4 (1.0, 1.0, 1.0, 1.0); + light_ambient = vec4 (0.33, 0.4, 0.5, 1.0); + } else - { - - lightArg = (terminator/100000.0 - 10.0)/20.0; - light_diffuse.b = 0.78 + lightArg * 0.21; - light_diffuse.g = 0.907 + lightArg * 0.091; - light_diffuse.r = 0.904 + lightArg * 0.092; - light_diffuse.a = 1.0; - - //light_ambient.b = 0.41 + lightArg * 0.08; - //light_ambient.g = 0.333 + lightArg * 0.06; - light_ambient.r = 0.316 + lightArg * 0.016; - light_ambient.g = light_ambient.r * 0.4/0.33; - light_ambient.b = light_ambient.r * 0.5/0.33; - light_ambient.a = 1.0; - } + { + lightArg = (terminator/100000.0 - 10.0)/20.0; + light_diffuse.b = 0.78 + lightArg * 0.21; + light_diffuse.g = 0.907 + lightArg * 0.091; + light_diffuse.r = 0.904 + lightArg * 0.092; + light_diffuse.a = 1.0; + //light_ambient.b = 0.41 + lightArg * 0.08; + //light_ambient.g = 0.333 + lightArg * 0.06; + light_ambient.r = 0.316 + lightArg * 0.016; + light_ambient.g = light_ambient.r * 0.4/0.33; + light_ambient.b = light_ambient.r * 0.5/0.33; + light_ambient.a = 1.0; + } + light_diffuse = light_diffuse * scattering; yprime_alt = -sqrt(2.0 * EarthRadius * hazeLayerAltitude); -} + + } //End the faster, full-day version without lightfields -// a sky/earth irradiation map model - the sky creates much more diffuse radiation than the ground, so -// steep faces end up shaded more + // a sky/earth irradiation map model - the sky creates much more diffuse radiation than the ground, so + // steep faces end up shaded more + + light_ambient = light_ambient * ((1.0+steepness)/2.0 * 1.2 + (1.0-steepness)/2.0 * 0.2); -light_ambient = light_ambient * ((1.0+steepness)/2.0 * 1.2 + (1.0-steepness)/2.0 * 0.2); + // deeper shadows when there is lots of direct light -// deeper shadows when there is lots of direct light - -float shade_depth = 1.0 * smoothstep (0.6,0.95,ground_scattering) * (1.0-smoothstep(0.1,0.5,overcast)) * smoothstep(0.4,1.5,earthShade); - - light_ambient.rgb = light_ambient.rgb * (1.0 - shade_depth); - light_diffuse.rgb = light_diffuse.rgb * (1.0 + 1.2 * shade_depth); - -if (use_IR_vision) - { - light_ambient.rgb = max(light_ambient.rgb, vec3 (0.5, 0.5, 0.5)); - } + float shade_depth = 1.0 * smoothstep (0.6,0.95,ground_scattering) * (1.0-smoothstep(0.1,0.5,overcast)) * smoothstep(0.4,1.5,earthShade); + + light_ambient.rgb = light_ambient.rgb * (1.0 - shade_depth); + light_diffuse.rgb = light_diffuse.rgb * (1.0 + 1.2 * shade_depth); + + if (use_IR_vision) + { + light_ambient.rgb = max(light_ambient.rgb, vec3 (0.5, 0.5, 0.5)); + } -// default lighting based on texture and material using the light we have just computed - - light_diffuse_comp = light_diffuse; - //Testing phase code: ambient colours are not sent to fragement shader yet. - // They are all default except for water/ocean etc. currently - // Emission is all set to the default of vec4(0.0, 0.0, 0.0, 1.0) - //To do: Fix this once ambient colour becomes available in the fragment shaders. - //const vec4 ambient_color = vec4(0.2, 0.2, 0.2, 1.0); - const vec4 ambient_color = vec4(1.0); - vec4 constant_term = ambient_color * (gl_LightModel.ambient + light_ambient); - - light_diffuse_comp.a = yprime_alt; - gl_FrontColor.rgb = constant_term.rgb; // gl_FrontColor.a = 1.0; - gl_BackColor.rgb = constant_term.rgb; // gl_BackColor.a = 0.0; - gl_FrontColor.a = mie_angle; - gl_BackColor.a = mie_angle; - - setupShadows(ecPosition); + // default lighting based on texture and material using the light we have just computed + + light_diffuse_comp = light_diffuse; + //Testing phase code: ambient colours are not sent to fragement shader yet. + // They are all default except for water/ocean etc. currently + // Emission is all set to the default of vec4(0.0, 0.0, 0.0, 1.0) + //To do: Fix this once ambient colour becomes available in the fragment shaders. + //const vec4 ambient_color = vec4(0.2, 0.2, 0.2, 1.0); + const vec4 ambient_color = vec4(1.0); + vec4 constant_term = ambient_color * (gl_LightModel.ambient + light_ambient); + + light_diffuse_comp.a = yprime_alt; + gl_FrontColor.rgb = constant_term.rgb; // gl_FrontColor.a = 1.0; + gl_BackColor.rgb = constant_term.rgb; // gl_BackColor.a = 0.0; + gl_FrontColor.a = mie_angle; + gl_BackColor.a = mie_angle; + + setupShadows(ecPosition); } diff --git a/Shaders/ws30-ALS.frag b/Shaders/ws30-ALS.frag index 4a516f4a4..880406aad 100644 --- a/Shaders/ws30-ALS.frag +++ b/Shaders/ws30-ALS.frag @@ -43,6 +43,7 @@ varying vec4 light_diffuse_comp; varying vec3 normal; varying vec3 relPos; +varying vec2 ground_tex_coord; uniform sampler2D landclass; uniform sampler2DArray textureArray; @@ -144,21 +145,33 @@ int get_random_landclass(in vec2 co, in vec2 tile_size); // The partial derivatives of the tile_coord at the fragment is needed to adjust for // the stretching of different textures, so that the correct mip-map level is looked // up and there are no seams. +// Texture types: 0: base texture, 1: grain texture, 2: gradient texture, 3 dot texture, +// 4: mix texture, 5: detail texture. -vec4 lookup_ground_texture_array(in vec2 tile_coord, in int landclass_id, in vec2 dx, in vec2 dy); +vec4 lookup_ground_texture_array(in int texture_type, in vec2 ground_texture_coord, in int landclass_id, + in vec4 dFdx_and_dFdy); // Look up the landclass id [0 .. 255] for this particular fragment. // Lookup id of any neighbouring landclass that is within the search distance. // Searches are performed in upto 4 directions right now, but only one landclass is looked up // Create a mix factor werighting the influences of nearby landclasses -void get_landclass_id(in vec2 tile_coord, - const in float landclass_texel_size_m, in vec2 dx, in vec2 dy, +void get_landclass_id(in vec2 tile_coord, in vec4 dFdx_and_dFdy, out int landclass_id, out ivec4 neighbor_landclass_ids, out int num_unique_neighbors,out vec4 mix_factor ); +// Look up the texel of the specified texture type (e.g. grain or detail textures) for this fragment +// and any neighbor texels, then mix. + +vec4 get_mixed_texel(in int texture_type, in vec2 g_texture_coord, + in int landclass_id, in int num_unique_neighbors, + in ivec4 neighbor_texel_landclass_ids, in vec4 neighbor_mix_factors, + in vec4 dFdx_and_dFdy + ); + + // End Test-phase code //////////////////////// @@ -209,16 +222,15 @@ void main() vec4 mfact; - const float landclass_texel_size_m = 25.0; // Partial derivatives of s and t for this fragment, // with respect to window (screen space) x and y axes. // Used to pick mipmap LoD levels, and turn off unneeded procedural detail - vec2 dx = dFdx(tile_coord); - vec2 dy = dFdy(tile_coord); + // dFdx and dFdy are packed in a vec4 so multiplying + // to scale takes 1 instruction slot. + vec4 dxdy_gc = vec4(dFdx(tile_coord) , dFdy(tile_coord)); - get_landclass_id(tile_coord, landclass_texel_size_m, dx, dy, - lc, lc_n, num_unique_neighbors, mfact); + get_landclass_id(tile_coord, dxdy_gc, lc, lc_n, num_unique_neighbors, mfact); // The landclass id is used to index into arrays containing // material parameters and textures for the landclass as @@ -226,9 +238,18 @@ void main() float index = float(lc)/512.0; vec4 index_n = vec4(lc_n)/512.0; - // Material properties. - vec4 mat_diffuse, mat_ambient, mat_specular; - float mat_shininess; + // Material properties. + vec4 mat_diffuse, mat_ambient, mat_specular; + float mat_shininess; + + // Calculate texture coords for ground textures + // Textures are stretched along the ground to different + // lengths along each axes as set by and + // regional definitions parameters. + vec2 stretch_dimensions = fg_dimensionsArray[lc].st; + vec2 tileSize = vec2(fg_tileWidth, fg_tileHeight); + vec2 texture_scaling = tileSize.yx / stretch_dimensions.st; + vec2 st = texture_scaling.st * ground_tex_coord.st; if (fg_photoScenery) { mat_ambient = vec4(1.0,1.0,1.0,1.0); @@ -238,46 +259,26 @@ void main() texel = texture(landclass, vec2(gl_TexCoord[0].s, 1.0 - gl_TexCoord[0].t)); } else { - // Color Mode is always AMBIENT_AND_DIFFUSE, which means - // using a base colour of white for ambient/diffuse, - // rather than the material color from ambientArray/diffuseArray. - mat_ambient = vec4(1.0,1.0,1.0,1.0); - mat_diffuse = vec4(1.0,1.0,1.0,1.0); - mat_specular = fg_specularArray[lc]; - mat_shininess = fg_dimensionsArray[lc].z; + + // Color Mode is always AMBIENT_AND_DIFFUSE, which means + // using a base colour of white for ambient/diffuse, + // rather than the material color from ambientArray/diffuseArray. + mat_ambient = vec4(1.0,1.0,1.0,1.0); + mat_diffuse = vec4(1.0,1.0,1.0,1.0); + mat_specular = fg_specularArray[lc]; + mat_shininess = fg_dimensionsArray[lc].z; // Look up ground textures by indexing into the texture array. // Different textures are stretched along the ground to different // lengths along each axes as set by and // regional definitions parameters - // Look up texture coordinates and scale of ground textures - // Landclass for this fragment - texel = lookup_ground_texture_array(tile_coord, lc, dx, dy); + // Lookup the base texture texel for this fragment and any neighbors, with mixing + texel = get_mixed_texel(0, ground_tex_coord, lc, num_unique_neighbors, lc_n, mfact, dxdy_gc); - // Mix texels - to work consistently it needs a more preceptual interpolation than mix() - if (num_unique_neighbors != 0) - { - // Closest neighbor landclass - vec4 texel_closest = lookup_ground_texture_array(tile_coord, lc_n[0], dx, dy); - - // Neighbor contributions - vec4 texel_nc=texel_closest; - - if (num_unique_neighbors > 1) - { - // 2nd Closest neighbor landclass - vec4 texel_2nd_closest = lookup_ground_texture_array(tile_coord, lc_n[1], - dx, dy); - - texel_nc = mix(texel_closest, texel_2nd_closest, mfact[1]); - } - - texel = mix(texel, texel_nc, mfact[0]); - } } - vec4 color = mat_ambient * (gl_LightModel.ambient + gl_LightSource[0].ambient); + vec4 color = mat_ambient * (gl_LightModel.ambient + gl_LightSource[0].ambient); // Testing code: // Use rlc even when looking up textures to recreate the extra performance hit diff --git a/Shaders/ws30-ALS.vert b/Shaders/ws30-ALS.vert index 0ef6387a9..5095c86e9 100644 --- a/Shaders/ws30-ALS.vert +++ b/Shaders/ws30-ALS.vert @@ -27,6 +27,7 @@ uniform vec3 fg_modelOffset; varying vec4 light_diffuse_comp; varying vec3 normal; varying vec3 relPos; +varying vec2 ground_tex_coord; varying vec4 ecPosition; varying float yprime_alt; @@ -85,6 +86,9 @@ void main() gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; normal = gl_NormalMatrix * gl_Normal; + // Temporary value: + ground_tex_coord = gl_TexCoord[0].st; + // here start computations for the haze layer // we need several geometrical quantities diff --git a/Shaders/ws30-overlay-ALS.geom b/Shaders/ws30-overlay-ALS.geom new file mode 100644 index 000000000..3393474af --- /dev/null +++ b/Shaders/ws30-overlay-ALS.geom @@ -0,0 +1,75 @@ +// -*-C++-*- +#version 120 +#extension GL_EXT_geometry_shader4 : enable + +// The following is copied from terrain-overlay.geom + +#define MAX_LAYERS 8 +#define MIN_LAYERS 2 +#define MAX_MINUS_MIN_LAYERS 6 + +uniform float overlay_max_height; + +varying in vec3 v_normal[3]; + +varying out vec2 g_rawpos; +varying out float g_distance_to_eye; +varying out vec3 g_normal; +varying out float g_altitude; +varying out float g_layer; + +uniform mat4 fg_LightMatrix_csm0; +uniform mat4 fg_LightMatrix_csm1; +uniform mat4 fg_LightMatrix_csm2; +uniform mat4 fg_LightMatrix_csm3; +varying out vec4 lightSpacePos[4]; +void setupShadows(vec4 eyeSpacePos) +{ + lightSpacePos[0] = fg_LightMatrix_csm0 * eyeSpacePos; + lightSpacePos[1] = fg_LightMatrix_csm1 * eyeSpacePos; + lightSpacePos[2] = fg_LightMatrix_csm2 * eyeSpacePos; + lightSpacePos[3] = fg_LightMatrix_csm3 * eyeSpacePos; +} + +float min3(in float a, in float b, in float c) +{ + float m = a; + if (m > b) m = b; + if (m > c) m = c; + return m; +} + +void main() +{ + float distances[3]; + distances[0] = -(gl_ModelViewMatrix * gl_PositionIn[0]).z; + distances[1] = -(gl_ModelViewMatrix * gl_PositionIn[1]).z; + distances[2] = -(gl_ModelViewMatrix * gl_PositionIn[2]).z; + float minDistance = min3(distances[0], distances[1], distances[2]); + //float avgDistance = (distances[0]+distances[1]+distances[2])*0.33; + + int numLayers = MIN_LAYERS + int((1.0 - smoothstep(250.0, 5000.0, minDistance)) * float(MAX_MINUS_MIN_LAYERS)); + + float deltaLayer = 1.0 / float(numLayers); + float currDeltaLayer = 1.5 * deltaLayer;// * 0.5; + + for (int layer = 0; layer < numLayers; ++layer) { + for (int i = 0; i < 3; ++i) { + vec4 pos = gl_PositionIn[i] + vec4(v_normal[i] * currDeltaLayer * overlay_max_height, 0.0); + g_rawpos = gl_PositionIn[i].xy; + g_distance_to_eye = distances[i]; + g_layer = currDeltaLayer; + g_normal = v_normal[i]; + g_altitude = gl_PositionIn[i].z; + + setupShadows(gl_ModelViewMatrix * pos); + + gl_Position = gl_ModelViewProjectionMatrix * pos; + gl_TexCoord[0] = gl_TexCoordIn[i][0]; + EmitVertex(); + } + EndPrimitive(); + + currDeltaLayer += deltaLayer; + } +} diff --git a/Shaders/ws30-overlay-ALS.vert b/Shaders/ws30-overlay-ALS.vert new file mode 100644 index 000000000..fa717a7f5 --- /dev/null +++ b/Shaders/ws30-overlay-ALS.vert @@ -0,0 +1,21 @@ +// -*-C++-*- +#version 120 + +//Copied from grass-ALS.vert + +// The UV scale controls the grass thickness. Lower numbers thicken the blades +// while higher numbers make them thinner. +#define UV_SCALE 10.0 + +varying vec3 v_normal; + +void main() +{ + + gl_Position = gl_Vertex; + + // WS2: gl_TexCoord[0] = gl_MultiTexCoord0 * UV_SCALE; + gl_TexCoord[0] = gl_MultiTexCoord0 * UV_SCALE; + + v_normal = gl_Normal; +}