Fixed many map problems, re-added surface mist

This commit is contained in:
Joshua Barretto 2020-11-17 16:37:00 +00:00
parent 579bdcf10e
commit aa59d66a76
2 changed files with 95 additions and 67 deletions

View File

@ -9,7 +9,7 @@ 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)
#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);
@ -18,15 +18,19 @@ vec2 get_cloud_heights(vec2 pos) {
float emission_strength = clamp((sin(time_of_day.x / (3600 * 24)) - 0.8) / 0.1, 0, 1);
// Returns vec4(r, g, b, density)
vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
vec4 cloud_at(vec3 pos, float dist, bool close_hack, out vec3 emission) {
// Natural attenuation of air (air naturally attenuates light that passes through it)
// Simulate the atmosphere thinning above 3000 metres down to nothing at 5000 metres
float air = 0.0001 * clamp((10000.0 - pos.z) / 7000, 0, 1);
float air = 0.00015 * clamp((10000.0 - pos.z) / 7000, 0, 1);
// Mist sits close to the ground in valleys (TODO: use base_alt to put it closer to water)
float MIST_MIN = 300;
const float MIST_FADE_HEIGHT = 250;
float mist = 0.0003 * pow(clamp(1.0 - (pos.z - MIST_MIN) / MIST_FADE_HEIGHT, 0.0, 1), 2) / (1.0 + pow(1.0 + dist / 20000.0, 2.0));
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) * 2 + 0.5;
#endif
mist_min_alt *= 250;
const float MIST_FADE_HEIGHT = 500;
float mist = 0.005 * 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);
@ -34,6 +38,13 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
float cloud_tendency = cloud_tendency_at(pos.xy);
float cloud = 0;
// The first first sample is taken very close to the ground and does not match other sample distances.
// This means that clouds get bizarre sampling. Avoiding sampling the clouds in this sample entirely makes for
// better results.
if (close_hack) {
cloud_tendency = 0.0;
}
vec2 cloud_attr = get_cloud_heights(wind_pos.xy);
float cloud_factor = 0.0;
float turb_noise = 0.0;
@ -51,7 +62,7 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
#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);
mist *= 1.0 + turb_noise;
cloud_factor = 0.5 * (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;
@ -60,7 +71,7 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
}
// What proportion of sunlight is *not* being blocked by nearby cloud? (approximation)
float sun_access = clamp((pos.z - cloud_attr.x + turb_noise * 250.0) * 0.002 + 0.35 + mist * 10000, 0.0, 1);
float sun_access = clamp((pos.z - cloud_attr.x + turb_noise * 250.0) * 0.002 + 0.35 + max(mist * 20000, 0), 0, 1);
// 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;
@ -71,16 +82,16 @@ vec4 cloud_at(vec3 pos, float dist, out vec3 emission) {
vec3 cloud_norm = vec3(
(cloud_tendency - cloud_tendency_x) * 6,
(cloud_tendency - cloud_tendency_y) * 6,
(pos.z - cloud_attr.x) / 450 + turb_noise
) * 0.5;
sun_access = mix(max(dot(-sun_dir.xyz, cloud_norm) + 0.5, 0.025), sun_access, 0.25);
moon_access = mix(max(dot(-moon_dir.xyz, cloud_norm) + 0.5, 0.025), moon_access, 0.25);
(pos.z - cloud_attr.x) / 250 + turb_noise + 0.25
);
sun_access = mix(max(dot(-sun_dir.xyz, cloud_norm) + 0.0, 0.025), sun_access, 0.25);
moon_access = mix(max(dot(-moon_dir.xyz, cloud_norm) + 0.35, 0.025), moon_access, 0.25);
#endif
// Prevent mist (i.e: vapour beneath clouds) being accessible to the sun to avoid visual problems
float suppress_mist = clamp((pos.z - cloud_attr.x + cloud_attr.y) / 300, 0, 1);
sun_access *= suppress_mist;
moon_access *= suppress_mist;
//sun_access *= suppress_mist;
//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);
@ -149,11 +160,11 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
vec3 dir_diff = vec3(0);
#if (CLOUD_MODE == CLOUD_MODE_MINIMAL)
/* splay += (texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.5 - time_of_day * 0.000025).x - 0.5) * 0.4 / (1.0 + pow(dir.z, 2) * 10); */
dir_diff = vec3(
(texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10),
(texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10),
(texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10)
) * 1500;
/* dir_diff = vec3( */
/* (texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10), */
/* (texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10), */
/* (texture(t_noise, vec2(atan2(dir.x, dir.y) * 2 / PI, dir.z) * 1.0 - time_of_day * 0.00005).x - 0.5) * 0.2 / (1.0 + pow(dir.z, 2) * 10) */
/* ) * 1500; */
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
@ -164,18 +175,22 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
float net_light = get_sun_brightness() + get_moon_brightness();
float cdist = max_dist;
while (cdist > 1) {
float ndist = step_to_dist(trunc(dist_to_step(cdist - 0.25)));
float ldist = cdist * 1.25;
bool close_hack = true;
//int i = 0;
while (cdist > 4 /*&& i < 1000*/) {
//i += 1;
vec3 emission;
vec4 sample = cloud_at(origin + (dir + dir_diff / ndist) * ndist * splay, ndist, emission);
vec4 sample = cloud_at(origin + (dir + dir_diff / cdist) * ldist * splay, ldist, close_hack, emission);
close_hack = false;
vec2 density_integrals = max(sample.zw, vec2(0)) * (cdist - ndist);
vec2 density_integrals = max(sample.zw, vec2(0)) * (ldist - cdist);
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.5;
const float RAYLEIGH = 0.25;
surf_color =
// Attenuate light passing through the clouds
@ -191,7 +206,9 @@ vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, const float time_of
sky_color * sun_access * scatter_factor * get_sun_brightness() +
sky_color * moon_access * scatter_factor * get_moon_brightness();
cdist = ndist;
ldist = cdist;
cdist = step_to_dist(trunc(dist_to_step(cdist - 0.25)));
}
return surf_color;

View File

@ -39,8 +39,8 @@ widget_ids! {
map_settings_align,
show_towns_img,
show_towns_box,
show_towns_text,
show_castles_img,
show_towns_text,
show_castles_img,
show_castles_box,
show_castles_text,
show_dungeons_img,
@ -65,7 +65,7 @@ pub struct Map<'a> {
localized_strings: &'a Localization,
global_state: &'a GlobalState,
rot_imgs: &'a ImgsRot,
tooltip_manager: &'a mut TooltipManager,
tooltip_manager: &'a mut TooltipManager,
}
impl<'a> Map<'a> {
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
@ -79,7 +79,7 @@ impl<'a> Map<'a> {
pulse: f32,
localized_strings: &'a Localization,
global_state: &'a GlobalState,
tooltip_manager: &'a mut TooltipManager,
tooltip_manager: &'a mut TooltipManager,
) -> Self {
Self {
show: show,
@ -92,7 +92,7 @@ impl<'a> Map<'a> {
_pulse: pulse,
localized_strings,
global_state,
tooltip_manager,
tooltip_manager,
}
}
}
@ -191,7 +191,7 @@ impl<'a> Widget for Map<'a> {
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(21))
.color(TEXT_COLOR)
.set(state.ids.qlog_title, ui);
.set(state.ids.qlog_title, ui);
// Location Name
/*match self.client.current_chunk() {
@ -234,19 +234,19 @@ impl<'a> Widget for Map<'a> {
let w_src = max_zoom / zoom;
let h_src = max_zoom / zoom;
// Handle dragging
let drag = self.global_state.settings.gameplay.map_drag;
// Handle dragging
let drag = self.global_state.settings.gameplay.map_drag;
let dragged: Vec2::<f64> = ui.widget_input(state.ids.grid).drags().left().map(|drag| Vec2::<f64>::from(drag.delta_xy)).sum();
let drag_new = drag + dragged;
events.push(Event::MapDrag(drag_new));
let drag_new = drag + dragged / zoom;
events.push(Event::MapDrag(drag_new));
let rect_src = position::Rect::from_xy_dim(
[
(player_pos.x as f64 / TerrainChunkSize::RECT_SIZE.x as f64) - drag.x,
((worldsize.y - player_pos.y as f64) / TerrainChunkSize::RECT_SIZE.y as f64) + drag.y,
],
[w_src, h_src],
);
);
// X-Button
if Button::image(self.imgs.close_button)
.w_h(24.0, 25.0)
@ -256,8 +256,8 @@ impl<'a> Widget for Map<'a> {
.set(state.ids.close, ui)
.was_clicked()
{
events.push(Event::Close);
events.push(Event::MapDrag(drag_new - drag_new));
events.push(Event::Close);
events.push(Event::MapDrag(drag_new - drag_new));
}
Image::new(world_map.none)
.mid_top_with_margin_on(state.ids.map_align, 10.0)
@ -281,13 +281,13 @@ impl<'a> Widget for Map<'a> {
.set(state.ids.zoom_slider, ui)
{
events.push(Event::MapZoom(new_val as f64));
}
}
// Handle zooming with the mousewheel
let zoom_lvl = self.global_state.settings.gameplay.map_zoom;
let scrolled: f64 = ui.widget_input(state.ids.grid).scrolls().map(|scroll| scroll.y).sum();
let new_zoom_lvl = (zoom_lvl + scrolled * 0.1).clamped(1.0, max_zoom);
events.push(Event::MapZoom(new_zoom_lvl as f64));
let new_zoom_lvl = (zoom_lvl * (1.0 + scrolled * 0.1)).clamped(1.0, 20.0/*max_zoom*/);
events.push(Event::MapZoom(new_zoom_lvl as f64));
// Icon settings
// Alignment
@ -298,7 +298,7 @@ impl<'a> Widget for Map<'a> {
// Show difficulties
Image::new(self.imgs.map_dif_5)
.top_left_with_margins_on(state.ids.map_settings_align, 5.0, 5.0)
.w_h(20.0, 20.0)
.w_h(20.0, 20.0)
.set(state.ids.show_difficulty_img, ui);
if Button::image(if self.show.map_difficulty {
self.imgs.checkbox_checked} else {self.imgs.checkbox})
@ -323,7 +323,7 @@ impl<'a> Widget for Map<'a> {
// Towns
Image::new(self.imgs.mmap_site_town)
.down_from(state.ids.show_difficulty_img, 10.0)
.w_h(20.0, 20.0)
.w_h(20.0, 20.0)
.set(state.ids.show_towns_img, ui);
if Button::image(if self.show.map_towns {
self.imgs.checkbox_checked} else {self.imgs.checkbox})
@ -348,7 +348,7 @@ impl<'a> Widget for Map<'a> {
// Castles
Image::new(self.imgs.mmap_site_castle)
.down_from(state.ids.show_towns_img, 10.0)
.w_h(20.0, 20.0)
.w_h(20.0, 20.0)
.set(state.ids.show_castles_img, ui);
if Button::image(if self.show.map_castles {
self.imgs.checkbox_checked} else {self.imgs.checkbox})
@ -373,7 +373,7 @@ impl<'a> Widget for Map<'a> {
// Dungeons
Image::new(self.imgs.mmap_site_dungeon)
.down_from(state.ids.show_castles_img, 10.0)
.w_h(20.0, 20.0)
.w_h(20.0, 20.0)
.set(state.ids.show_dungeons_img, ui);
if Button::image(if self.show.map_dungeons {
self.imgs.checkbox_checked} else {self.imgs.checkbox})
@ -417,8 +417,9 @@ Text::new("Dungeons")
let rcpos =
rwpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f32) * zoom as f32 * 3.0
/ 4.0;
let rpos =
Vec2::unit_x().rotated_z(0.0) * rcpos.x + Vec2::unit_y().rotated_z(0.0) * rcpos.y;
let rpos = Vec2::unit_x().rotated_z(0.0) * rcpos.x
+ Vec2::unit_y().rotated_z(0.0) * rcpos.y
+ drag.map(|e| (e * zoom_lvl) as f32 / 1.67);
if rpos
.map2(map_size, |e, sz| e.abs() > sz as f32 / 2.0)
@ -433,7 +434,7 @@ Text::new("Dungeons")
SiteKind::Dungeon => "Dungeon",
SiteKind::Castle => "Castle",
};
let desc = format!("Difficulty: {}", dif);
let desc = format!("Difficulty: {}", dif);
Button::image(match &site.kind {
SiteKind::Town => if self.show.map_towns {self.imgs.mmap_site_town } else {self.imgs.nothing},
SiteKind::Dungeon => if self.show.map_dungeons {self.imgs.mmap_site_dungeon} else {self.imgs.nothing},
@ -441,15 +442,15 @@ Text::new("Dungeons")
})
.x_y_position_relative_to(
state.ids.grid,
position::Relative::Scalar(rpos.x as f64 + drag.x * zoom_lvl),
position::Relative::Scalar(rpos.y as f64 + drag.y * zoom_lvl),
position::Relative::Scalar(rpos.x as f64),
position::Relative::Scalar(rpos.y as f64),
)
.w_h(20.0 * 1.2, 20.0 * 1.2)
.hover_image(match &site.kind {
SiteKind::Town => self.imgs.mmap_site_town_hover,
SiteKind::Dungeon => self.imgs.mmap_site_dungeon_hover,
SiteKind::Castle => self.imgs.mmap_site_castle_hover,
})
})
.image_color(UI_HIGHLIGHT_0)
.parent(ui.window)
.with_tooltip(self.tooltip_manager, title, &desc, &site_tooltip, match dif {
@ -464,7 +465,7 @@ Text::new("Dungeons")
.set(state.ids.mmap_site_icons[i], ui);
// Difficulty from 0-6
// 0 = towns and places without a difficulty level
// 0 = towns and places without a difficulty level
if self.show.map_difficulty {
let size = 1.8; // Size factor for difficulty indicators
@ -481,11 +482,11 @@ Text::new("Dungeons")
6 => -12.0 * size,
_ => -4.0 * size,
})
.w(match dif {
.w(match dif {
6 => 12.0 * size,
_ => 4.0 * size * dif as f64,
})
.h(match dif {
.h(match dif {
6 => 12.0 * size,
_ => 4.0 * size,
})
@ -504,7 +505,7 @@ Text::new("Dungeons")
SiteKind::Town => if self.show.map_towns {dif_img.set(state.ids.site_difs[i], ui) },
SiteKind::Dungeon => if self.show.map_dungeons {dif_img.set(state.ids.site_difs[i], ui)},
SiteKind::Castle => if self.show.map_castles {dif_img.set(state.ids.site_difs[i], ui)},
}
}
}
}
@ -517,16 +518,26 @@ Text::new("Dungeons")
(e as f64 / sz).clamped(0.0, 1.0)
});*/
//let xy = rel * 760.0;
let scale = 0.6;
let arrow_sz = Vec2::new(32.0, 37.0) * scale;
Image::new(self.rot_imgs.indicator_mmap_small.target_north)
.top_left_with_margins_on(state.ids.grid, 407.0 + drag.y * zoom_lvl, 417.0 + drag.x * zoom_lvl)
.w_h(arrow_sz.x, arrow_sz.y)
.color(Some(UI_HIGHLIGHT_0))
.floating(true)
.parent(ui.window)
.set(state.ids.indicator, ui);
let rpos = drag.map(|e| (e * zoom_lvl) as f32 / 2.0);
if !rpos
.map2(map_size, |e, sz| e.abs() > sz as f32 / 1.67)
.reduce_or()
{
let scale = 0.6;
let arrow_sz = Vec2::new(32.0, 37.0) * scale;
Image::new(self.rot_imgs.indicator_mmap_small.target_north)
//.top_left_with_margins_on(state.ids.grid, 407.0 - drag.y * zoom_lvl, 417.0 + drag.x * zoom_lvl)
.x_y_position_relative_to(
state.ids.grid,
position::Relative::Scalar(rpos.x as f64),
position::Relative::Scalar(rpos.y as f64),
)
.w_h(arrow_sz.x, arrow_sz.y)
.color(Some(UI_HIGHLIGHT_0))
.floating(true)
.parent(ui.window)
.set(state.ids.indicator, ui);
}
events
}