diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e14c1295b..3d4f0ce25f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Reworked mindflayer to have unique attacks - Glowing remains are now `Armor` instead of `Ingredients`. +- Generated a net world map +- Overhauled clouds for more verticality and performance + ### Removed ### Fixed diff --git a/assets/voxygen/shaders/fluid-frag/shiny.glsl b/assets/voxygen/shaders/fluid-frag/shiny.glsl index b73dc24393..0c5865394b 100644 --- a/assets/voxygen/shaders/fluid-frag/shiny.glsl +++ b/assets/voxygen/shaders/fluid-frag/shiny.glsl @@ -179,7 +179,7 @@ void main() { // Squared to account for prior saturation. float f_light = 1.0;// pow(f_light, 1.5); vec3 reflect_color = get_sky_color(/*reflect_ray_dir*/beam_view_dir, time_of_day.x, f_pos, vec3(-100000), 0.125, true); - reflect_color = get_cloud_color(reflect_color, reflect_ray_dir, cam_pos.xyz, time_of_day.x, 100000.0, 0.25); + reflect_color = get_cloud_color(reflect_color, reflect_ray_dir, cam_pos.xyz, time_of_day.x, 100000.0, 0.1); reflect_color *= f_light; // /*const */vec3 water_color = srgb_to_linear(vec3(0.2, 0.5, 1.0)); // /*const */vec3 water_color = srgb_to_linear(vec3(0.8, 0.9, 1.0)); diff --git a/assets/voxygen/shaders/include/cloud/regular.glsl b/assets/voxygen/shaders/include/cloud/regular.glsl index 0e02b3116f..31f5032b21 100644 --- a/assets/voxygen/shaders/include/cloud/regular.glsl +++ b/assets/voxygen/shaders/include/cloud/regular.glsl @@ -1,92 +1,115 @@ #include #include -const float CLOUD_THRESHOLD = 0.27; -const float CLOUD_SCALE = 5.0; -const float CLOUD_DENSITY = 150.0; - -vec2 get_cloud_heights(vec2 pos) { - const float CLOUD_HALF_WIDTH = 300; - const float CLOUD_HEIGHT_VARIATION = 1500.0; - float cloud_alt = CLOUD_AVG_ALT + (texture(t_noise, pos.xy * 0.00005).x - 0.5) * CLOUD_HEIGHT_VARIATION; - #if (CLOUD_MODE > CLOUD_MODE_MINIMAL) - cloud_alt += (texture(t_noise, pos.xy * 0.001).x - 0.5) * 0.1 * CLOUD_HEIGHT_VARIATION; - #endif - return vec2(cloud_alt, CLOUD_HALF_WIDTH); +float falloff(float x) { + return pow(max(x > 0.577 ? (0.3849 / x - 0.1) : (0.9 - x * x), 0.0), 4); } float emission_strength = clamp((sin(time_of_day.x / (3600 * 24)) - 0.8) / 0.1, 0, 1); +// Return the 'broad' density of the cloud at a position. This gets refined later with extra noise, but is important +// for computing light access. +float cloud_broad(vec3 pos) { + return 0.0 + + 2 * (noise_3d(pos / vec3(vec2(30000.0), 20000.0) / cloud_scale + 1000.0) - 0.5) + ; +} + // Returns vec4(r, g, b, density) vec4 cloud_at(vec3 pos, float dist, out vec3 emission) { // Natural attenuation of air (air naturally attenuates light that passes through it) // Simulate the atmosphere thinning as you get higher. Not physically accurate, but then // it can't be since Veloren's world is flat, not spherical. - float air = 0.00035 * clamp((10000.0 - pos.z) / 7000, 0, 1); + float atmosphere_alt = CLOUD_AVG_ALT + 40000.0; + float air = 0.00005 * clamp((atmosphere_alt - pos.z) / 20000, 0, 1); // Mist sits close to the ground in valleys (TODO: use base_alt to put it closer to water) float mist_min_alt = 0.5; - #if (CLOUD_MODE > CLOUD_MODE_LOW) - mist_min_alt = (texture(t_noise, pos.xy * 0.00015).x - 0.5) * 1.25 + 0.5; + #if (CLOUD_MODE >= CLOUD_MODE_MEDIUM) + mist_min_alt = (texture(t_noise, pos.xy / 50000.0).x - 0.5) * 1.5 + 0.5; #endif - mist_min_alt *= 250; + mist_min_alt = view_distance.z * 1.5 * (1.0 + mist_min_alt * 0.5); const float MIST_FADE_HEIGHT = 500; - float mist = 0.00125 * pow(clamp(1.0 - (pos.z - mist_min_alt) / MIST_FADE_HEIGHT, 0.0, 1), 4.0) / (1.0 + pow(1.0 + dist / 20000.0, 2.0)); + float mist = 0.00025 * pow(clamp(1.0 - (pos.z - mist_min_alt) / MIST_FADE_HEIGHT, 0.0, 1), 4.0) / (1.0 + pow(1.0 + dist / 20000.0, 2.0)); - vec3 wind_pos = vec3(pos.xy + wind_offset, pos.z); + float alt = alt_at(pos.xy - focus_off.xy); + + vec3 wind_pos = vec3(pos.xy + wind_offset, pos.z + noise_2d(pos.xy / 20000) * 500); // Clouds float cloud_tendency = cloud_tendency_at(pos.xy); float cloud = 0; - vec2 cloud_attr = get_cloud_heights(wind_pos.xy); - float cloud_factor = 0.0; - float turb_noise = 0.0; + //vec2 cloud_attr = get_cloud_heights(wind_pos.xy); float sun_access = 0.0; float moon_access = 0.0; float cloud_sun_access = 0.0; float cloud_moon_access = 0.0; + float cloud_broad_a = 0.0; + float cloud_broad_b = 0.0; // This is a silly optimisation but it actually nets us a fair few fps by skipping quite a few expensive calcs - if (cloud_tendency > 0 || mist > 0.0) { + if ((pos.z < CLOUD_AVG_ALT + 15000.0 && cloud_tendency > 0.0) || mist > 0.0) { // Turbulence (small variations in clouds/mist) const float turb_speed = -1.0; // Turbulence goes the opposite way vec3 turb_offset = vec3(1, 1, 0) * time_of_day.x * turb_speed; + mist *= 0.5 + + 4 * (noise_2d(wind_pos.xy / 20000) - 0.5) + + 1 * (noise_3d(wind_pos / 1000) - 0.5); + + float CLOUD_DEPTH = (view_distance.w - view_distance.z) * 0.8; + const float CLOUD_DENSITY = 5.0; + const float CLOUD_ALT_VARI_WIDTH = 100000.0; + const float CLOUD_ALT_VARI_SCALE = 5000.0; + float cloud_alt = CLOUD_AVG_ALT + alt * 0.5; + + cloud_broad_a = cloud_broad(wind_pos + sun_dir.xyz * 250); + cloud_broad_b = cloud_broad(wind_pos - sun_dir.xyz * 250); + cloud = cloud_tendency + (0.0 + + 24 * (cloud_broad_a + cloud_broad_b) * 0.5 #if (CLOUD_MODE >= CLOUD_MODE_MINIMAL) - turb_noise = noise_3d((wind_pos + turb_offset) * 0.001) - 0.5; + + 4 * (noise_3d((wind_pos + turb_offset) / 2000.0 / cloud_scale) - 0.5) #endif - #if (CLOUD_MODE >= CLOUD_MODE_MEDIUM) - turb_noise += (noise_3d((wind_pos + turb_offset * 0.3) * 0.004) - 0.5) * 0.35; + #if (CLOUD_MODE >= CLOUD_MODE_LOW) + + 0.5 * (noise_3d((wind_pos + turb_offset * 0.5) / 250.0 / cloud_scale) - 0.5) #endif #if (CLOUD_MODE >= CLOUD_MODE_HIGH) - turb_noise += (noise_3d((wind_pos + turb_offset * 0.3) * 0.01) - 0.5) * 0.125; + + 0.5 * (noise_3d(wind_pos / 150.0 / cloud_scale) - 0.5) #endif - mist *= 1.0 + turb_noise; - - cloud_factor = 0.25 * (1.0 - pow(min(abs(pos.z - cloud_attr.x) / (cloud_attr.y * pow(max(cloud_tendency * 20.0, 0), 0.5)), 1.0), 1.0)); - float cloud_flat = min(cloud_tendency, 0.07) * 0.05; - cloud_flat *= (1.0 + turb_noise * 7.0 * max(0, 1.0 - cloud_factor * 5)); - cloud = cloud_flat * pow(cloud_factor, 2) * 20; + ) * 0.01; + cloud = pow(cloud, 3) * sign(cloud); + cloud *= CLOUD_DENSITY * (cloud_tendency * 100) * falloff(abs(pos.z - cloud_alt) / CLOUD_DEPTH); // What proportion of sunlight is *not* being blocked by nearby cloud? (approximation) - cloud_sun_access = clamp((pos.z - cloud_attr.x + turb_noise * 250.0) * 0.002 + 0.35, 0, 1); - // Since we're assuming the sun/moon is always above (not always correct) it's the same for the moon - cloud_moon_access = sun_access; - + // Basically, just throw together a few values that roughly approximate this term and come up with an average + cloud_sun_access = (clamp(( + // Cloud density gradient + 0.25 * (cloud_broad_a - cloud_broad_b + (0.25 * (noise_3d(wind_pos / 4000 / cloud_scale) - 0.5) + 0.1 * (noise_3d(wind_pos / 1000 / cloud_scale) - 0.5))) #if (CLOUD_MODE >= CLOUD_MODE_HIGH) - // Try to calculate a reasonable approximation of the cloud normal - float cloud_tendency_x = cloud_tendency_at(pos.xy + vec2(100, 0)); - float cloud_tendency_y = cloud_tendency_at(pos.xy + vec2(0, 100)); - vec3 cloud_norm = vec3( - (cloud_tendency - cloud_tendency_x) * 4, - (cloud_tendency - cloud_tendency_y) * 4, - (pos.z - cloud_attr.x) / 250 + turb_noise + 0.5 - ); - cloud_sun_access = mix(max(dot(-sun_dir.xyz, cloud_norm) + 0.0, 0.025), cloud_sun_access, 0.25); - cloud_moon_access = mix(max(dot(-moon_dir.xyz, cloud_norm) + 0.35, 0.025), cloud_moon_access, 0.25); + // More noise + + 0.01 * (noise_3d(wind_pos / 500) / cloud_scale - 0.5) #endif + ) * 4.0 - 0.7, -1, 1) + 1.0); + // Since we're assuming the sun/moon is always above (not always correct) it's the same for the moon + cloud_moon_access = 1.0 - cloud_sun_access; } - float mist_sun_access = 0.5 + turb_noise * 0.5; + // Keeping this because it's something I'm likely to reenable later + /* + #if (CLOUD_MODE >= CLOUD_MODE_HIGH) + // Try to calculate a reasonable approximation of the cloud normal + float cloud_tendency_x = cloud_tendency_at(pos.xy + vec2(100, 0)); + float cloud_tendency_y = cloud_tendency_at(pos.xy + vec2(0, 100)); + vec3 cloud_norm = vec3( + (cloud_tendency - cloud_tendency_x) * 4, + (cloud_tendency - cloud_tendency_y) * 4, + (pos.z - cloud_attr.x) / cloud_attr.y + 0.5 + ); + cloud_sun_access = mix(max(dot(-sun_dir.xyz, cloud_norm) - 1.0, 0.025), cloud_sun_access, 0.25); + cloud_moon_access = mix(max(dot(-moon_dir.xyz, cloud_norm) - 0.6, 0.025), cloud_moon_access, 0.25); + #endif + */ + + float mist_sun_access = noise_2d(wind_pos.xy / 10000); float mist_moon_access = mist_sun_access; sun_access = mix(cloud_sun_access, mist_sun_access, clamp(mist * 20000, 0, 1)); moon_access = mix(cloud_moon_access, mist_moon_access, clamp(mist * 20000, 0, 1)); @@ -97,28 +120,21 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission) { //moon_access *= suppress_mist; // Prevent clouds and mist appearing underground (but fade them out gently) - float not_underground = clamp(1.0 - (alt_at(pos.xy - focus_off.xy) - (pos.z - focus_off.z)) / 80.0, 0, 1); + float not_underground = clamp(1.0 - (alt - (pos.z - focus_off.z)) / 80.0 + dist * 0.001, 0, 1); air *= not_underground; float vapor_density = (mist + cloud) * not_underground; if (emission_strength <= 0.0) { emission = vec3(0); } else { - float z = clamp(pos.z, 0, 10000); - float emission_alt = 4000.0; - #if (CLOUD_MODE >= CLOUD_MODE_LOW) - emission_alt += (noise_3d(vec3(wind_pos.xy * 0.00003 + cloud_tendency * 0.2, time_of_day.x * 0.0001)) - 0.5) * 6000; - #endif - #if (CLOUD_MODE >= CLOUD_MODE_HIGH) - emission_alt += (noise_3d(vec3(wind_pos.xy * 0.0005 + cloud_tendency * 0.2, emission_alt * 0.0001 + time_of_day.x * 0.0005)) - 0.5) * 1000; - #endif - float tail = (texture(t_noise, wind_pos.xy * 0.00005).x - 0.5) * 10 + (z - emission_alt) * 0.001; - vec3 emission_col = vec3(0.6 + tail * 0.6, 1.0, 0.3 + tail * 0.2); - float emission_nz = max(texture(t_noise, wind_pos.xy * 0.00003).x - 0.6, 0) / (10.0 + abs(z - emission_alt) / 40); + float emission_alt = CLOUD_AVG_ALT * 2.0 + (noise_3d(vec3(wind_pos.xy * 0.0001 + cloud_tendency * 0.2, time_of_day.x * 0.0002)) - 0.5) * 6000; #if (CLOUD_MODE >= CLOUD_MODE_MEDIUM) - emission_nz *= (1.0 + (noise_3d(vec3(wind_pos.xy * 0.05, time_of_day.x * 0.15) * 0.004) - 0.5) * 4.0); + emission_alt += (noise_3d(vec3(wind_pos.xy * 0.0005 + cloud_tendency * 0.2, emission_alt * 0.0001 + time_of_day.x * 0.001)) - 0.5) * 1000; #endif - emission = emission_col * emission_nz * emission_strength * max(sun_dir.z, 0) * 20; + float tail = (texture(t_noise, wind_pos.xy * 0.000025).x - 0.5) * 5 + (pos.z - emission_alt) * 0.0001; + vec3 emission_col = vec3(0.8 + tail * 1.5, 0.5 - tail * 0.2, 0.3 + tail * 0.2); + float emission_nz = max(pow(texture(t_noise, wind_pos.xy * 0.000015).x, 8), 0.01) * 0.25 / (10.0 + abs(pos.z - emission_alt) / 80); + emission = emission_col * emission_nz * emission_strength * max(sun_dir.z, 0) * 500000 / (1000.0 + abs(pos.z - emission_alt) * 0.1); } // We track vapor density and air density separately. Why? Because photons will ionize particles in air @@ -136,13 +152,13 @@ const float DIST_CAP = 50000; #if (CLOUD_MODE == CLOUD_MODE_ULTRA) const uint QUALITY = 200u; #elif (CLOUD_MODE == CLOUD_MODE_HIGH) - const uint QUALITY = 50u; + const uint QUALITY = 40u; #elif (CLOUD_MODE == CLOUD_MODE_MEDIUM) - const uint QUALITY = 30u; + const uint QUALITY = 18u; #elif (CLOUD_MODE == CLOUD_MODE_LOW) - const uint QUALITY = 16u; + const uint QUALITY = 6u; #elif (CLOUD_MODE == CLOUD_MODE_MINIMAL) - const uint QUALITY = 5u; + const uint QUALITY = 2u; #endif const float STEP_SCALE = DIST_CAP / (10.0 * float(QUALITY)); @@ -175,11 +191,14 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of splay += (texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 5.0 - time_of_day * 0.00005).x - 0.5) * 0.075 / (1.0 + pow(dir.z, 2) * 10); #endif + /* const float RAYLEIGH = 0.25; */ + const vec3 RAYLEIGH = vec3(0.025, 0.1, 0.5); + // Proportion of sunlight that get scattered back into the camera by clouds - float sun_scatter = max(dot(-dir, sun_dir.xyz), 0.5); - float moon_scatter = max(dot(-dir, moon_dir.xyz), 0.5); - vec3 sky_color = get_sky_color(); + float sun_scatter = dot(-dir, sun_dir.xyz) * 0.5 + 0.7; + float moon_scatter = dot(-dir, moon_dir.xyz) * 0.5 + 0.7; float net_light = get_sun_brightness() + get_moon_brightness(); + vec3 sky_color = RAYLEIGH * net_light; float cdist = max_dist; float ldist = cdist; @@ -196,22 +215,16 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of float sun_access = sample.x; float moon_access = sample.y; - float scatter_factor = 1.0 - 1.0 / (1.0 + density_integrals.x); - - const float RAYLEIGH = 0.25; + float cloud_scatter_factor = 1.0 - 1.0 / (1.0 + clamp(density_integrals.x, 0, 1)); + float global_scatter_factor = 1.0 - 1.0 / (1.0 + clamp(density_integrals.y, 0, 1)); surf_color = // Attenuate light passing through the clouds - surf_color * (1.0 - scatter_factor) + - // This is not rayleigh scattering, but it's good enough for our purposes (only considers sun) - (1.0 - surf_color) * net_light * sky_color * density_integrals.y * RAYLEIGH + - // Add the directed light light scattered into the camera by the clouds - get_sun_color() * sun_scatter * sun_access * scatter_factor * get_sun_brightness() + - get_moon_color() * moon_scatter * moon_access * scatter_factor * get_moon_brightness() + - emission * density_integrals.y + - // Global illumination (uniform scatter from the sky) - sky_color * sun_access * scatter_factor * get_sun_brightness() + - sky_color * moon_access * scatter_factor * get_moon_brightness(); + surf_color * (1.0 - cloud_scatter_factor - global_scatter_factor) + + // Add the directed light light scattered into the camera by the clouds and the atmosphere (global illumination) + get_sun_color() * sun_scatter * get_sun_brightness() * (sun_access * cloud_scatter_factor + sky_color * global_scatter_factor) + + get_moon_color() * moon_scatter * get_moon_brightness() * (moon_access * cloud_scatter_factor + sky_color * global_scatter_factor) + + emission * density_integrals.y; } return surf_color; diff --git a/assets/voxygen/shaders/include/sky.glsl b/assets/voxygen/shaders/include/sky.glsl index b614efbd7f..bbeb51c074 100644 --- a/assets/voxygen/shaders/include/sky.glsl +++ b/assets/voxygen/shaders/include/sky.glsl @@ -18,14 +18,14 @@ const float PI = 3.141592; const vec3 SKY_DAY_TOP = vec3(0.1, 0.5, 0.9); const vec3 SKY_DAY_MID = vec3(0.02, 0.28, 0.8); const vec3 SKY_DAY_BOT = vec3(0.1, 0.2, 0.3); -const vec3 DAY_LIGHT = vec3(2.8, 3.5, 1.8); -const vec3 SUN_HALO_DAY = vec3(0.06, 0.06, 0.005); +const vec3 DAY_LIGHT = vec3(3.8, 3.0, 1.8); +const vec3 SUN_HALO_DAY = vec3(0.8, 0.8, 0.001); const vec3 SKY_DUSK_TOP = vec3(0.06, 0.1, 0.20); const vec3 SKY_DUSK_MID = vec3(0.35, 0.1, 0.15); const vec3 SKY_DUSK_BOT = vec3(0.0, 0.1, 0.23); const vec3 DUSK_LIGHT = vec3(8.0, 1.5, 0.15); -const vec3 SUN_HALO_DUSK = vec3(1.2, 0.15, 0.01); +const vec3 SUN_HALO_DUSK = vec3(2.2, 0.5, 0.1); const vec3 SKY_NIGHT_TOP = vec3(0.001, 0.001, 0.0025); const vec3 SKY_NIGHT_MID = vec3(0.001, 0.005, 0.02); @@ -76,17 +76,16 @@ vec3 glow_light(vec3 pos) { // return normalize(-vec3(sin(moon_angle_rad), 0.0, cos(moon_angle_rad) - 0.5)); //} -float CLOUD_AVG_ALT = view_distance.z + 0.75 * view_distance.w; +float CLOUD_AVG_ALT = view_distance.z + (view_distance.w - view_distance.z) * 1.25; const float wind_speed = 0.25; vec2 wind_offset = vec2(time_of_day.x * wind_speed); +float cloud_scale = view_distance.z / 150.0; + float cloud_tendency_at(vec2 pos) { - float nz = texture(t_noise, (pos + wind_offset) * 0.000075).x - 0.5; - nz = clamp(nz, 0, 1); - #if (CLOUD_MODE >= CLOUD_MODE_MEDIUM) - nz += (texture(t_noise, (pos + wind_offset) * 0.00035).x - 0.5) * 0.15; - #endif + float nz = texture(t_noise, (pos + wind_offset) / 60000.0 / cloud_scale).x - 0.3; + nz = pow(clamp(nz, 0, 1), 4); return nz; } @@ -101,9 +100,7 @@ float cloud_shadow(vec3 pos, vec3 light_dir) { float fade = 1.0 - clamp((length(xy_offset) - FADE_RANGE.x) / (FADE_RANGE.y - FADE_RANGE.x), 0, 1); float cloud = cloud_tendency_at(pos.xy + focus_off.xy - xy_offset); - cloud = cloud * 2.0; - - return clamp(1 - fade * cloud * 1.65, 0, 1); + return clamp(1 - fade * cloud * 16.0, 0, 1); #endif } @@ -112,7 +109,7 @@ float get_sun_brightness(/*vec3 sun_dir*/) { } float get_moon_brightness(/*vec3 moon_dir*/) { - return max(-moon_dir.z + 0.6, 0.0) * 0.2; + return max(-moon_dir.z + 0.6, 0.0) * 0.05; } vec3 get_sun_color(/*vec3 sun_dir*/) { @@ -142,7 +139,7 @@ vec3 get_sky_color(/*vec3 sun_dir*/) { } vec3 get_moon_color(/*vec3 moon_dir*/) { - return vec3(0.05, 0.05, 0.6); + return vec3(0.05, 0.05, 1.6); } DirectionalLight get_sun_info(vec4 _dir, float shade_frac/*, vec4 light_pos[2]*/, /*vec4 sun_pos*/vec3 f_pos) { @@ -413,7 +410,7 @@ float is_star_at(vec3 dir) { //return 0.0; - return 1.0 / (1.0 + pow(dist * 1000, 8)); + return 1.0 / (1.0 + pow(dist * 750, 8)); } vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float quality, bool with_features, float refractionIndex) { @@ -434,7 +431,7 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q } // Sun - const vec3 SUN_SURF_COLOR = vec3(1.5, 0.9, 0.35) * 3.0; + const vec3 SUN_SURF_COLOR = vec3(1.5, 0.9, 0.35) * 8.0; vec3 sun_halo_color = mix( SUN_HALO_DUSK, @@ -442,7 +439,7 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q max(-sun_dir.z, 0.0) ); - vec3 sun_halo = sun_halo_color * 16 * pow(max(dot(dir, -sun_dir), 0), 8.0); + vec3 sun_halo = sun_halo_color * 4 * pow(max(dot(dir, -sun_dir), 0), 20.0); vec3 sun_surf = vec3(0); if (with_features) { float angle = 0.00035; @@ -451,11 +448,11 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q vec3 sun_light = sun_halo + sun_surf; // Moon - const vec3 MOON_SURF_COLOR = vec3(0.7, 1.0, 1.5) * 3.0; - const vec3 MOON_HALO_COLOR = vec3(0.015, 0.015, 0.05) * 25; + const vec3 MOON_SURF_COLOR = vec3(0.7, 1.0, 1.5) * 20.0; + const vec3 MOON_HALO_COLOR = vec3(0.015, 0.015, 0.05) * 48; vec3 moon_halo_color = MOON_HALO_COLOR; - vec3 moon_halo = moon_halo_color * pow(max(dot(dir, -moon_dir), 0), 500.0); + vec3 moon_halo = moon_halo_color * pow(max(dot(dir, -moon_dir), 0), 100.0); vec3 moon_surf = vec3(0); if (with_features) { float angle = 0.00035; @@ -465,52 +462,50 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q // Replaced all clamp(sun_dir, 0, 1) with max(sun_dir, 0) because sun_dir is calculated from sin and cos, which are never > 1 - vec3 sky_top = mix( - mix( - SKY_DUSK_TOP + star / (1.0 + moon_surf * 100.0), - SKY_NIGHT_TOP + star / (1.0 + moon_surf * 100.0), - max(pow(sun_dir.z, 0.2), 0) - ), - SKY_DAY_TOP, - max(-sun_dir.z, 0) - ); + #if (CLOUD_MODE == CLOUD_MODE_NONE) + vec3 sky_top = mix( + mix( + SKY_DUSK_TOP + star / (1.0 + moon_surf * 100.0), + SKY_NIGHT_TOP + star / (1.0 + moon_surf * 100.0), + max(pow(sun_dir.z, 0.2), 0) + ), + SKY_DAY_TOP, + max(-sun_dir.z, 0) + ); - vec3 sky_mid = mix( - mix( SKY_DUSK_MID, - SKY_NIGHT_MID, - max(pow(sun_dir.z, 0.2), 0) - ), - SKY_DAY_MID, - max(-sun_dir.z, 0) - ); + vec3 sky_mid = mix( + mix( SKY_DUSK_MID, + SKY_NIGHT_MID, + max(pow(sun_dir.z, 0.2), 0) + ), + SKY_DAY_MID, + max(-sun_dir.z, 0) + ); - vec3 sky_bot = mix( - mix( - SKY_DUSK_BOT, - SKY_NIGHT_BOT, - max(pow(sun_dir.z, 0.2), 0) - ), - SKY_DAY_BOT, - max(-sun_dir.z, 0) - ); + vec3 sky_bot = mix( + mix( + SKY_DUSK_BOT, + SKY_NIGHT_BOT, + max(pow(sun_dir.z, 0.2), 0) + ), + SKY_DAY_BOT, + max(-sun_dir.z, 0) + ); - vec3 sky_color = mix( - mix( - sky_mid, - sky_bot, - pow(max(-dir.z, 0), 0.4) - ), - sky_top, - max(dir.z, 0) - ); + vec3 sky_color = mix( + mix( + sky_mid, + sky_bot, + pow(max(-dir.z, 0), 0.4) + ), + sky_top, + max(dir.z, 0) + ); + #else + vec3 sky_color = vec3(0) + star; + #endif - // Approximate distance to fragment - float f_dist = distance(origin, f_pos); - - if (f_dist > 5000.0) { - sky_color += sun_light + moon_light; - } - return sky_color; + return sky_color + sun_light + moon_light; } vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float quality, bool with_stars) { diff --git a/assets/voxygen/shaders/lod-terrain-frag.glsl b/assets/voxygen/shaders/lod-terrain-frag.glsl index defb468ec7..1fe702656c 100644 --- a/assets/voxygen/shaders/lod-terrain-frag.glsl +++ b/assets/voxygen/shaders/lod-terrain-frag.glsl @@ -648,7 +648,7 @@ void main() { float passthrough = dot(faceforward(f_norm, f_norm, cam_to_frag), -cam_to_frag); vec3 reflect_color = get_sky_color(reflect_ray, time_of_day.x, f_pos, vec3(-100000), 0.125, true); - reflect_color = get_cloud_color(reflect_color, reflect_ray, cam_pos.xyz, time_of_day.x, 100000.0, 0.25); + reflect_color = get_cloud_color(reflect_color, reflect_ray, cam_pos.xyz, time_of_day.x, 100000.0, 0.1); const float REFLECTANCE = 0.5; surf_color = illuminate(max_light, view_dir, f_col * emitted_light, reflect_color * REFLECTANCE + water_color * reflected_light); diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index 1e632c8ff0..e19bb3eb34 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -294,7 +294,7 @@ void main() { ); } else if (inst_mode == SNOW) { float height = mix(-4, 60, pow(start_end(1, 0), 3)); - float wind_speed = (inst_pos.z - 250) * 0.025; + float wind_speed = (inst_pos.z - 2000) * 0.025; vec3 offset = linear_motion(vec3(0), vec3(1, 1, 0) * wind_speed); float end_alt = alt_at(start_pos.xy + offset.xy); attr = Attr( diff --git a/assets/voxygen/texture/noise.png b/assets/voxygen/texture/noise.png index faef1bed6b..0ff406ea81 100644 --- a/assets/voxygen/texture/noise.png +++ b/assets/voxygen/texture/noise.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9c41eb6e06bf9fc61135ab9009bf81a6eaf55f34101d698032650188187670d4 -size 9532 +oid sha256:079f7e84955e6592d6b01bf386aa6533332f56aee0a98da5b6da95a58b1ea6ac +size 3340 diff --git a/assets/world/map/veloren_0_6_0_0.bin b/assets/world/map/veloren_0_6_0_0.bin deleted file mode 100644 index 6056e7869c..0000000000 --- a/assets/world/map/veloren_0_6_0_0.bin +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d021e9faef8b1a34a7a3f28f80d7a057cd9b536025898e6c21ca01c40fecca7f -size 16777236 diff --git a/assets/world/map/veloren_0_9_0_0.bin b/assets/world/map/veloren_0_9_0_0.bin new file mode 100644 index 0000000000..87ffd860e1 --- /dev/null +++ b/assets/world/map/veloren_0_9_0_0.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:16f43f83ba897f290eaa3a73c94a1d085de44d86a4faf9de8b834b706683ce60 +size 16777252 diff --git a/client/src/lib.rs b/client/src/lib.rs index fb41f7bc77..2b6019d3a4 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -33,7 +33,7 @@ use common::{ grid::Grid, outcome::Outcome, recipe::RecipeBook, - resources::PlayerEntity, + resources::{DeltaTime, PlayerEntity, TimeOfDay}, terrain::{block::Block, neighbors, BiomeKind, SitesKind, TerrainChunk, TerrainChunkSize}, trade::{PendingTrade, SitePrices, TradeAction, TradeId, TradeResult}, uid::{Uid, UidAllocator}, @@ -1472,7 +1472,9 @@ impl Client { } }, ServerGeneral::TimeOfDay(time_of_day) => { - *self.state.ecs_mut().write_resource() = time_of_day; + let dt = self.state.ecs().read_resource::().0; + let mut tod = self.state.ecs_mut().write_resource::(); + tod.0 = Lerp::lerp(tod.0, time_of_day.0, dt as f64); }, ServerGeneral::EntitySync(entity_sync_package) => { self.state diff --git a/common/src/cmd.rs b/common/src/cmd.rs index a1692dbabf..e2868f0f10 100644 --- a/common/src/cmd.rs +++ b/common/src/cmd.rs @@ -80,6 +80,7 @@ pub enum ChatCommand { Safezone, Say, SetMotd, + Site, SkillPoint, Spawn, Sudo, @@ -140,6 +141,7 @@ pub static CHAT_COMMANDS: &[ChatCommand] = &[ ChatCommand::Safezone, ChatCommand::Say, ChatCommand::SetMotd, + ChatCommand::Site, ChatCommand::SkillPoint, ChatCommand::Spawn, ChatCommand::Sudo, @@ -438,6 +440,9 @@ impl ChatCommand { ChatCommand::SetMotd => { cmd(vec![Message(Optional)], "Set the server description", Admin) }, + // Uses Message because site names can contain spaces, which would be assumed to be + // separators otherwise + ChatCommand::Site => cmd(vec![Message(Required)], "Teleport to a site", Admin), ChatCommand::SkillPoint => cmd( vec![ Enum("skill tree", SKILL_TREES.clone(), Required), @@ -546,6 +551,7 @@ impl ChatCommand { ChatCommand::Safezone => "safezone", ChatCommand::Say => "say", ChatCommand::SetMotd => "set_motd", + ChatCommand::Site => "site", ChatCommand::SkillPoint => "skill_point", ChatCommand::Spawn => "spawn", ChatCommand::Sudo => "sudo", diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 90796fce26..3d0d3db1e9 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -127,6 +127,7 @@ fn get_handler(cmd: &ChatCommand) -> CommandHandler { ChatCommand::Safezone => handle_safezone, ChatCommand::Say => handle_say, ChatCommand::SetMotd => handle_set_motd, + ChatCommand::Site => handle_site, ChatCommand::SkillPoint => handle_skill_point, ChatCommand::Spawn => handle_spawn, ChatCommand::Sudo => handle_sudo, @@ -463,6 +464,51 @@ fn handle_goto( } } +fn handle_site( + server: &mut Server, + client: EcsEntity, + target: EcsEntity, + args: String, + action: &ChatCommand, +) { + if let Ok(dest_name) = scan_fmt!(&args, &action.arg_fmt(), String) { + if server + .state + .read_component_copied::(target) + .is_some() + { + match server.world.civs().sites().find(|site| { + site.site_tmp + .map_or(false, |id| server.index.sites[id].name() == dest_name) + }) { + Some(site) => { + let pos = server + .world + .find_lowest_accessible_pos(server.index.as_index_ref(), site.center); + server.state.write_component(target, comp::Pos(pos)); + server.state.write_component(target, comp::ForceUpdate); + }, + None => { + server.notify_client( + client, + ServerGeneral::server_msg(ChatType::CommandError, "Site not found"), + ); + }, + }; + } else { + server.notify_client( + client, + ServerGeneral::server_msg(ChatType::CommandError, "You have no position."), + ); + } + } else { + server.notify_client( + client, + ServerGeneral::server_msg(ChatType::CommandError, action.help_string()), + ); + } +} + fn handle_home( server: &mut Server, client: EcsEntity, diff --git a/server/src/lib.rs b/server/src/lib.rs index c9fc9484a4..3869da74eb 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -66,7 +66,6 @@ use common::{ slowjob::SlowJobPool, terrain::TerrainChunkSize, uid::UidAllocator, - vol::{ReadVol, RectVolSize}, }; use common_ecs::run_now; use common_net::{ @@ -297,50 +296,28 @@ impl Server { // but are needed to be explicit about casting (and to make the compiler stop // complaining) - // spawn in the chunk, that is in the middle of the world - let center_chunk: Vec2 = world.sim().map_size_lg().chunks().map(i32::from) / 2; - - // Find a town to spawn in that's close to the centre of the world - let spawn_chunk = world - .civs() - .sites() - .filter(|site| matches!(site.kind, world::civ::SiteKind::Settlement)) - .map(|site| site.center) - .min_by_key(|site_pos| site_pos.distance_squared(center_chunk)) - .unwrap_or(center_chunk); - - // Calculate the middle of the chunk in the world - let spawn_wpos = TerrainChunkSize::center_wpos(spawn_chunk); - - // Unwrapping because generate_chunk only returns err when should_continue evals - // to true - let (tc, _cs) = world.generate_chunk(index, spawn_chunk, || false).unwrap(); - let min_z = tc.get_min_z(); - let max_z = tc.get_max_z(); - - let pos = Vec3::new(spawn_wpos.x, spawn_wpos.y, min_z); - (0..(max_z - min_z)) - .map(|z_diff| pos + Vec3::unit_z() * z_diff) - .find(|test_pos| { - let chunk_relative_xy = test_pos - .xy() - .map2(TerrainChunkSize::RECT_SIZE, |e, sz| e.rem_euclid(sz as i32)); - tc.get( - Vec3::new(chunk_relative_xy.x, chunk_relative_xy.y, test_pos.z) - - Vec3::unit_z(), - ) - .map_or(false, |b| b.is_filled()) - && (0..3).all(|z| { - tc.get( - Vec3::new(chunk_relative_xy.x, chunk_relative_xy.y, test_pos.z) - + Vec3::unit_z() * z, - ) - .map_or(true, |b| !b.is_solid()) - }) + // Search for town defined by spawn_town server setting. If this fails, or is + // None, set spawn to the nearest town to the centre of the world + let spawn_chunk = match settings.spawn_town.as_ref().and_then(|spawn_town| { + world.civs().sites().find(|site| { + site.site_tmp + .map_or(false, |id| index.sites[id].name() == spawn_town) }) - .unwrap_or(pos) - .map(|e| e as f32) - + 0.5 + }) { + Some(t) => t.center, + None => { + let center_chunk = world.sim().map_size_lg().chunks().map(i32::from) / 2; + world + .civs() + .sites() + .filter(|site| matches!(site.kind, world::civ::SiteKind::Settlement)) + .map(|site| site.center) + .min_by_key(|site_pos| site_pos.distance_squared(center_chunk)) + .unwrap_or(center_chunk) + }, + }; + + world.find_lowest_accessible_pos(index, spawn_chunk) }; #[cfg(not(feature = "worldgen"))] let spawn_point = Vec3::new(0.0, 0.0, 256.0); diff --git a/server/src/rtsim/mod.rs b/server/src/rtsim/mod.rs index 68528e237f..d364462d9b 100644 --- a/server/src/rtsim/mod.rs +++ b/server/src/rtsim/mod.rs @@ -98,7 +98,7 @@ pub fn init(state: &mut State, #[cfg(feature = "worldgen")] world: &world::World #[cfg(not(feature = "worldgen"))] let mut rtsim = RtSim::new(Vec2::new(40, 40)); - for _ in 0..2500 { + for _ in 0..world.sim().get_size().product() / 400 { let pos = rtsim .chunks .size() diff --git a/server/src/settings.rs b/server/src/settings.rs index 121c7fd4b6..67a1af3817 100644 --- a/server/src/settings.rs +++ b/server/src/settings.rs @@ -16,7 +16,7 @@ use std::{ use tracing::{error, warn}; use world::sim::FileOpts; -const DEFAULT_WORLD_SEED: u32 = 59686; +const DEFAULT_WORLD_SEED: u32 = 25269; const CONFIG_DIR: &str = "server_config"; const SETTINGS_FILENAME: &str = "settings.ron"; const WHITELIST_FILENAME: &str = "whitelist.ron"; @@ -42,6 +42,7 @@ pub struct Settings { pub banned_words_files: Vec, pub max_player_group_size: u32, pub client_timeout: Duration, + pub spawn_town: Option, } impl Default for Settings { @@ -59,6 +60,7 @@ impl Default for Settings { banned_words_files: Vec::new(), max_player_group_size: 6, client_timeout: Duration::from_secs(40), + spawn_town: None, } } } diff --git a/world/src/civ/mod.rs b/world/src/civ/mod.rs index bf481901d2..84b5178a45 100644 --- a/world/src/civ/mod.rs +++ b/world/src/civ/mod.rs @@ -86,8 +86,7 @@ impl Civs { let initial_civ_count = initial_civ_count(sim.map_size_lg()); let mut ctx = GenCtx { sim, rng }; - // TODO: Care about world size when generating caves. - for _ in 0..100 { + for _ in 0..ctx.sim.get_size().product() / 10_000 { this.generate_cave(&mut ctx); } @@ -251,13 +250,13 @@ impl Civs { .into_iter() .for_each(|posi| { let chpos = uniform_idx_as_vec2(ctx.sim.map_size_lg(), posi); - let wpos = chpos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32); + let wpos = chpos.map(|e| e as i64) * TerrainChunkSize::RECT_SIZE.map(|e| e as i64); let closest_site = (*sites) .iter_mut() .filter(|s| !matches!(s.1.kind, crate::site::SiteKind::Dungeon(_))) - .min_by_key(|(_id, s)| s.get_origin().distance_squared(wpos)); + .min_by_key(|(_id, s)| s.get_origin().map(|e| e as i64).distance_squared(wpos)); if let Some((_id, s)) = closest_site { - let distance_squared = s.get_origin().distance_squared(wpos); + let distance_squared = s.get_origin().map(|e| e as i64).distance_squared(wpos); s.economy .add_chunk(ctx.sim.get(chpos).unwrap(), distance_squared); } diff --git a/world/src/lib.rs b/world/src/lib.rs index 749ae305c4..87eae3c622 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -165,6 +165,41 @@ impl World { pub fn sample_blocks(&self) -> BlockGen { BlockGen::new(ColumnGen::new(&self.sim)) } + pub fn find_lowest_accessible_pos(&self, index: IndexRef, chunk_pos: Vec2) -> Vec3 { + // Calculate the middle of the chunk in the world + let spawn_wpos = TerrainChunkSize::center_wpos(chunk_pos); + + // Unwrapping because generate_chunk only returns err when should_continue evals + // to true + let (tc, _cs) = self.generate_chunk(index, chunk_pos, || false).unwrap(); + let min_z = tc.get_min_z(); + let max_z = tc.get_max_z(); + + let pos = Vec3::new(spawn_wpos.x, spawn_wpos.y, min_z); + (0..(max_z - min_z)) + .map(|z_diff| pos + Vec3::unit_z() * z_diff) + .find(|test_pos| { + let chunk_relative_xy = test_pos + .xy() + .map2(TerrainChunkSize::RECT_SIZE, |e, sz| e.rem_euclid(sz as i32)); + tc.get( + Vec3::new(chunk_relative_xy.x, chunk_relative_xy.y, test_pos.z) + - Vec3::unit_z(), + ) + .map_or(false, |b| b.is_filled()) + && (0..3).all(|z| { + tc.get( + Vec3::new(chunk_relative_xy.x, chunk_relative_xy.y, test_pos.z) + + Vec3::unit_z() * z, + ) + .map_or(true, |b| !b.is_solid()) + }) + }) + .unwrap_or(pos) + .map(|e| e as f32) + + 0.5 + } + #[allow(clippy::or_fun_call)] // TODO: Pending review in #587 #[allow(clippy::eval_order_dependence)] #[allow(clippy::result_unit_err)] diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 7b064c02db..198eb31e93 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -265,7 +265,7 @@ pub type ModernMap = WorldMap_0_7_0; /// with changing versions, or at least keep it in a constant somewhere that's /// easy to change. #[allow(clippy::redundant_static_lifetimes)] // TODO: Pending review in #587 -pub const DEFAULT_WORLD_MAP: &'static str = "world.map.veloren_0_6_0_0"; +pub const DEFAULT_WORLD_MAP: &'static str = "world.map.veloren_0_9_0_0"; impl WorldFileLegacy { #[inline] @@ -462,7 +462,7 @@ impl WorldSim { // // FIXME: This is a hack! At some point we will hae a more principled way of // dealing with this. - let continent_scale_hack = 1.0/*4.0*/; + let continent_scale_hack = 2.0/*4.0*/; let (parsed_world_file, map_size_lg) = parsed_world_file .and_then(|map| match MapSizeLg::new(map.map_size_lg) { Ok(map_size_lg) => Some((Some(map), map_size_lg)), diff --git a/world/src/sim2/mod.rs b/world/src/sim2/mod.rs index 4235ffa96b..f3dd81a083 100644 --- a/world/src/sim2/mod.rs +++ b/world/src/sim2/mod.rs @@ -568,7 +568,7 @@ fn trade_at_site( break; } } - let mut paid_amount = allocated_amount - balance / *price; + let mut paid_amount = (allocated_amount - balance / *price).min(economy.stocks[*g]); if paid_amount / allocated_amount < 0.95 { debug!( "Client {} is broke on {:?} : {} {} severity {}", diff --git a/world/src/site/economy.rs b/world/src/site/economy.rs index 51f8fa1039..296c22f540 100644 --- a/world/src/site/economy.rs +++ b/world/src/site/economy.rs @@ -279,7 +279,7 @@ impl Economy { // info!("resources {:?}", self.stocks); } - pub fn add_chunk(&mut self, ch: &SimChunk, distance_squared: i32) { + pub fn add_chunk(&mut self, ch: &SimChunk, distance_squared: i64) { let biome = ch.get_biome(); // we don't scale by pi, although that would be correct let distance_bin = (distance_squared >> 16).min(64) as usize;