diff --git a/Effects/ws30.eff b/Effects/ws30.eff
index be5f2f8bd..03f961512 100644
--- a/Effects/ws30.eff
+++ b/Effects/ws30.eff
@@ -35,14 +35,6 @@
repeat
normalized
-
- Textures/Terrain/sand6.png
- 2d
- nearest
- repeat
- repeat
- normalized
-
Textures/Terrain/snow3.png
2d
@@ -859,11 +851,6 @@
coastline
sampler-2d
7
-
-
- sand
- sampler-2d
- 8
swatch_size
@@ -1289,11 +1276,6 @@
sampler-2d
7
-
- sand
- sampler-2d
- 8
-
swatch_size
int
diff --git a/Shaders/ws30-ALS-detailed.frag b/Shaders/ws30-ALS-detailed.frag
index 465818b72..cbb4c1ba9 100644
--- a/Shaders/ws30-ALS-detailed.frag
+++ b/Shaders/ws30-ALS-detailed.frag
@@ -29,17 +29,13 @@
// End of test phase controls
//////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-
-
-
-
-
+// Constants controlling the transition from water
+// to terrain depending on the terrain normal
+// A normal of 1.0 is completely horizontal.
+const float WATER_START = 0.995; // Deeper water.
+const float WATER_BEACH_TO_WATER = 0.99; // Transition point between the shoreline and the shallow water
+const float WATER_STEEP_TO_BEACH = 0.985; // The transition point between the shoreline and the land
+const float WATER_STEEP = 0.98; // Anything with less than this value is considered not water or shoreline
// written by Thorsten Renk, Oct 2011, based on default.frag
// Ambient term comes in gl_Color.rgb.
@@ -101,8 +97,8 @@ uniform vec3 fg_modelOffset;
// Coastline texture - generated from VPBTechnique
uniform sampler2D coastline;
-// Sand texture
-uniform sampler2D sand;
+// Index into the material definition for shorelines
+uniform int fg_shoreAtlasIndex;
const float EarthRadius = 5800000.0;
const float terminator_width = 200000.0;
@@ -321,7 +317,8 @@ float noise_2000m = Noise3D(worldPos.xyz, 2000.0);
// Mix factor of base textures for 2 neighbour landclass(es)
vec4 mfact;
- bool water = false;
+ bool water_lc = false;
+ bool mix_water_texel = false;
// Partial derivatives of s and t of ground texture coords for this fragment,
// with respect to window (screen space) x and y axes.
@@ -332,35 +329,37 @@ float noise_2000m = Noise3D(worldPos.xyz, 2000.0);
get_landclass_id(tile_coord, dxdy_gc, lc, lc_n, num_unique_neighbors, mfact);
get_material(lc, ground_tex_coord, dxdy_gc, mat_shininess, mat_ambient, mat_diffuse, mat_specular, dxdy, st);
- vec4 coast = texture2D(coastline, tile_coord);
if (fg_photoScenery) {
- texel = texture(landclass, vec2(gl_TexCoord[0].s, 1.0 - gl_TexCoord[0].t));
- water = (texture(coastline, vec2(tile_coord.s, tile_coord.t)).r > 0.1);
- } else if (coast.g > 0.1) {
- texel = lookup_ground_texture_array(0, tile_coord, lc, dxdy);
- water = texture(landclass, vec2(tile_coord.s, tile_coord.t)).z > 0.9;
+ texel = texture(landclass, vec2(gl_TexCoord[0].s, 1.0 - gl_TexCoord[0].t));
+ water_lc = (texture(coastline, vec2(tile_coord.s, tile_coord.t)).r > 0.1);
} else {
// 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);
- water = texture(landclass, vec2(tile_coord.s, tile_coord.t)).z > 0.9;
+ water_lc = texture(landclass, vec2(tile_coord.s, tile_coord.t)).z > 0.9;
}
- float steep = 0.9;
- float steepToBeach = 0.93;
- float beachToWater = 0.95;
- float waterStart = 0.97;
+ float steepness_modifier = texture2D(coastline, tile_coord).g * 0.1;
+ bool water = water_lc || texture2D(coastline, tile_coord).b > 0.05;
- if ((water_shader == 1) && ((coast.b > 0.05) || (water && steepness < (waterStart + 0.02)))) {
+ if ((water_shader == 1) && (water && (steepness + steepness_modifier)< WATER_START)) {
// This is a water fragment, so calculate the fragment color procedurally, but mix in the steep and beach
- vec4 steep_texel = lookup_ground_texture_array(2, ground_tex_coord, lc, dxdy_gc); // Uses the same index as the gradient texture, which it is
- vec4 beach_texel = texture2D(sand, ground_tex_coord); // Use the dot texture, which is overloaded to be the beach texture
- texel = mix(steep_texel, beach_texel, smoothstep(steep, steepToBeach, steepness));
- fragColor = mix(texel, generateWaterTexel(), smoothstep(beachToWater,waterStart,steepness));
+ if (water_lc) {
+ lc = fg_shoreAtlasIndex;
+ get_material(lc, ground_tex_coord, dxdy_gc, mat_shininess, mat_ambient, mat_diffuse, mat_specular, dxdy, st);
+ }
- fragColor.rgb += getClusteredLightsContribution(eyePos.xyz, n, fragColor.rgb);
- } else if ((water_shader == 1) && water) {
+ vec4 steep_texel = lookup_ground_texture_array(0, ground_tex_coord, lc, dxdy_gc); // Uses the same index as the gradient texture, which it is
+ vec4 beach_texel = lookup_ground_texture_array(0, ground_tex_coord, fg_shoreAtlasIndex, dxdy_gc); // Use the shore texture
+ texel = mix(steep_texel, beach_texel, smoothstep(WATER_STEEP, WATER_STEEP_TO_BEACH, steepness + steepness_modifier));
+
+ // Flag that we need to mix in a water texel later if appropriate.
+ mix_water_texel = (steepness + steepness_modifier > WATER_BEACH_TO_WATER);
+ water = false;
+ }
+
+ if ((water_shader == 1) && water) {
fragColor = generateWaterTexel();
fragColor.rgb += getClusteredLightsContribution(eyePos.xyz, n, fragColor.rgb);
} else {
@@ -602,6 +601,9 @@ float noise_2000m = Noise3D(worldPos.xyz, 2000.0);
color = clamp(color, 0.0, 1.0);
fragColor = color * texel + specular;
+
+ if (mix_water_texel) { fragColor = mix(fragColor, generateWaterTexel(), smoothstep(WATER_BEACH_TO_WATER, WATER_START, steepness + steepness_modifier)); }
+
fragColor.rgb += getClusteredLightsContribution(eyePos.xyz, n, texel.rgb);
}
diff --git a/Shaders/ws30-ALS-landclass-search-functions.frag b/Shaders/ws30-ALS-landclass-search-functions.frag
index ed5ee9647..4e14d9500 100644
--- a/Shaders/ws30-ALS-landclass-search-functions.frag
+++ b/Shaders/ws30-ALS-landclass-search-functions.frag
@@ -528,6 +528,13 @@ int read_landclass_id(in vec2 tile_coord)
return lc;
}
+// Landclass sources: texture or random
+ivec2 read_landclass_id_and_water(in vec2 tile_coord)
+{
+ int lc = (int(texture2D(landclass, tile_coord.st).g * 255.0 + 0.5));
+ return ivec2(lc, (texture2D(landclass, tile_coord.st).b > 0.9) ? 1 : 0);
+}
+
int read_landclass_id_non_pixelated(in vec2 tile_coord,
const in float landclass_texel_size_m)
@@ -991,8 +998,8 @@ if ( (enable_large_scale_transition_search == 1) &&
for (int i=1;i<=n;i++) {
vec2 c = c0+float(i)*dir;
- int v = read_landclass_id(c);
- if ((v != lc) && (mi[0] > n)) {l[0] = v; mi[0] = i; }
+ ivec2 v = read_landclass_id_and_water(c);
+ if ((v[0] != lc) && (v[1] != 1) && (mi[0] > n)) {l[0] = v[0]; mi[0] = i; }
}
@@ -1001,8 +1008,8 @@ if ( (enable_large_scale_transition_search == 1) &&
for (int i=1;i<=n;i++)
{
vec2 c = c0+float(i)*dir;
- int v = read_landclass_id(c);
- if ((v != lc) && (mi[1] > n)) {l[1] = v; mi[1] = i; }
+ ivec2 v = read_landclass_id_and_water(c);
+ if ((v[0] != lc) && (v[1] != 1) && (mi[1] > n)) {l[1] = v[0]; mi[1] = i; }
}
@@ -1011,8 +1018,8 @@ if ( (enable_large_scale_transition_search == 1) &&
for (int i=1;i<=n;i++)
{
vec2 c = c0+float(i)*dir;
- int v = read_landclass_id(c);
- if ((v != lc) && (mi[2] > n)) {l[2] = v; mi[2] = i; }
+ ivec2 v = read_landclass_id_and_water(c);
+ if ((v[0] != lc) && (v[1] != 1) && (mi[2] > n)) {l[2] = v[0]; mi[2] = i; }
}
@@ -1021,8 +1028,8 @@ if ( (enable_large_scale_transition_search == 1) &&
for (int i=1;i<=n;i++)
{
vec2 c = c0+float(i)*dir;
- int v = read_landclass_id(c);
- if ((v != lc) && (mi[3] > n)) {l[3] = v; mi[3] = i; }
+ ivec2 v = read_landclass_id_and_water(c);
+ if ((v[0] != lc) && (v[1] != 1) && (mi[3] > n)) {l[3] = v[0]; mi[3] = i; }
}
diff --git a/Shaders/ws30-ALS-ultra.frag b/Shaders/ws30-ALS-ultra.frag
index aeb0aa04e..41464530e 100644
--- a/Shaders/ws30-ALS-ultra.frag
+++ b/Shaders/ws30-ALS-ultra.frag
@@ -28,6 +28,15 @@ const int randomise_texture_lookups = 0;
// Use built-in water shader. Use for testing impact of ws30-water.frag
const int water_shader = 1;
+
+// Constants controlling the transition from water
+// to terrain depending on the terrain normal
+// A normal of 1.0 is completely horizontal.
+const float WATER_START = 0.995; // Deeper water.
+const float WATER_BEACH_TO_WATER = 0.99; // Transition point between the shoreline and the shallow water
+const float WATER_STEEP_TO_BEACH = 0.985; // The transition point between the shoreline and the land
+const float WATER_STEEP = 0.98; // Anything with less than this value is considered not water or shoreline
+
//
// End of test phase controls
//////////////////////////////////////////////////////////////////
@@ -103,6 +112,9 @@ uniform vec4 fg_materialParams1[128];
uniform vec4 fg_materialParams2[128];
uniform vec4 fg_materialParams3[128];
+// Index into the material definition for shorelines
+uniform int fg_shoreAtlasIndex;
+
// Coastline texture - generated from VPBTechnique
uniform sampler2D coastline;
@@ -417,7 +429,8 @@ void main()
// Mix factor of base textures for 2 neighbour landclass(es)
vec4 mfact;
- bool water = false;
+ bool water_lc = false;
+ bool mix_water_texel = false;
// Partial derivatives of s and t of ground texture coords for this fragment,
// with respect to window (screen space) x and y axes.
@@ -428,47 +441,64 @@ void main()
get_landclass_id(tile_coord, dxdy_gc, lc, lc_n, num_unique_neighbors, mfact);
get_material(lc, ground_tex_coord, dxdy_gc, mat_shininess, mat_ambient, mat_diffuse, mat_specular, dxdy, st);
- vec4 coast = texture2D(coastline, tile_coord);
if (fg_photoScenery) {
// The photoscenery orthophotos are stored in the landclass texture
// and use normalised tile coordinates
texel = texture(landclass, vec2(tile_coord.s, 1.0 - tile_coord.t));
- water = (texture(coastline, vec2(tile_coord.s, tile_coord.t)).r > 0.1);
+ water_lc = (texture(coastline, vec2(tile_coord.s, tile_coord.t)).r > 0.1);
// Do not attempt any mixing
flag = 0;
mix_flag = 0;
- } else if (coast.g > 0.1) {
- texel = lookup_ground_texture_array(0, tile_coord, lc, dxdy);
- water = texture(landclass, vec2(tile_coord.s, tile_coord.t)).z > 0.9;
} else {
// 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);
- water = texture(landclass, vec2(tile_coord.s, tile_coord.t)).z > 0.9;
+ water_lc = texture(landclass, vec2(tile_coord.s, tile_coord.t)).b > 0.5;
}
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]));
- float steep = 0.9;
- float steepToBeach = 0.93;
- float beachToWater = 0.95;
- float waterStart = 0.97;
+ // The coastline BLUE channel provides a higher detail level for waters. The coastline G channel provides a
+ // steepness modified that is used so that rivers and lakes are displayed with water on more angled surfaces. Otherwise
+ // rivers tend to just be sand, as they flow downhill.
+ float steepness_modifier = texture2D(coastline, tile_coord).g * 0.1;
+ bool water = water_lc || texture2D(coastline, tile_coord).b > 0.05;
+ if (water && (steepness + steepness_modifier < WATER_START)) {
+ // For water surfaces that are simply too steep to be plausible we look for an adjacent landclass and mix it with
+ // a possible shoreline
+ if (water_lc) {
+ if (lc == lc_n[0]) {
+ // Default to the shore material definition
+ lc = fg_shoreAtlasIndex;
+ } else {
+ lc = lc_n[0];
+ }
+ }
- if ((coast.b > 0.05) || (water && steepness < (waterStart + 0.02))) {
- float waterline_min_steepness = fg_materialParams3[lc].y;
- float waterline_max_steepness = fg_materialParams3[lc].z;
- vec4 steep_texel = lookup_ground_texture_array(2, ground_tex_coord, lc, dxdy_gc); // Uses the same index as the gradient texture, which it is
- vec4 beach_texel = texture2D(sand, ground_tex_coord); // Use the dot texture, which is overloaded to be the beach texture
- texel = mix(steep_texel, beach_texel, smoothstep(steep, steepToBeach, steepness));
- fragColor = mix(texel, generateWaterTexel(), smoothstep(beachToWater,waterStart,steepness));
- fragColor.rgb += getClusteredLightsContribution(ecPosition.xyz, n, fragColor.rgb);
- } else if (water) {
+ get_material(lc, ground_tex_coord, dxdy_gc, mat_shininess, mat_ambient, mat_diffuse, mat_specular, dxdy, st);
+ vec4 color = gl_Color * mat_ambient;
+ color.a = 1.0;
+
+ vec4 steep_texel = lookup_ground_texture_array(0, ground_tex_coord, lc, dxdy); // look up the secondary texture
+ vec4 beach_texel = lookup_ground_texture_array(0, ground_tex_coord, fg_shoreAtlasIndex, dxdy); // Use the shore texture
+ texel = mix(steep_texel, beach_texel, smoothstep(WATER_STEEP, WATER_STEEP_TO_BEACH, steepness + steepness_modifier));
+
+ // Flag that we need to mix in a water texel later if appropriate.
+ mix_water_texel = (steepness + steepness_modifier > WATER_BEACH_TO_WATER);
+ water = false;
+ }
+
+ // Test code to view the coastline rasters in-sim
+ //texel.r = texture2D(coastline, tile_coord).b;
+ //water = false;
+
+ if (water) {
fragColor = generateWaterTexel();
fragColor.rgb += getClusteredLightsContribution(ecPosition.xyz, n, fragColor.rgb);
} else {
@@ -833,6 +863,9 @@ void main()
color.rgb += secondary_light * light_distance_fading(dist);
fragColor = color * texel + specular;
+
+ if (mix_water_texel) { fragColor = mix(fragColor, generateWaterTexel(), smoothstep(WATER_BEACH_TO_WATER, WATER_START, steepness + steepness_modifier)); }
+
fragColor.rgb += getClusteredLightsContribution(ecPosition.xyz, n, texel.rgb);
}