mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
more correct occlusion
This commit is contained in:
parent
83ee54001e
commit
54f958acc7
@ -102,7 +102,7 @@ void main() {
|
||||
#ifdef EXPERIMENTAL_RAIN
|
||||
vec3 old_color = color.rgb;
|
||||
|
||||
// If this value is changed also change it in voxygen/src/scene/mod.rs
|
||||
// If this value is changed also change it in common/src/weather.rs
|
||||
float fall_rate = 70.0;
|
||||
dir.xy += wind_vel * dir.z / fall_rate;
|
||||
dir = normalize(dir);
|
||||
@ -118,7 +118,6 @@ void main() {
|
||||
rain_dist *= 0.3;
|
||||
|
||||
vec2 drop_density = vec2(30, 1);
|
||||
vec2 drop_size = vec2(0.0008, 0.05);
|
||||
|
||||
vec2 rain_pos = (view_pos * rain_dist);
|
||||
rain_pos += vec2(0, tick.x * fall_rate + cam_wpos.z);
|
||||
@ -140,6 +139,7 @@ void main() {
|
||||
break;
|
||||
}
|
||||
float rain_density = rain_density_at(cam_wpos.xy + rpos.xy) * rain_occlusion_at(cam_pos.xyz + rpos.xyz) * 10.0;
|
||||
vec2 drop_size = vec2(0.0008, 0.05);
|
||||
|
||||
if (fract(hash(fract(vec4(cell, rain_dist, 0) * 0.01))) > rain_density) {
|
||||
continue;
|
||||
|
@ -48,7 +48,7 @@ use common::{
|
||||
trade::{PendingTrade, SitePrices, TradeAction, TradeId, TradeResult},
|
||||
uid::{Uid, UidAllocator},
|
||||
vol::RectVolSize,
|
||||
weather::{self, Weather},
|
||||
weather::{self, Weather, WeatherGrid},
|
||||
};
|
||||
#[cfg(feature = "tracy")] use common_base::plot;
|
||||
use common_base::{prof_span, span};
|
||||
@ -153,24 +153,23 @@ pub struct SiteInfoRich {
|
||||
}
|
||||
|
||||
struct WeatherLerp {
|
||||
old: (Grid<Weather>, Instant),
|
||||
new: (Grid<Weather>, Instant),
|
||||
current: Grid<Weather>,
|
||||
old: (WeatherGrid, Instant),
|
||||
new: (WeatherGrid, Instant),
|
||||
}
|
||||
|
||||
impl WeatherLerp {
|
||||
fn weather_update(&mut self, weather: Grid<Weather>) {
|
||||
fn weather_update(&mut self, weather: WeatherGrid) {
|
||||
self.old = mem::replace(&mut self.new, (weather, Instant::now()));
|
||||
}
|
||||
|
||||
fn update(&mut self) {
|
||||
fn update(&mut self, to_update: &mut WeatherGrid) {
|
||||
let old = &self.old.0;
|
||||
let new = &self.new.0;
|
||||
if new.size() == Vec2::zero() {
|
||||
return;
|
||||
}
|
||||
if self.current.size() != new.size() {
|
||||
self.current = new.clone();
|
||||
if to_update.size() != new.size() {
|
||||
*to_update = new.clone();
|
||||
}
|
||||
if old.size() == new.size() {
|
||||
// Assume updates are regular
|
||||
@ -178,9 +177,12 @@ impl WeatherLerp {
|
||||
/ self.new.1.duration_since(self.old.1).as_secs_f32())
|
||||
.clamp(0.0, 1.0);
|
||||
|
||||
old.iter().zip(new.iter()).for_each(|((p, old), (_, new))| {
|
||||
self.current[p] = Weather::lerp(old, new, t);
|
||||
});
|
||||
to_update
|
||||
.iter_mut()
|
||||
.zip(old.iter().zip(new.iter()))
|
||||
.for_each(|((_, current), ((_, old), (_, new)))| {
|
||||
*current = Weather::lerp(old, new, t);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,15 +190,8 @@ impl WeatherLerp {
|
||||
impl Default for WeatherLerp {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
old: (
|
||||
Grid::new(Vec2::new(0, 0), Weather::default()),
|
||||
Instant::now(),
|
||||
),
|
||||
new: (
|
||||
Grid::new(Vec2::new(0, 0), Weather::default()),
|
||||
Instant::now(),
|
||||
),
|
||||
current: Grid::new(Vec2::new(0, 0), Weather::default()),
|
||||
old: (WeatherGrid::new(Vec2::broadcast(0)), Instant::now()),
|
||||
new: (WeatherGrid::new(Vec2::broadcast(0)), Instant::now()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1465,47 +1460,12 @@ impl Client {
|
||||
.map(|v| v.0)
|
||||
}
|
||||
|
||||
pub fn get_weather(&self) -> &Grid<Weather> { &self.weather.current }
|
||||
|
||||
pub fn current_weather(&self) -> Weather {
|
||||
pub fn weather_at_player(&self) -> Weather {
|
||||
self.position()
|
||||
.map(|wpos| self.current_weather_wpos(wpos.xy()))
|
||||
.map(|wpos| self.state.weather_at(wpos.xy()))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn current_weather_wpos(&self, wpos: Vec2<f32>) -> Weather {
|
||||
let cell_pos = wpos / ((TerrainChunkSize::RECT_SIZE * weather::CHUNKS_PER_CELL).as_());
|
||||
let rpos = cell_pos.map(|e| e.fract());
|
||||
let cell_pos = cell_pos.map(|e| e.floor());
|
||||
|
||||
let wpos = cell_pos.as_::<i32>();
|
||||
Weather::lerp(
|
||||
&Weather::lerp(
|
||||
self.weather
|
||||
.current
|
||||
.get(wpos)
|
||||
.unwrap_or(&Weather::default()),
|
||||
self.weather
|
||||
.current
|
||||
.get(wpos + Vec2::unit_x())
|
||||
.unwrap_or(&Weather::default()),
|
||||
rpos.x,
|
||||
),
|
||||
&Weather::lerp(
|
||||
self.weather
|
||||
.current
|
||||
.get(wpos + Vec2::unit_x())
|
||||
.unwrap_or(&Weather::default()),
|
||||
self.weather
|
||||
.current
|
||||
.get(wpos + Vec2::one())
|
||||
.unwrap_or(&Weather::default()),
|
||||
rpos.x,
|
||||
),
|
||||
rpos.y,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn current_chunk(&self) -> Option<Arc<TerrainChunk>> {
|
||||
let chunk_pos = Vec2::from(self.position()?)
|
||||
.map2(TerrainChunkSize::RECT_SIZE, |e: f32, sz| {
|
||||
@ -1724,6 +1684,9 @@ impl Client {
|
||||
self.invite = None;
|
||||
}
|
||||
|
||||
// TODO: put this somewhere else? Otherwise update comments here.
|
||||
self.weather.update(&mut self.state.weather_grid_mut());
|
||||
|
||||
// Lerp towards the target time of day - this ensures a smooth transition for
|
||||
// large jumps in TimeOfDay such as when using /time
|
||||
if let Some(target_tod) = self.target_time_of_day {
|
||||
@ -1751,8 +1714,6 @@ impl Client {
|
||||
|
||||
// 5) Terrain
|
||||
self.tick_terrain()?;
|
||||
// TODO: put this somewhere else?
|
||||
self.weather.update();
|
||||
|
||||
// Send a ping to the server once every second
|
||||
if self.state.get_time() - self.last_server_ping > 1. {
|
||||
|
@ -15,7 +15,7 @@ use common::{
|
||||
trade::{PendingTrade, SitePrices, TradeId, TradeResult},
|
||||
uid::Uid,
|
||||
uuid::Uuid,
|
||||
weather::Weather,
|
||||
weather::{Weather, WeatherGrid},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -198,7 +198,7 @@ pub enum ServerGeneral {
|
||||
/// Economic information about sites
|
||||
SiteEconomy(EconomyInfo),
|
||||
MapMarker(comp::MapMarkerUpdate),
|
||||
WeatherUpdate(common::grid::Grid<Weather>),
|
||||
WeatherUpdate(WeatherGrid),
|
||||
}
|
||||
|
||||
impl ServerGeneral {
|
||||
|
@ -1,10 +1,11 @@
|
||||
use std::fmt;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::{Lerp, Vec2};
|
||||
use vek::{Lerp, Vec2, Vec3};
|
||||
|
||||
pub const CHUNKS_PER_CELL: u32 = 16;
|
||||
// Weather::default is Clear, 0 degrees C and no wind
|
||||
use crate::{grid::Grid, terrain::TerrainChunkSize, vol::RectVolSize};
|
||||
|
||||
/// Weather::default is Clear, 0 degrees C and no wind
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||
pub struct Weather {
|
||||
/// Clouds currently in the area between 0 and 1
|
||||
@ -39,6 +40,13 @@ impl Weather {
|
||||
wind: Vec2::<f32>::lerp(from.wind, to.wind, t),
|
||||
}
|
||||
}
|
||||
|
||||
// Get the rain direction for this weather
|
||||
pub fn rain_dir(&self) -> Vec3<f32> {
|
||||
// If this value is changed also change it in cloud-frag.glsl
|
||||
const FALL_RATE: f32 = 70.0;
|
||||
(-Vec3::unit_z() + self.wind / FALL_RATE).normalized()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
@ -59,3 +67,62 @@ impl fmt::Display for WeatherKind {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const CHUNKS_PER_CELL: u32 = 16;
|
||||
|
||||
pub const CELL_SIZE: u32 = CHUNKS_PER_CELL * TerrainChunkSize::RECT_SIZE.x;
|
||||
|
||||
/// How often the weather is updated, in seconds
|
||||
pub const WEATHER_DT: f32 = 5.0;
|
||||
|
||||
// pub const MAX_WIND_SPEED: f32 = CELL_SIZE as f32 / WEATHER_DT;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WeatherGrid {
|
||||
weather: Grid<Weather>,
|
||||
}
|
||||
|
||||
impl WeatherGrid {
|
||||
pub fn new(size: Vec2<u32>) -> Self {
|
||||
Self {
|
||||
weather: Grid::new(size.as_(), Weather::default()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (Vec2<i32>, &Weather)> { self.weather.iter() }
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (Vec2<i32>, &mut Weather)> {
|
||||
self.weather.iter_mut()
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Vec2<u32> { self.weather.size().as_() }
|
||||
|
||||
/// Get the weather at a given world position by doing bilinear
|
||||
/// interpolation between four cells.
|
||||
pub fn get_interpolated(&self, wpos: Vec2<f32>) -> Weather {
|
||||
let cell_pos = wpos / CELL_SIZE as f32;
|
||||
let rpos = cell_pos.map(|e| e.fract());
|
||||
let cell_pos = cell_pos.map(|e| e.floor());
|
||||
|
||||
let wpos = cell_pos.as_::<i32>();
|
||||
Weather::lerp(
|
||||
&Weather::lerp(
|
||||
self.weather.get(wpos).unwrap_or(&Weather::default()),
|
||||
self.weather
|
||||
.get(wpos + Vec2::unit_x())
|
||||
.unwrap_or(&Weather::default()),
|
||||
rpos.x,
|
||||
),
|
||||
&Weather::lerp(
|
||||
self.weather
|
||||
.get(wpos + Vec2::unit_x())
|
||||
.unwrap_or(&Weather::default()),
|
||||
self.weather
|
||||
.get(wpos + Vec2::one())
|
||||
.unwrap_or(&Weather::default()),
|
||||
rpos.x,
|
||||
),
|
||||
rpos.y,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ use common::{
|
||||
time::DayPeriod,
|
||||
trade::Trades,
|
||||
vol::{ReadVol, WriteVol},
|
||||
weather::{Weather, WeatherGrid},
|
||||
};
|
||||
use common_base::span;
|
||||
use common_ecs::{PhysicsMetrics, SysMetrics};
|
||||
@ -206,6 +207,7 @@ impl State {
|
||||
// Register synced resources used by the ECS.
|
||||
ecs.insert(TimeOfDay(0.0));
|
||||
ecs.insert(Calendar::default());
|
||||
ecs.insert(WeatherGrid::new(Vec2::zero()));
|
||||
|
||||
// Register unsynced resources used by the ECS.
|
||||
ecs.insert(Time(0.0));
|
||||
@ -346,13 +348,23 @@ impl State {
|
||||
/// last game tick.
|
||||
pub fn terrain_changes(&self) -> Fetch<TerrainChanges> { self.ecs.read_resource() }
|
||||
|
||||
/// Get a reference the current in-game weather grid.
|
||||
pub fn weather_grid(&self) -> Fetch<WeatherGrid> { self.ecs.read_resource() }
|
||||
|
||||
/// Get a mutable reference the current in-game weather grid.
|
||||
pub fn weather_grid_mut(&mut self) -> FetchMut<WeatherGrid> { self.ecs.write_resource() }
|
||||
|
||||
/// Get the current weather at a position.
|
||||
pub fn weather_at(&self, pos: Vec2<f32>) -> Weather {
|
||||
self.weather_grid().get_interpolated(pos)
|
||||
}
|
||||
|
||||
/// Get the current in-game time of day.
|
||||
///
|
||||
/// Note that this should not be used for physics, animations or other such
|
||||
/// localised timings.
|
||||
pub fn get_time_of_day(&self) -> f64 { self.ecs.read_resource::<TimeOfDay>().0 }
|
||||
|
||||
/// Get the current in-game day period (period of the day/night cycle)
|
||||
/// Get the current in-game day period (period of the day/night cycle)
|
||||
pub fn get_day_period(&self) -> DayPeriod { self.get_time_of_day().into() }
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use common::weather::CHUNKS_PER_CELL;
|
||||
use common::weather::{WeatherGrid, CHUNKS_PER_CELL, WEATHER_DT};
|
||||
use common_ecs::{dispatch, System};
|
||||
use common_state::State;
|
||||
use specs::DispatcherBuilder;
|
||||
@ -18,17 +18,18 @@ pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
pub fn init(state: &mut State, world: &world::World) {
|
||||
// How many chunks wide a weather cell is.
|
||||
// 16 here means that a weather cell is 16x16 chunks.
|
||||
let sim = sim::WeatherSim::new(world.sim().get_size() / CHUNKS_PER_CELL, world);
|
||||
let weather_size = world.sim().get_size() / CHUNKS_PER_CELL;
|
||||
let sim = sim::WeatherSim::new(weather_size, world);
|
||||
state.ecs_mut().insert(sim);
|
||||
// Tick weather every 2 seconds
|
||||
state
|
||||
.ecs_mut()
|
||||
.insert(SysScheduler::<tick::Sys>::every(Duration::from_secs_f32(
|
||||
sim::DT,
|
||||
WEATHER_DT,
|
||||
)));
|
||||
state
|
||||
.ecs_mut()
|
||||
.insert(SysScheduler::<sync::Sys>::every(Duration::from_secs_f32(
|
||||
sim::DT,
|
||||
WEATHER_DT,
|
||||
)));
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use common::{
|
||||
resources::TimeOfDay,
|
||||
terrain::TerrainChunkSize,
|
||||
vol::RectVolSize,
|
||||
weather::{Weather, CHUNKS_PER_CELL},
|
||||
weather::{Weather, WeatherGrid, CELL_SIZE, CHUNKS_PER_CELL},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use noise::{NoiseFn, SuperSimplex, Turbulence};
|
||||
@ -43,18 +43,9 @@ pub struct WeatherInfo {
|
||||
pub struct WeatherSim {
|
||||
cells: Grid<Cell>, // The variables used for simulation
|
||||
consts: Grid<Constants>, // The constants from the world used for simulation
|
||||
weather: Grid<Weather>, // The current weather.
|
||||
info: Grid<WeatherInfo>,
|
||||
}
|
||||
|
||||
/*
|
||||
const MAX_WIND_SPEED: f32 = 128.0;
|
||||
*/
|
||||
pub(crate) const CELL_SIZE: u32 = CHUNKS_PER_CELL * TerrainChunkSize::RECT_SIZE.x;
|
||||
|
||||
/// How often the weather is updated, in seconds
|
||||
pub(crate) const DT: f32 = 5.0; // CELL_SIZE as f32 / MAX_WIND_SPEED;
|
||||
|
||||
fn sample_plane_normal(points: &[Vec3<f32>]) -> Option<Vec3<f32>> {
|
||||
if points.len() < 3 {
|
||||
return None;
|
||||
@ -140,7 +131,6 @@ impl WeatherSim {
|
||||
})
|
||||
.collect_vec(),
|
||||
),
|
||||
weather: Grid::new(size, Weather::default()),
|
||||
info: Grid::new(size, WeatherInfo::default()),
|
||||
};
|
||||
this.cells.iter_mut().for_each(|(point, cell)| {
|
||||
@ -150,8 +140,6 @@ impl WeatherSim {
|
||||
this
|
||||
}
|
||||
|
||||
pub fn get_weather(&self) -> &Grid<Weather> { &self.weather }
|
||||
|
||||
/*
|
||||
fn get_cell(&self, p: Vec2<i32>, time: f64) -> Cell {
|
||||
*self.cells.get(p).unwrap_or(&sample_cell(p, time))
|
||||
@ -160,7 +148,7 @@ impl WeatherSim {
|
||||
|
||||
// https://minds.wisconsin.edu/bitstream/handle/1793/66950/LitzauSpr2013.pdf
|
||||
// Time step is cell size / maximum wind speed
|
||||
pub fn tick(&mut self, time_of_day: &TimeOfDay) {
|
||||
pub fn tick(&mut self, time_of_day: &TimeOfDay, out: &mut WeatherGrid) {
|
||||
let time = time_of_day.0;
|
||||
|
||||
let base_nz = Turbulence::new(
|
||||
@ -173,7 +161,7 @@ impl WeatherSim {
|
||||
|
||||
let rain_nz = SuperSimplex::new();
|
||||
|
||||
for (point, cell) in self.weather.iter_mut() {
|
||||
for (point, cell) in out.iter_mut() {
|
||||
let wpos = cell_to_wpos(point);
|
||||
|
||||
let pos = wpos.as_::<f64>() + time as f64 * 0.1;
|
||||
@ -391,4 +379,6 @@ impl WeatherSim {
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Vec2<u32> { self.cells.size().as_() }
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use common::weather::WeatherGrid;
|
||||
use common_ecs::{Origin, Phase, System};
|
||||
use common_net::msg::ServerGeneral;
|
||||
use specs::{Join, ReadExpect, ReadStorage, Write};
|
||||
@ -11,7 +12,7 @@ pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
ReadExpect<'a, WeatherSim>,
|
||||
ReadExpect<'a, WeatherGrid>,
|
||||
Write<'a, SysScheduler<Self>>,
|
||||
ReadStorage<'a, Client>,
|
||||
);
|
||||
@ -20,14 +21,16 @@ impl<'a> System<'a> for Sys {
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(_job: &mut common_ecs::Job<Self>, (sim, mut scheduler, clients): Self::SystemData) {
|
||||
fn run(
|
||||
_job: &mut common_ecs::Job<Self>,
|
||||
(weather_grid, mut scheduler, clients): Self::SystemData,
|
||||
) {
|
||||
if scheduler.should_run() {
|
||||
let mut lazy_msg = None;
|
||||
for client in clients.join() {
|
||||
if lazy_msg.is_none() {
|
||||
lazy_msg = Some(
|
||||
client.prepare(ServerGeneral::WeatherUpdate(sim.get_weather().clone())),
|
||||
);
|
||||
lazy_msg =
|
||||
Some(client.prepare(ServerGeneral::WeatherUpdate(weather_grid.clone())));
|
||||
}
|
||||
lazy_msg.as_ref().map(|msg| client.send_prepared(msg));
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use common::resources::TimeOfDay;
|
||||
use common::{resources::TimeOfDay, weather::WeatherGrid};
|
||||
use common_ecs::{Origin, Phase, System};
|
||||
use specs::{Read, Write, WriteExpect};
|
||||
|
||||
@ -13,6 +13,7 @@ impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Read<'a, TimeOfDay>,
|
||||
WriteExpect<'a, WeatherSim>,
|
||||
WriteExpect<'a, WeatherGrid>,
|
||||
Write<'a, SysScheduler<Self>>,
|
||||
);
|
||||
|
||||
@ -22,10 +23,13 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
fn run(
|
||||
_job: &mut common_ecs::Job<Self>,
|
||||
(game_time, mut sim, mut scheduler): Self::SystemData,
|
||||
(game_time, mut sim, mut grid, mut scheduler): Self::SystemData,
|
||||
) {
|
||||
if scheduler.should_run() {
|
||||
sim.tick(&*game_time);
|
||||
if grid.size() != sim.size() {
|
||||
*grid = WeatherGrid::new(sim.size());
|
||||
}
|
||||
sim.tick(&game_time, &mut grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,11 +157,11 @@ impl AmbientMgr {
|
||||
}
|
||||
|
||||
fn check_rain_necessity(&mut self, client: &Client) -> bool {
|
||||
client.current_weather().rain > 0.001
|
||||
client.weather_at_player().rain > 0.001
|
||||
}
|
||||
|
||||
fn check_thunder_necessity(&mut self, client: &Client) -> bool {
|
||||
client.current_weather().rain * 500.0 > 0.7
|
||||
client.weather_at_player().rain * 500.0 > 0.7
|
||||
}
|
||||
|
||||
fn check_leaves_necessity(&mut self, client: &Client, camera: &Camera) -> bool {
|
||||
@ -238,7 +238,7 @@ impl AmbientChannel {
|
||||
let focus_off = camera.get_focus_pos().map(f32::trunc);
|
||||
let cam_pos = camera.dependents().cam_pos + focus_off;
|
||||
// Float from around -30.0 to 30.0
|
||||
let client_wind_speed_sq = client.current_weather().wind.magnitude_squared();
|
||||
let client_wind_speed_sq = client.weather_at_player().wind.magnitude_squared();
|
||||
|
||||
let (terrain_alt, tree_density) = if let Some(chunk) = client.current_chunk() {
|
||||
(chunk.meta().alt(), chunk.meta().tree_density())
|
||||
@ -268,13 +268,13 @@ impl AmbientChannel {
|
||||
// multipler at end will have to change depending on how intense rain normally
|
||||
// is
|
||||
// TODO: make rain diminish with distance above terrain
|
||||
let rain_intensity = client.current_weather().rain * 500.0;
|
||||
let rain_intensity = client.weather_at_player().rain * 500.0;
|
||||
|
||||
return rain_intensity.min(0.9);
|
||||
}
|
||||
|
||||
fn get_thunder_volume(&mut self, client: &Client) -> f32 {
|
||||
let thunder_intensity = client.current_weather().rain * 500.0;
|
||||
let thunder_intensity = client.weather_at_player().rain * 500.0;
|
||||
|
||||
if thunder_intensity < 0.7 {
|
||||
0.0
|
||||
|
@ -332,7 +332,7 @@ impl MusicMgr {
|
||||
|
||||
let is_dark = (state.get_day_period().is_dark()) as bool;
|
||||
let current_period_of_day = Self::get_current_day_period(is_dark);
|
||||
let current_weather = client.current_weather();
|
||||
let current_weather = client.weather_at_player();
|
||||
let current_biome = client.current_biome();
|
||||
let current_site = client.current_site();
|
||||
|
||||
|
@ -2388,7 +2388,7 @@ impl Hud {
|
||||
.font_size(self.fonts.cyri.scale(14))
|
||||
.set(self.ids.time, ui_widgets);
|
||||
|
||||
let weather = client.current_weather();
|
||||
let weather = client.weather_at_player();
|
||||
Text::new(&format!(
|
||||
"Weather({kind:.5}): {{cloud: {cloud:.5}, rain: {rain:.5}, wind: <{wind_x:.5}, \
|
||||
{wind_y:.2}>}}",
|
||||
|
@ -182,7 +182,7 @@ impl Lod {
|
||||
}
|
||||
}
|
||||
// Update weather texture
|
||||
let weather = client.get_weather();
|
||||
let weather = client.state().weather_grid();
|
||||
let size = weather.size().as_::<u32>();
|
||||
renderer.update_texture(
|
||||
&self.data.weather,
|
||||
|
@ -692,7 +692,10 @@ impl Scene {
|
||||
scene_data.ambiance,
|
||||
self.camera.get_mode(),
|
||||
scene_data.sprite_render_distance as f32 - 20.0,
|
||||
client.current_weather_wpos(cam_pos.xy()).wind,
|
||||
client
|
||||
.state()
|
||||
.weather_at(focus_off.xy() + cam_pos.xy())
|
||||
.wind,
|
||||
)]);
|
||||
renderer.update_clouds_locals(CloudsLocals::new(proj_mat_inv, view_mat_inv));
|
||||
renderer.update_postprocess_locals(PostProcessLocals::new(proj_mat_inv, view_mat_inv));
|
||||
@ -704,13 +707,14 @@ impl Scene {
|
||||
self.debug.maintain(renderer);
|
||||
|
||||
// Maintain the terrain.
|
||||
let (_visible_bounds, visible_light_volume, visible_psr_bounds) = self.terrain.maintain(
|
||||
renderer,
|
||||
scene_data,
|
||||
focus_pos,
|
||||
self.loaded_distance,
|
||||
&self.camera,
|
||||
);
|
||||
let (_visible_bounds, visible_light_volume, visible_psr_bounds, visible_occlusion_volume) =
|
||||
self.terrain.maintain(
|
||||
renderer,
|
||||
scene_data,
|
||||
focus_pos,
|
||||
self.loaded_distance,
|
||||
&self.camera,
|
||||
);
|
||||
|
||||
// Maintain the figures.
|
||||
let _figure_bounds = self.figure_mgr.maintain(
|
||||
@ -752,7 +756,8 @@ impl Scene {
|
||||
* Mat4::translation_3d(Vec3::new(1.0, -1.0, 0.0));
|
||||
|
||||
let directed_mats = |d_view_mat: math::Mat4<f32>,
|
||||
d_dir: math::Vec3<f32>|
|
||||
d_dir: math::Vec3<f32>,
|
||||
volume: &Vec<math::Vec3<f32>>|
|
||||
-> (Mat4<f32>, Mat4<f32>) {
|
||||
// NOTE: Light view space, right-handed.
|
||||
let v_p_orig = math::Vec3::from(d_view_mat * math::Vec4::from_direction(new_dir));
|
||||
@ -765,7 +770,7 @@ impl Scene {
|
||||
// (right-handed).
|
||||
let bounds1 = math::fit_psr(
|
||||
view_mat.map_cols(math::Vec4::from),
|
||||
visible_light_volume.iter().copied(),
|
||||
volume.iter().copied(),
|
||||
math::Vec4::homogenized,
|
||||
);
|
||||
let n_e = f64::from(-bounds1.max.z);
|
||||
@ -997,17 +1002,15 @@ impl Scene {
|
||||
)
|
||||
};
|
||||
|
||||
let weather = client.current_weather_wpos(focus_off.xy() + cam_pos.xy());
|
||||
let weather = client.state().weather_at(focus_off.xy() + cam_pos.xy());
|
||||
if true || weather.rain > 0.001
|
||||
// TODO: check if rain map mode is on
|
||||
{
|
||||
// If this value is changed also change it in cloud-frag.glsl
|
||||
const FALL_RATE: f32 = 70.0;
|
||||
let rain_dir =
|
||||
math::Vec3::from(-Vec3::unit_z() + weather.wind / FALL_RATE).normalized();
|
||||
let rain_dir = math::Vec3::from(weather.rain_dir());
|
||||
let rain_view_mat = math::Mat4::look_at_rh(look_at, look_at + rain_dir, up);
|
||||
|
||||
let (shadow_mat, texture_mat) = directed_mats(rain_view_mat, rain_dir);
|
||||
let (shadow_mat, texture_mat) =
|
||||
directed_mats(rain_view_mat, rain_dir, &visible_occlusion_volume);
|
||||
|
||||
let rain_occlusion_locals = RainOcclusionLocals::new(shadow_mat, texture_mat);
|
||||
renderer.update_consts(&mut self.data.rain_occlusion_mats, &[rain_occlusion_locals]);
|
||||
@ -1029,7 +1032,8 @@ impl Scene {
|
||||
let mut directed_shadow_mats = Vec::with_capacity(6);
|
||||
|
||||
let light_view_mat = math::Mat4::look_at_rh(look_at, look_at + directed_light_dir, up);
|
||||
let (shadow_mat, texture_mat) = directed_mats(light_view_mat, directed_light_dir);
|
||||
let (shadow_mat, texture_mat) =
|
||||
directed_mats(light_view_mat, directed_light_dir, &visible_light_volume);
|
||||
|
||||
let shadow_locals = ShadowLocals::new(shadow_mat, texture_mat);
|
||||
|
||||
@ -1166,7 +1170,7 @@ impl Scene {
|
||||
prof_span!("rain occlusion");
|
||||
if let Some(mut occlusion_pass) = drawer.rain_occlusion_pass() {
|
||||
self.terrain
|
||||
.render_shadows(&mut occlusion_pass.draw_terrain_shadows(), focus_pos);
|
||||
.render_occlusion(&mut occlusion_pass.draw_terrain_shadows(), cam_pos);
|
||||
|
||||
self.figure_mgr.render_shadows(
|
||||
&mut occlusion_pass.draw_figure_shadows(),
|
||||
|
@ -812,7 +812,13 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
focus_pos: Vec3<f32>,
|
||||
loaded_distance: f32,
|
||||
camera: &Camera,
|
||||
) -> (Aabb<f32>, Vec<math::Vec3<f32>>, math::Aabr<f32>) {
|
||||
) -> (
|
||||
// TODO: Better return type?
|
||||
Aabb<f32>,
|
||||
Vec<math::Vec3<f32>>,
|
||||
math::Aabr<f32>,
|
||||
Vec<math::Vec3<f32>>,
|
||||
) {
|
||||
let camera::Dependents {
|
||||
view_mat,
|
||||
proj_mat_treeculler,
|
||||
@ -1395,11 +1401,56 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
})
|
||||
};
|
||||
drop(guard);
|
||||
span!(guard, "Rain occlusion magic");
|
||||
let weather = scene_data.state.weather_at(focus_pos.xy());
|
||||
let visible_occlusion_volume = if weather.rain > 0.0 {
|
||||
let occlusion_box = Aabb {
|
||||
min: visible_bounding_box
|
||||
.min
|
||||
.map2(focus_pos - 10.0, |a, b| a.max(b)),
|
||||
max: visible_bounding_box
|
||||
.max
|
||||
.map2(focus_pos + 10.0, |a, b| a.min(b)),
|
||||
};
|
||||
let visible_bounding_box = math::Aabb::<f32> {
|
||||
min: math::Vec3::from(occlusion_box.min - focus_off),
|
||||
max: math::Vec3::from(occlusion_box.max - focus_off),
|
||||
};
|
||||
let visible_bounds_fine = math::Aabb {
|
||||
min: math::Vec3::from(visible_bounding_box.min.as_::<f64>()),
|
||||
max: math::Vec3::from(visible_bounding_box.max.as_::<f64>()),
|
||||
};
|
||||
// TODO: move out shared calculations
|
||||
let inv_proj_view =
|
||||
math::Mat4::from_col_arrays((proj_mat_treeculler * view_mat).into_col_arrays())
|
||||
.as_::<f64>()
|
||||
.inverted();
|
||||
|
||||
let ray_direction = math::Vec3::<f32>::from(weather.rain_dir());
|
||||
|
||||
// NOTE: We use proj_mat_treeculler here because
|
||||
// calc_focused_light_volume_points makes the assumption that the
|
||||
// near plane lies before the far plane.
|
||||
let visible_occlusion_volume = math::calc_focused_light_volume_points(
|
||||
inv_proj_view,
|
||||
ray_direction.as_::<f64>(),
|
||||
visible_bounds_fine,
|
||||
1e-6,
|
||||
)
|
||||
.map(|v| v.as_::<f32>())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
visible_occlusion_volume
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
drop(guard);
|
||||
(
|
||||
visible_bounding_box,
|
||||
visible_light_volume,
|
||||
visible_psr_bounds,
|
||||
visible_occlusion_volume,
|
||||
)
|
||||
}
|
||||
|
||||
@ -1452,6 +1503,38 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
.for_each(|(model, locals)| drawer.draw(model, locals));
|
||||
}
|
||||
|
||||
pub fn render_occlusion<'a>(
|
||||
&'a self,
|
||||
drawer: &mut TerrainShadowDrawer<'_, 'a>,
|
||||
focus_pos: Vec3<f32>,
|
||||
) {
|
||||
span!(_guard, "render_occlusion", "Terrain::render_occlusion");
|
||||
let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| {
|
||||
(e as i32).div_euclid(sz as i32)
|
||||
});
|
||||
// For rain occlusion we only need to render the closest chunks.
|
||||
// TODO: Is this a good value?
|
||||
const RAIN_OCCLUSION_CHUNKS: usize = 16;
|
||||
let chunk_iter = Spiral2d::new()
|
||||
.filter_map(|rpos| {
|
||||
let pos = focus_chunk + rpos;
|
||||
self.chunks.get(&pos)
|
||||
})
|
||||
.take(self.chunks.len().min(RAIN_OCCLUSION_CHUNKS));
|
||||
|
||||
chunk_iter
|
||||
// Find a way to keep this?
|
||||
// .filter(|chunk| chunk.can_shadow_sun())
|
||||
.filter_map(|chunk| {
|
||||
// TODO: Should the fuid model also be considered here?
|
||||
chunk
|
||||
.opaque_model
|
||||
.as_ref()
|
||||
.map(|model| (model, &chunk.locals))
|
||||
})
|
||||
.for_each(|(model, locals)| drawer.draw(model, locals));
|
||||
}
|
||||
|
||||
pub fn chunks_for_point_shadows(
|
||||
&self,
|
||||
focus_pos: Vec3<f32>,
|
||||
|
Loading…
Reference in New Issue
Block a user