base occlusion texture size of off voxels

This commit is contained in:
IsseW 2022-04-06 15:40:58 +02:00
parent a6fd5d5c8b
commit 3eabe24f12
19 changed files with 154 additions and 121 deletions

28
Cargo.lock generated
View File

@ -654,16 +654,16 @@ dependencies = [
[[package]]
name = "clap"
version = "3.1.8"
version = "3.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
checksum = "3124f3f75ce09e22d1410043e1e24f2ecc44fad3afe4f08408f1f7663d68da2b"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"clap_lex",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim 0.10.0",
"termcolor",
"textwrap 0.15.0",
@ -682,6 +682,15 @@ dependencies = [
"syn 1.0.90",
]
[[package]]
name = "clap_lex"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "189ddd3b5d32a70b35e7686054371742a937b0d99128e76dde6340210e966669"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "clipboard-win"
version = "3.1.1"
@ -3980,9 +3989,6 @@ name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]]
name = "owned_ttf_parser"
@ -6362,7 +6368,7 @@ dependencies = [
"async-channel",
"authc",
"byteorder",
"clap 3.1.8",
"clap 3.1.10",
"hashbrown 0.11.2",
"image",
"num 0.4.0",
@ -6551,7 +6557,7 @@ dependencies = [
"bincode",
"bitflags",
"bytes",
"clap 3.1.8",
"clap 3.1.10",
"criterion",
"crossbeam-channel",
"futures-core",
@ -6674,7 +6680,7 @@ name = "veloren-server-cli"
version = "0.12.0"
dependencies = [
"ansi-parser",
"clap 3.1.8",
"clap 3.1.10",
"crossterm 0.23.2",
"lazy_static",
"mimalloc",
@ -6825,7 +6831,7 @@ dependencies = [
name = "veloren-voxygen-i18n"
version = "0.10.0"
dependencies = [
"clap 3.1.8",
"clap 3.1.10",
"deunicode",
"git2",
"hashbrown 0.11.2",
@ -6842,7 +6848,7 @@ dependencies = [
"arr_macro",
"bincode",
"bitvec",
"clap 3.1.8",
"clap 3.1.10",
"criterion",
"csv",
"deflate",

View File

@ -139,13 +139,13 @@ 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) {
if (rain_density < 0.001 || fract(hash(fract(vec4(cell, rain_dist, 0) * 0.01))) > rain_density) {
continue;
}
vec2 near_drop = cell + (vec2(0.5) + (vec2(hash(vec4(cell, 0, 0)), 0.5) - 0.5) * vec2(2, 0)) / drop_density;
vec2 drop_size = vec2(0.0008, 0.05);
float avg_alpha = (drop_size.x * drop_size.y) * 10 / 1;
float alpha = sign(max(1 - length((rain_pos - near_drop) / drop_size * 0.1), 0));
float light = sqrt(dot(old_color, vec3(1))) + (get_sun_brightness() + get_moon_brightness()) * 0.01;

View File

@ -121,11 +121,8 @@ float cloud_tendency_at(vec2 pos) {
return sample_weather(pos).r;
}
const float RAIN_CLOUD = 0.05;
float rain_density_at(vec2 pos) {
return sample_weather(pos).g;
//return clamp((cloud_tendency_at(pos) - RAIN_CLOUD) * 10, 0, 1);
}
float cloud_shadow(vec3 pos, vec3 light_dir) {

View File

@ -234,6 +234,7 @@ void main() {
#ifdef EXPERIMENTAL_RAIN
vec3 pos = f_pos + focus_off.xyz;
float rain_density = rain_density_at(pos.xy) * rain_occlusion_at(f_pos.xyz) * 50.0;
// Toggle to see rain_occlusion
// tgt_color = vec4(rain_occlusion_at(f_pos.xyz), 0.0, 0.0, 1.0);
// return;
if (rain_density > 0 && !faces_fluid && f_norm.z > 0.5) {

View File

@ -163,6 +163,7 @@ impl WeatherLerp {
}
fn update(&mut self, to_update: &mut WeatherGrid) {
prof_span!("WeatherLerp::update");
let old = &self.old.0;
let new = &self.new.0;
if new.size() == Vec2::zero() {

View File

@ -82,6 +82,21 @@ pub struct WeatherGrid {
weather: Grid<Weather>,
}
fn to_cell_pos(wpos: Vec2<f32>) -> Vec2<f32> { wpos / CELL_SIZE as f32 - 0.5 }
// TODO: Move consts from world to common to avoid duplication
const LOCALITY: [Vec2<i32>; 9] = [
Vec2::new(0, 0),
Vec2::new(0, 1),
Vec2::new(1, 0),
Vec2::new(0, -1),
Vec2::new(-1, 0),
Vec2::new(1, 1),
Vec2::new(1, -1),
Vec2::new(-1, 1),
Vec2::new(-1, -1),
];
impl WeatherGrid {
pub fn new(size: Vec2<u32>) -> Self {
Self {
@ -100,7 +115,7 @@ impl WeatherGrid {
/// 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 cell_pos = to_cell_pos(wpos);
let rpos = cell_pos.map(|e| e.fract());
let cell_pos = cell_pos.map(|e| e.floor());
@ -125,4 +140,24 @@ impl WeatherGrid {
rpos.y,
)
}
/// Get the max weather near a position
pub fn get_max_near(&self, wpos: Vec2<f32>) -> Weather {
let cell_pos: Vec2<i32> = to_cell_pos(wpos).as_();
LOCALITY
.iter()
.map(|l| {
self.weather
.get(cell_pos + l)
.cloned()
.unwrap_or_default()
})
.reduce(|a, b| Weather {
cloud: a.cloud.max(b.cloud),
rain: a.rain.max(b.rain),
wind: a.wind.map2(b.wind, |a, b| a.max(b)),
})
// There will always be 9 elements in locality
.unwrap()
}
}

View File

@ -359,6 +359,10 @@ impl State {
self.weather_grid().get_interpolated(pos)
}
pub fn max_weather_near(&self, pos: Vec2<f32>) -> Weather {
self.weather_grid().get_max_near(pos)
}
/// Get the current in-game time of day.
///
/// Note that this should not be used for physics, animations or other such

View File

@ -1,4 +1,4 @@
use common::weather::{WeatherGrid, CHUNKS_PER_CELL, WEATHER_DT};
use common::weather::{CHUNKS_PER_CELL, WEATHER_DT};
use common_ecs::{dispatch, System};
use common_state::State;
use specs::DispatcherBuilder;

View File

@ -1,15 +1,21 @@
use common::{
grid::Grid,
resources::TimeOfDay,
terrain::TerrainChunkSize,
vol::RectVolSize,
weather::{Weather, WeatherGrid, CELL_SIZE, CHUNKS_PER_CELL},
weather::{WeatherGrid, CELL_SIZE},
};
use itertools::Itertools;
use noise::{NoiseFn, SuperSimplex, Turbulence};
use vek::*;
use world::World;
/*
#[derive(Clone, Copy, Default)]
struct Cell {
wind: Vec2<f32>,
temperature: f32,
moisture: f32,
cloud: f32,
}
#[derive(Default)]
pub struct Constants {
alt: f32,
@ -18,13 +24,6 @@ pub struct Constants {
temp: f32,
}
#[derive(Clone, Copy, Default)]
struct Cell {
wind: Vec2<f32>,
temperature: f32,
moisture: f32,
cloud: f32,
}
/// Used to sample weather that isn't simulated
fn sample_cell(_p: Vec2<i32>, _time: f64) -> Cell {
Cell {
@ -40,12 +39,6 @@ pub struct WeatherInfo {
pub lightning_chance: f32,
}
pub struct WeatherSim {
cells: Grid<Cell>, // The variables used for simulation
consts: Grid<Constants>, // The constants from the world used for simulation
info: Grid<WeatherInfo>,
}
fn sample_plane_normal(points: &[Vec3<f32>]) -> Option<Vec3<f32>> {
if points.len() < 3 {
return None;
@ -82,13 +75,21 @@ fn sample_plane_normal(points: &[Vec3<f32>]) -> Option<Vec3<f32>> {
Some(Vec3::new(xy * yz - xz * yy, xy * xz - yz * xx, det_z).normalized())
}
}
*/
fn cell_to_wpos(p: Vec2<i32>) -> Vec2<i32> { p * CELL_SIZE as i32 }
pub struct WeatherSim {
// cells: Grid<Cell>, // The variables used for simulation
// consts: Grid<Constants>, // The constants from the world used for simulation
// info: Grid<WeatherInfo>,
size: Vec2<u32>,
}
impl WeatherSim {
pub fn new(size: Vec2<u32>, world: &World) -> Self {
pub fn new(size: Vec2<u32>, _world: &World) -> Self {
/*
let size = size.as_();
let mut this = Self {
let this = Self {
cells: Grid::new(size, Cell::default()),
consts: Grid::from_raw(
size,
@ -138,6 +139,8 @@ impl WeatherSim {
*cell = sample_cell(point, time);
});
this
*/
Self { size }
}
/*
@ -380,5 +383,5 @@ impl WeatherSim {
*/
}
pub fn size(&self) -> Vec2<u32> { self.cells.size().as_() }
pub fn size(&self) -> Vec2<u32> { self.size }
}

View File

@ -5,8 +5,6 @@ use specs::{Join, ReadExpect, ReadStorage, Write};
use crate::{client::Client, sys::SysScheduler};
use super::sim::WeatherSim;
#[derive(Default)]
pub struct Sys;

View File

@ -151,7 +151,7 @@ impl AmbientMgr {
+ ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2))
.min(1.0);
return alt_multiplier * tree_multiplier > 0.0;
alt_multiplier * tree_multiplier > 0.0
},
AmbientChannelTag::Rain => {
let focus_off = camera.get_focus_pos().map(f32::trunc);
@ -165,9 +165,9 @@ impl AmbientMgr {
let camera_multiplier =
1.0 - ((cam_pos.z - terrain_alt).abs() / 75.0).powi(2).min(1.0);
return client.weather_at_player().rain > 0.001 || camera_multiplier > 0.0;
client.weather_at_player().rain > 0.001 || camera_multiplier > 0.0
},
AmbientChannelTag::Thunder => return client.weather_at_player().rain * 500.0 > 0.7,
AmbientChannelTag::Thunder => client.weather_at_player().rain * 500.0 > 0.7,
AmbientChannelTag::Leaves => {
let focus_off = camera.get_focus_pos().map(f32::trunc);
let cam_pos = camera.dependents().cam_pos + focus_off;
@ -182,7 +182,7 @@ impl AmbientMgr {
+ ((cam_pos.z - terrain_alt + 20.0).abs() / 150.0).powi(2))
.min(1.0));
return tree_multiplier > 0.1;
tree_multiplier > 0.1
},
}
}
@ -199,7 +199,7 @@ impl AmbientChannel {
target_volume = self.check_camera(state, client, cam_pos, target_volume);
return target_volume;
target_volume
}
fn check_camera(
@ -268,10 +268,10 @@ impl AmbientChannel {
/ 30.0_f32.powi(2))
.min(1.0);
return alt_multiplier
alt_multiplier
* tree_multiplier
* (wind_speed_multiplier + ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2))
.min(1.0);
.min(1.0)
},
AmbientChannelTag::Rain => {
let focus_off = camera.get_focus_pos().map(f32::trunc);
@ -288,7 +288,7 @@ impl AmbientChannel {
let rain_intensity = (client.weather_at_player().rain * 500.0) * camera_multiplier;
return rain_intensity.min(0.9);
rain_intensity.min(0.9)
},
AmbientChannelTag::Thunder => {
let rain_intensity = client.weather_at_player().rain * 500.0;

View File

@ -371,12 +371,9 @@ impl AudioFrontend {
}
if tag_match {
return found_channel;
} else {
return None;
}
} else {
return None;
}
None
}
// Unused code that may be useful in the future:

View File

@ -367,8 +367,7 @@ impl Default for RenderMode {
fluid: FluidMode::default(),
lighting: LightingMode::default(),
shadow: ShadowMode::default(),
// TODO: should 0.5 be default for rain_occlusion?
rain_occlusion: ShadowMapMode { resolution: 0.5 },
rain_occlusion: ShadowMapMode::default(),
bloom: BloomMode::default(),
point_glow: 0.35,
experimental_shaders: HashSet::default(),

View File

@ -104,7 +104,7 @@ impl RainOcclusionFigurePipeline {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
cull_mode: Some(wgpu::Face::Back),
clamp_depth: true,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,

View File

@ -49,6 +49,10 @@ pub type ColLightInfo = (Vec<[u8; 4]>, Vec2<u16>);
const QUAD_INDEX_BUFFER_U16_START_VERT_LEN: u16 = 3000;
const QUAD_INDEX_BUFFER_U32_START_VERT_LEN: u32 = 3000;
// For rain occlusion we only need to render the closest chunks.
// TODO: Is this a good value?
pub const RAIN_OCCLUSION_CHUNKS: usize = 9;
/// A type that stores all the layouts associated with this renderer that never
/// change when the RenderMode is modified.
struct ImmutableLayouts {
@ -366,15 +370,12 @@ impl Renderer {
})
.ok();
let rain_occlusion_view = RainOcclusionMap::create_view(
&device,
(dims.width, dims.height),
&pipeline_modes.rain_occlusion,
)
.map_err(|err| {
warn!("Could not create rain occlusion map views: {:?}", err);
})
.ok();
let rain_occlusion_view =
RainOcclusionMap::create_view(&device, &pipeline_modes.rain_occlusion)
.map_err(|err| {
warn!("Could not create rain occlusion map views: {:?}", err);
})
.ok();
let shaders = Shaders::load_expect("");
let shaders_watcher = shaders.reload_watcher();
@ -747,7 +748,6 @@ impl Renderer {
if let Some(rain_depth) = rain_views {
match RainOcclusionMap::create_view(
&self.device,
(dims.x, dims.y),
&self.pipeline_modes.rain_occlusion,
) {
Ok(new_rain_depth) => {

View File

@ -1,9 +1,10 @@
use crate::render::pipelines::rain_occlusion;
use crate::render::{pipelines::rain_occlusion, renderer::RAIN_OCCLUSION_CHUNKS};
use super::{
super::{texture::Texture, RenderError, ShadowMapMode},
Renderer,
};
use common::{terrain::TerrainChunkSize, vol::RectVolSize};
use vek::*;
/// A type that holds shadow map data. Since shadow mapping may not be
@ -115,15 +116,17 @@ impl RainOcclusionMap {
/// Returns (point, directed)
pub(super) fn create_view(
device: &wgpu::Device,
size: (u32, u32),
mode: &ShadowMapMode,
) -> Result<Texture, RenderError> {
// (Attempt to) apply resolution factor to rain occlusion map resolution.
let resolution_factor = mode.resolution.clamped(0.25, 4.0);
let max_texture_size = Renderer::max_texture_size_raw(device);
let size =
(RAIN_OCCLUSION_CHUNKS as f32).sqrt().ceil() as u32 * TerrainChunkSize::RECT_SIZE * 2;
// Limit to max texture size, rather than erroring.
let size = Vec2::new(size.0, size.1).map(|e| {
let size = size.map(|e| {
let size = e as f32 * resolution_factor;
// NOTE: We know 0 <= e since we clamped the resolution factor to be between
// 0.25 and 4.0.
@ -221,6 +224,4 @@ impl RainOcclusionMap {
Self::Disabled(dummy) => dummy,
}
}
pub fn is_enabled(&self) -> bool { matches!(self, Self::Enabled(_)) }
}

View File

@ -797,7 +797,7 @@ impl Scene {
// space (left-handed).
let bounds0 = math::fit_psr(
light_all_mat,
visible_light_volume.iter().copied(),
volume.iter().copied(),
math::Vec4::homogenized,
);
// Vague idea: project z_n from the camera view to the light view (where it's
@ -976,7 +976,7 @@ impl Scene {
},
} = math::fit_psr(
shadow_all_mat,
visible_light_volume.iter().copied(),
volume.iter().copied(),
math::Vec4::homogenized,
);
let s_x = 2.0 / (xmax - xmin);
@ -998,10 +998,11 @@ impl Scene {
)
};
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
{
let weather = client
.state()
.max_weather_near(focus_off.xy() + cam_pos.xy());
if weather.rain > 0.0 {
let weather = client.state().weather_at(focus_off.xy() + cam_pos.xy());
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);
@ -1009,6 +1010,7 @@ impl Scene {
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]);
}
@ -1131,6 +1133,7 @@ impl Scene {
let is_daylight = sun_dir.z < 0.0;
let focus_pos = self.camera.get_focus_pos();
let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
let is_rain = state.max_weather_near(cam_pos.xy()).rain > 0.0;
let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
@ -1161,20 +1164,20 @@ impl Scene {
self.terrain.chunks_for_point_shadows(focus_pos),
)
}
// Render rain occlusion texture
{
prof_span!("rain occlusion");
if let Some(mut occlusion_pass) = drawer.rain_occlusion_pass() {
self.terrain
.render_occlusion(&mut occlusion_pass.draw_terrain_shadows(), cam_pos);
}
// Render rain occlusion texture
if is_rain {
prof_span!("rain occlusion");
if let Some(mut occlusion_pass) = drawer.rain_occlusion_pass() {
self.terrain
.render_occlusion(&mut occlusion_pass.draw_terrain_shadows(), cam_pos);
self.figure_mgr.render_shadows(
&mut occlusion_pass.draw_figure_shadows(),
state,
tick,
camera_data,
);
}
self.figure_mgr.render_shadows(
&mut occlusion_pass.draw_figure_shadows(),
state,
tick,
camera_data,
);
}
}

View File

@ -10,6 +10,7 @@ use crate::{
},
render::{
pipelines::{self, ColLights},
renderer::RAIN_OCCLUSION_CHUNKS,
ColLightInfo, FirstPassDrawer, FluidVertex, GlobalModel, Instances, LodData, Mesh, Model,
RenderError, Renderer, SpriteGlobalsBindGroup, SpriteInstance, SpriteVertex, SpriteVerts,
TerrainLocals, TerrainShadowDrawer, TerrainVertex, SPRITE_VERT_PAGE_SIZE,
@ -1295,6 +1296,10 @@ impl<V: RectRasterableVol> Terrain<V> {
min: focus_pos - 2.0,
max: focus_pos + 2.0,
});
let inv_proj_view =
math::Mat4::from_col_arrays((proj_mat_treeculler * view_mat).into_col_arrays())
.as_::<f64>()
.inverted();
// PSCs: Potential shadow casters
let ray_direction = scene_data.get_sun_dir();
@ -1315,10 +1320,6 @@ impl<V: RectRasterableVol> Terrain<V> {
};
let focus_off = math::Vec3::from(focus_off);
let visible_bounds_fine = visible_bounding_box.as_::<f64>();
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(ray_direction);
// NOTE: We use proj_mat_treeculler here because
// calc_focused_light_volume_points makes the assumption that the
@ -1402,45 +1403,35 @@ 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)),
};
// Check if there is rain near the camera
let max_weather = scene_data.state.max_weather_near(focus_pos.xy());
let visible_occlusion_volume = if max_weather.rain > 0.0 {
let occlusion_box = visible_bounding_box/*.intersection(Aabb {
min: focus_pos + camera.dependents().cam_pos - 100.0,
max: focus_pos + camera.dependents().cam_pos + 100.0,
})*/;
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>()),
min: visible_bounding_box.min.as_::<f64>(),
max: 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 weather = scene_data.state.weather_at(focus_pos.xy());
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(
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
.collect::<Vec<_>>()
} else {
Vec::new()
};
@ -1512,9 +1503,6 @@ impl<V: RectRasterableVol> Terrain<V> {
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;

View File

@ -1617,7 +1617,7 @@ impl PlayState for SessionState {
&outcome,
&scene_data,
&mut global_state.audio,
&client.state(),
client.state(),
cam_pos,
);
self.hud