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
+
+
+
+
+
+
+ ambient-and-diffuse
+
+
+
+ smooth
+ back
+
+
+
+
+
+
+
+
+ 1
+
+ nearest-mipmap-nearest
+ nearest-mipmap-nearest
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+ 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
+
+
+
+ intrinsic_wetness
+ float
+
+
+
+ transition_model
+ float
+
+
+
+ hires_overlay_bias
+ float
+
+
+
+ dot_density
+ float
+
+
+
+ dot_size
+ float
+
+
+
+ dust_resistance
+ float
+
+
+
+ visibility
+ float
+
+
+
+ avisibility
+ float
+
+
+
+ hazeLayerAltitude
+ float
+
+
+
+ scattering
+ float
+
+
+
+ ground_scattering
+ float
+
+
+
+ terminator
+ float
+
+
+
+ terrain_alt
+ float
+
+
+
+ overcast
+ float
+
+
+
+ eye_alt
+ float
+
+
+
+ eye_lat
+ float
+
+
+
+ eye_lon
+ float
+
+
+
+ snowlevel
+ float
+
+
+
+ snow_thickness_factor
+ float
+
+
+
+ dust_cover_factor
+ float
+
+
+
+ lichen_cover_factor
+ float
+
+
+
+ wetness
+ float
+
+
+
+ fogstructure
+ float
+
+
+
+ cloud_self_shading
+ float
+
+
+
+ moonlight
+ float
+
+
+
+ season
+ float
+
+
+
+ air_pollution
+ float
+
+
+
+
+ view_pitch_offset
+ float
+
+
+
+ view_heading_offset
+ float
+
+
+
+ field_of_view
+ float
+
+
+
+ landing_light1_offset
+ float
+
+
+
+ landing_light2_offset
+ float
+
+
+
+ landing_light3_offset
+ float
+
+
+
+
+ gamma
+ float
+
+
+
+ brightness
+ float
+
+
+
+ use_night_vision
+ bool
+
+
+
+ use_IR_vision
+ bool
+
+
+
+ use_filtering
+ bool
+
+
+
+ delta_T
+ float
+
+
+
+ fact_grey
+ float
+
+
+
+ fact_black
+ float
+
+
+
+
+ cloudpos1_x
+ float
+
+
+
+ cloudpos1_y
+ float
+
+
+
+ cloudpos2_x
+ float
+
+
+
+ cloudpos2_y
+ float
+
+
+
+ cloudpos3_x
+ float
+
+
+
+ cloudpos3_y
+ float
+
+
+
+ cloudpos4_x
+ float
+
+
+
+ cloudpos4_y
+ float
+
+
+
+ cloudpos5_x
+ float
+
+
+
+ cloudpos5_y
+ float
+
+
+
+ cloudpos6_x
+ float
+
+
+
+ cloudpos6_y
+ float
+
+
+
+ cloudpos7_x
+ float
+
+
+
+ cloudpos7_y
+ float
+
+
+
+ cloudpos8_x
+ float
+
+
+
+ cloudpos8_y
+ float
+
+
+
+ cloudpos9_x
+ float
+
+
+
+ cloudpos9_y
+ float
+
+
+
+ cloudpos10_x
+ float
+
+
+
+ cloudpos10_y
+ float
+
+
+
+ cloudpos11_x
+ float
+
+
+
+ cloudpos11_y
+ float
+
+
+
+ cloudpos12_x
+ float
+
+
+
+ cloudpos12_y
+ float
+
+
+
+ cloudpos13_x
+ float
+
+
+
+ cloudpos13_y
+ float
+
+
+
+ cloudpos14_x
+ float
+
+
+
+ cloudpos14_y
+ float
+
+
+
+ cloudpos15_x
+ float
+
+
+
+ cloudpos15_y
+ float
+
+
+
+ cloudpos16_x
+ float
+
+
+
+ cloudpos16_y
+ float
+
+
+
+ cloudpos17_x
+ float
+
+
+
+ cloudpos17_y
+ float
+
+
+
+ cloudpos18_x
+ float
+
+
+
+ cloudpos18_y
+ float
+
+
+
+ cloudpos19_x
+ float
+
+
+
+ cloudpos19_y
+ float
+
+
+
+ cloudpos20_x
+ float
+
+
+
+ cloudpos20_y
+ float
+
+
+
+ WindE
+ float
+
+
+
+ WindN
+ float
+
+
+
+ use_searchlight
+ int
+
+
+
+ use_landing_light
+ int
+
+
+
+ use_alt_landing_light
+ int
+
+
+
+ display_xsize
+ int
+
+
+
+ display_ysize
+ int
+
+
+
+ wind_effects
+ int
+
+
+
+ cloud_shadow_flag
+ int
+
+
+
+ rock_strata
+ int
+
+
+
+ raise_vertex
+ bool
+
+
+
+ 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
+
+
+
+
+
+ sun_atlas_size
+ int
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+ ambient-and-diffuse
+
+
+ smooth
+
+
+ back
+
+
+
+
+
+
+
+
+ 7
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+
+
+
+
+
+ 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
+
+
+
+ avisibility
+ float
+
+
+
+ scattering
+ float
+
+
+
+ overlay_bias
+ float
+
+
+
+ overlay_max_height
+ float
+
+
+
+ overlay_hardness
+ float
+
+
+
+ overlay_secondary_hardness
+ float
+
+
+
+ overlay_density
+ float
+
+
+
+ overlay_secondary_density
+ float
+
+
+
+ overlay_scale
+ float
+
+
+
+ overlay_brightness_top
+ float
+
+
+
+ overlay_brightness_bottom
+ float
+
+
+
+ overlay_steepness_factor
+ float
+
+
+
+ season
+ float
+
+
+
+ dust_cover_factor
+ float
+
+
+
+ wetness
+ float
+
+
+
+ snowlevel
+ float
+
+
+
+ snow_thickness_factor
+ float
+
+
+
+
+
+ cloudpos_n_x
+ float
+
+
+
+ cloudpos_n_y
+ float
+
+
+
+
+
+
+ gamma
+ float
+
+
+
+ brightness
+ float
+
+
+
+ use_night_vision
+ bool
+
+
+
+ use_IR_vision
+ bool
+
+
+
+ use_filtering
+ bool
+
+
+
+ delta_T
+ float
+
+
+
+ fact_grey
+ float
+
+
+
+ fact_black
+ float
+
+
+
+
+ display_xsize
+ int
+
+
+
+ display_ysize
+ int
+
+
+
+ overlay_autumn_flag
+ int
+
+
+
+ overlay_secondary_flag
+ int
+
+
+
+ cloud_shadow_flag
+ int
+
+
+
+
+ shadow_tex
+ sampler-2d
+ 10
+
+
+ shadows_enabled
+ bool
+
+
+
+
+
+ sun_atlas_size
+ int
+
+
+
+
+
+
+
+ true
+
+ 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;
+}