From 49df604de074ef0b98be9a04b75793c1dd16cd0c Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 16 Nov 2020 12:56:32 +0000 Subject: [PATCH] Better scattering and scatter (of both varieties) --- assets/voxygen/i18n/en.ron | 1 + .../shaders/include/cloud/regular.glsl | 34 ++++++++------- assets/voxygen/shaders/include/constants.glsl | 1 + assets/voxygen/shaders/include/sky.glsl | 4 +- assets/voxygen/shaders/lod-terrain-frag.glsl | 2 +- voxygen/src/hud/settings_window.rs | 4 ++ voxygen/src/render/mod.rs | 42 +++++-------------- voxygen/src/render/renderer.rs | 1 + world/src/layer/scatter.rs | 5 ++- world/src/lib.rs | 2 +- 10 files changed, 43 insertions(+), 53 deletions(-) diff --git a/assets/voxygen/i18n/en.ron b/assets/voxygen/i18n/en.ron index a705027832..fd223268cc 100644 --- a/assets/voxygen/i18n/en.ron +++ b/assets/voxygen/i18n/en.ron @@ -346,6 +346,7 @@ magically infused items?"#, "hud.settings.cloud_rendering_mode.low": "Low", "hud.settings.cloud_rendering_mode.medium": "Medium", "hud.settings.cloud_rendering_mode.high": "High", + "hud.settings.cloud_rendering_mode.ultra": "Ultra", "hud.settings.fullscreen": "Fullscreen", "hud.settings.fullscreen_mode": "Fullscreen Mode", "hud.settings.fullscreen_mode.exclusive": "Exclusive", diff --git a/assets/voxygen/shaders/include/cloud/regular.glsl b/assets/voxygen/shaders/include/cloud/regular.glsl index d059a3eaee..1d14c1c60b 100644 --- a/assets/voxygen/shaders/include/cloud/regular.glsl +++ b/assets/voxygen/shaders/include/cloud/regular.glsl @@ -40,13 +40,13 @@ vec4 cloud_at(vec3 pos, float dist) { // 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; - #if (CLOUD_MODE != CLOUD_MODE_MINIMAL) + #if (CLOUD_MODE >= CLOUD_MODE_MINIMAL) turb_noise = noise_3d((wind_pos + turb_offset) * 0.001) - 0.5; #endif - #if (CLOUD_MODE == CLOUD_MODE_MEDIUM || CLOUD_MODE == CLOUD_MODE_HIGH) + #if (CLOUD_MODE >= CLOUD_MODE_MEDIUM) turb_noise += (noise_3d((wind_pos + turb_offset * 0.3) * 0.004) - 0.5) * 0.35; #endif - #if (CLOUD_MODE == CLOUD_MODE_HIGH) + #if (CLOUD_MODE >= CLOUD_MODE_HIGH) turb_noise += (noise_3d((wind_pos + turb_offset * 0.3) * 0.01) - 0.5) * 0.125; #endif mist *= (1.0 + turb_noise); @@ -62,14 +62,14 @@ vec4 cloud_at(vec3 pos, float dist) { // Since we're assuming the sun/moon is always above (not always correct) it's the same for the moon float moon_access = sun_access; - #if (CLOUD_MODE == CLOUD_MODE_HIGH) + #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) * 7.5, - (cloud_tendency - cloud_tendency_y) * 7.5, - (pos.z - cloud_attr.x) / 250 + turb_noise * 1 + (cloud_tendency - cloud_tendency_x) * 6, + (cloud_tendency - cloud_tendency_y) * 6, + (pos.z - cloud_attr.x) / 250 + turb_noise ); sun_access = mix(clamp(dot(-sun_dir.xyz, cloud_norm), 0.025, 1), sun_access, 0.25); moon_access = mix(clamp(dot(-moon_dir.xyz, cloud_norm), 0.025, 1), moon_access, 0.25); @@ -96,14 +96,16 @@ float atan2(in float y, in float x) { } const float DIST_CAP = 50000; -#if (CLOUD_MODE == CLOUD_MODE_HIGH) - const uint QUALITY = 100u; +#if (CLOUD_MODE == CLOUD_MODE_ULTRA) + const uint QUALITY = 200u; +#elif (CLOUD_MODE == CLOUD_MODE_HIGH) + const uint QUALITY = 50u; #elif (CLOUD_MODE == CLOUD_MODE_MEDIUM) - const uint QUALITY = 40u; + const uint QUALITY = 30u; #elif (CLOUD_MODE == CLOUD_MODE_LOW) - const uint QUALITY = 20u; + const uint QUALITY = 16u; #elif (CLOUD_MODE == CLOUD_MODE_MINIMAL) - const uint QUALITY = 7u; + const uint QUALITY = 5u; #endif const float STEP_SCALE = DIST_CAP / (10.0 * float(QUALITY)); @@ -155,11 +157,13 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of float moon_access = sample.y; float scatter_factor = 1.0 - 1.0 / (1.0 + density_integrals.x); + const float RAYLEIGH = 0.5; + surf_color = - // Attenuate light passing through the clouds, removing light due to rayleigh scattering (transmission component) - surf_color * (1.0 - scatter_factor) - surf_color * density_integrals.y * sky_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) - sky_color * net_light * density_integrals.y + + (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() + // Really we should multiple by just moon_brightness here but this just looks better given that we lack HDR diff --git a/assets/voxygen/shaders/include/constants.glsl b/assets/voxygen/shaders/include/constants.glsl index 8d83b88955..f1bc2a8aa9 100644 --- a/assets/voxygen/shaders/include/constants.glsl +++ b/assets/voxygen/shaders/include/constants.glsl @@ -14,6 +14,7 @@ #define CLOUD_MODE_LOW 2 #define CLOUD_MODE_MEDIUM 3 #define CLOUD_MODE_HIGH 4 +#define CLOUD_MODE_ULTRA 5 #define LIGHTING_ALGORITHM_LAMBERTIAN 0 #define LIGHTING_ALGORITHM_BLINN_PHONG 1 diff --git a/assets/voxygen/shaders/include/sky.glsl b/assets/voxygen/shaders/include/sky.glsl index a8a0dfd209..1519cc7661 100644 --- a/assets/voxygen/shaders/include/sky.glsl +++ b/assets/voxygen/shaders/include/sky.glsl @@ -72,14 +72,14 @@ vec2 wind_offset = vec2(time_of_day.x * wind_speed); 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 || CLOUD_MODE == CLOUD_MODE_HIGH) + #if (CLOUD_MODE >= CLOUD_MODE_MEDIUM) nz += (texture(t_noise, (pos + wind_offset) * 0.00035).x - 0.5) * 0.15; #endif return nz; } float cloud_shadow(vec3 pos, vec3 light_dir) { - #if (CLOUD_MODE == CLOUD_MODE_NONE || CLOUD_MODE == CLOUD_MODE_MINIMAL) + #if (CLOUD_MODE <= CLOUD_MODE_MINIMAL) return 1.0; #else vec2 xy_offset = light_dir.xy * ((CLOUD_AVG_ALT - pos.z) / -light_dir.z); diff --git a/assets/voxygen/shaders/lod-terrain-frag.glsl b/assets/voxygen/shaders/lod-terrain-frag.glsl index 192840146c..217f1ea460 100644 --- a/assets/voxygen/shaders/lod-terrain-frag.glsl +++ b/assets/voxygen/shaders/lod-terrain-frag.glsl @@ -342,7 +342,7 @@ void main() { } else { f_ao *= mix(1.0, clamp(pow(fract(my_alt), 0.5), 0, 1), voxelize_factor); - if (fract(f_pos.x) * abs(my_norm.x / cam_dir.x) < fract(f_pos.y) * abs(my_norm.y / cam_dir.y)) {//cam_dir.x / my_norm.x + clamp(dot(vec3(1, 0, 0), -cam_dir), 0, 1)) { + if (fract(f_pos.x) * abs(my_norm.y / cam_dir.x) < fract(f_pos.y) * abs(my_norm.x / cam_dir.y)) { voxel_norm = vec3(sign(cam_dir.x), 0, 0); } else { voxel_norm = vec3(0, sign(cam_dir.y), 0); diff --git a/voxygen/src/hud/settings_window.rs b/voxygen/src/hud/settings_window.rs index 506b0f1aa8..a38a1b4980 100644 --- a/voxygen/src/hud/settings_window.rs +++ b/voxygen/src/hud/settings_window.rs @@ -2125,6 +2125,7 @@ impl<'a> Widget for SettingsWindow<'a> { CloudMode::Low, CloudMode::Medium, CloudMode::High, + CloudMode::Ultra, ]; let mode_label_list = [ &self.localized_strings.get("common.none"), @@ -2140,6 +2141,9 @@ impl<'a> Widget for SettingsWindow<'a> { &self .localized_strings .get("hud.settings.cloud_rendering_mode.high"), + &self + .localized_strings + .get("hud.settings.cloud_rendering_mode.ultra"), ]; // Get which cloud rendering mode is currently active diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 0c69b2cd86..57d57ebdf3 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -110,45 +110,23 @@ impl Default for AaMode { /// Cloud modes #[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)] pub enum CloudMode { - /// No clouds. On computers that can't handle loops well, have performance - /// issues in fragment shaders in general, or just have large - /// resolutions, this can be a *very* impactful performance difference. - /// Part of that is because of inefficiencies in how we implement - /// regular clouds. It is still not all that cheap on low-end machines, due - /// to many calculations being performed that use relatively expensive - /// functions, and at some point I'd like to both optimize the regular - /// sky shader further and create an even cheaper option. + /// No clouds. As cheap as it gets. None, - /// Volumetric clouds. This option can be *very* expensive on low-end - /// machines, to the point of making the game unusable, for several - /// reasons: - /// - /// - The volumetric clouds use raymarching, which will cause catastrophic - /// performance degradation on GPUs without good support for loops. There - /// is an attempt to minimize the impact of this using a z-range check, - /// but on some low-end GPUs (such as some integrated graphics cards) this - /// test doesn't appear to be able to be predicted well at shader - /// invocation time. - /// - The cloud computations themselves are fairly involved, further - /// degrading performance. - /// - Although the sky shader is always drawn at the outer edges of the - /// skybox, the clouds themselves are supposed to be positioned much - /// lower, which means the depth check for the skybox incorrectly cuts off - /// clouds in some places. To compensate for these cases (e.g. where - /// terrain is occluded by clouds from above, and the camera is above the - /// clouds), we currently branch to see if we need to render the clouds in - /// *every* fragment shader. For machines that can't optimize the check, - /// this is absurdly expensive, so we should look at alternatives in the - /// future that player better with the GPU. + /// Clouds, but barely. Ideally, any machine should be able to handle this just fine. Minimal, + /// Enough visual detail to be pleasing, but generally using poor-but-cheap approximations to derive parameters Low, - High, - #[serde(other)] + /// More detail. Enough to look good in most cases. For those that value looks but also high framerates. Medium, + /// High, but with extra compute power thrown at it to smooth out subtle imperfections + Ultra, + /// Lots of detail with good-but-costly derivation of parameters. + #[serde(other)] + High, } impl Default for CloudMode { - fn default() -> Self { CloudMode::Medium } + fn default() -> Self { CloudMode::High } } /// Fluid modes diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 972e6ce27e..5ee4691288 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -1829,6 +1829,7 @@ fn create_pipelines( CloudMode::Low => "CLOUD_MODE_LOW", CloudMode::Medium => "CLOUD_MODE_MEDIUM", CloudMode::High => "CLOUD_MODE_HIGH", + CloudMode::Ultra => "CLOUD_MODE_ULTRA", }, match mode.lighting { LightingMode::Ashikhmin => "LIGHTING_ALGORITHM_ASHIKHMIN", diff --git a/world/src/layer/scatter.rs b/world/src/layer/scatter.rs index 766a6be63f..577b2f3668 100644 --- a/world/src/layer/scatter.rs +++ b/world/src/layer/scatter.rs @@ -1,6 +1,7 @@ use crate::{column::ColumnSample, sim::SimChunk, util::RandomField, Canvas, CONFIG}; use common::terrain::SpriteKind; use noise::NoiseFn; +use rand::prelude::*; use std::f32; use vek::*; @@ -10,7 +11,7 @@ fn close(x: f32, tgt: f32, falloff: f32) -> f32 { const MUSH_FACT: f32 = 1.0e-4; // To balance everything around the mushroom spawning rate const DEPTH_WATER_NORM: f32 = 15.0; // Water depth at which regular underwater sprites start spawning -pub fn apply_scatter_to(canvas: &mut Canvas) { +pub fn apply_scatter_to(canvas: &mut Canvas, rng: &mut impl Rng) { use SpriteKind::*; #[allow(clippy::type_complexity)] // TODO: Add back all sprites we had before @@ -317,7 +318,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas) { .unwrap_or(true); if density > 0.0 && is_patch - && RandomField::new(i as u32).chance(Vec3::new(wpos2d.x, wpos2d.y, 0), density) + && rng.gen::() < density //RandomField::new(i as u32).chance(Vec3::new(wpos2d.x, wpos2d.y, 0), density) && underwater == *is_underwater { Some(*kind) diff --git a/world/src/lib.rs b/world/src/lib.rs index 631f4afbd3..35a35b5b92 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -241,7 +241,7 @@ impl World { }; layer::apply_trees_to(&mut canvas); - layer::apply_scatter_to(&mut canvas); + layer::apply_scatter_to(&mut canvas, &mut dynamic_rng); layer::apply_caves_to(&mut canvas); layer::apply_paths_to(&mut canvas);