mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Better scattering and scatter (of both varieties)
This commit is contained in:
parent
ee65b4fb17
commit
49df604de0
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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::<f32>() < density //RandomField::new(i as u32).chance(Vec3::new(wpos2d.x, wpos2d.y, 0), density)
|
||||
&& underwater == *is_underwater
|
||||
{
|
||||
Some(*kind)
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user