mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Limit figures drawn for rain occlusion
This commit is contained in:
parent
ac82689f83
commit
a7c724a46d
@ -108,6 +108,11 @@ void main() {
|
||||
vec2 view_pos = vec2(atan2(dir_2d.x, dir_2d.y), z);
|
||||
|
||||
vec3 cam_wpos = cam_pos.xyz + focus_off.xyz;
|
||||
// Rain density is now only based on the cameras current position.
|
||||
// This could be affected by a setting where rain_density_at is instead
|
||||
// called each iteration of the loop. With the current implementation
|
||||
// of rain_dir this has issues with being in a place where it doesn't rain
|
||||
// and seeing rain.
|
||||
float rain = rain_density_at(cam_wpos.xy);
|
||||
if (rain > 0.0) {
|
||||
float rain_dist = 50.0;
|
||||
|
@ -354,11 +354,12 @@ impl State {
|
||||
/// 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.
|
||||
/// Get the current weather at a position in worldspace.
|
||||
pub fn weather_at(&self, pos: Vec2<f32>) -> Weather {
|
||||
self.weather_grid().get_interpolated(pos)
|
||||
}
|
||||
|
||||
/// Get the max weather near a position in worldspace.
|
||||
pub fn max_weather_near(&self, pos: Vec2<f32>) -> Weather {
|
||||
self.weather_grid().get_max_near(pos)
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ impl RainOcclusionFigurePipeline {
|
||||
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Rain occlusion pipeline layout"),
|
||||
label: Some("Rain occlusion figure pipeline layout"),
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&global_layout.globals, &figure_layout.locals],
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ use crate::{
|
||||
camera::{Camera, CameraMode, Dependents},
|
||||
math,
|
||||
terrain::Terrain,
|
||||
SceneData, TrailMgr,
|
||||
SceneData, TrailMgr, RAIN_THRESHOLD,
|
||||
},
|
||||
};
|
||||
use anim::{
|
||||
@ -620,6 +620,7 @@ impl FigureMgr {
|
||||
scene_data: &SceneData,
|
||||
// Visible chunk data.
|
||||
visible_psr_bounds: math::Aabr<f32>,
|
||||
visible_por_bounds: math::Aabr<f32>,
|
||||
camera: &Camera,
|
||||
terrain: Option<&Terrain>,
|
||||
) -> anim::vek::Aabb<f32> {
|
||||
@ -637,25 +638,27 @@ impl FigureMgr {
|
||||
// of the image rendered from the light). If the position projected
|
||||
// with the ray_mat matrix is valid, and shadows are otherwise enabled,
|
||||
// we mark can_shadow.
|
||||
let can_shadow_sun = {
|
||||
let ray_direction = scene_data.get_sun_dir();
|
||||
let is_daylight = ray_direction.z < 0.0/*0.6*/;
|
||||
// Are shadows enabled at all?
|
||||
let can_shadow_sun = renderer.pipeline_modes().shadow.is_map() && is_daylight;
|
||||
// Rain occlusion is very similar to sun shadows, but using a different ray_mat,
|
||||
// and only if it's raining.
|
||||
let (can_shadow_sun, can_occlude_rain) = {
|
||||
let Dependents {
|
||||
proj_mat: _,
|
||||
view_mat: _,
|
||||
cam_pos,
|
||||
..
|
||||
} = camera.dependents();
|
||||
let cam_pos = math::Vec3::from(cam_pos);
|
||||
let ray_direction = math::Vec3::from(ray_direction);
|
||||
|
||||
// Transform (semi) world space to light space.
|
||||
let ray_mat: math::Mat4<f32> =
|
||||
math::Mat4::look_at_rh(cam_pos, cam_pos + ray_direction, math::Vec3::unit_y());
|
||||
let sun_dir = scene_data.get_sun_dir();
|
||||
let is_daylight = sun_dir.z < 0.0/*0.6*/;
|
||||
// Are shadows enabled at all?
|
||||
let can_shadow_sun = renderer.pipeline_modes().shadow.is_map() && is_daylight;
|
||||
|
||||
let weather = scene_data.state.weather_at(cam_pos.xy());
|
||||
|
||||
let cam_pos = math::Vec3::from(cam_pos);
|
||||
|
||||
let focus_off = math::Vec3::from(camera.get_focus_pos().map(f32::trunc));
|
||||
let ray_mat = ray_mat * math::Mat4::translation_3d(-focus_off);
|
||||
let focus_off_mat = math::Mat4::translation_3d(-focus_off);
|
||||
|
||||
let collides_with_aabr = |a: math::Aabr<f32>, b: math::Aabr<f32>| {
|
||||
let min = math::Vec4::new(a.min.x, a.min.y, b.min.x, b.min.y);
|
||||
@ -665,22 +668,40 @@ impl FigureMgr {
|
||||
#[cfg(not(feature = "simd"))]
|
||||
return min.partial_cmple(&max).reduce_and();
|
||||
};
|
||||
move |pos: (anim::vek::Vec3<f32>,), radius: f32| {
|
||||
// Short circuit when there are no shadows to cast.
|
||||
if !can_shadow_sun {
|
||||
return false;
|
||||
|
||||
let can_shadow = |ray_direction: Vec3<f32>,
|
||||
enabled: bool,
|
||||
visible_bounds: math::Aabr<f32>| {
|
||||
let ray_direction = math::Vec3::from(ray_direction);
|
||||
// Transform (semi) world space to light space.
|
||||
let ray_mat: math::Mat4<f32> =
|
||||
math::Mat4::look_at_rh(cam_pos, cam_pos + ray_direction, math::Vec3::unit_y());
|
||||
let ray_mat = ray_mat * focus_off_mat;
|
||||
move |pos: (anim::vek::Vec3<f32>,), radius: f32| {
|
||||
// Short circuit when there are no shadows to cast.
|
||||
if !enabled {
|
||||
return false;
|
||||
}
|
||||
// First project center onto shadow map.
|
||||
let center = (ray_mat * math::Vec4::new(pos.0.x, pos.0.y, pos.0.z, 1.0)).xy();
|
||||
// Then, create an approximate bounding box (± radius).
|
||||
let figure_box = math::Aabr {
|
||||
min: center - radius,
|
||||
max: center + radius,
|
||||
};
|
||||
// Quick intersection test for membership in the PSC (potential shader caster)
|
||||
// list.
|
||||
collides_with_aabr(figure_box, visible_bounds)
|
||||
}
|
||||
// First project center onto shadow map.
|
||||
let center = (ray_mat * math::Vec4::new(pos.0.x, pos.0.y, pos.0.z, 1.0)).xy();
|
||||
// Then, create an approximate bounding box (± radius).
|
||||
let figure_box = math::Aabr {
|
||||
min: center - radius,
|
||||
max: center + radius,
|
||||
};
|
||||
// Quick intersection test for membership in the PSC (potential shader caster)
|
||||
// list.
|
||||
collides_with_aabr(figure_box, visible_psr_bounds)
|
||||
}
|
||||
};
|
||||
(
|
||||
can_shadow(sun_dir, can_shadow_sun, visible_psr_bounds),
|
||||
can_shadow(
|
||||
weather.rain_vel(),
|
||||
weather.rain > RAIN_THRESHOLD,
|
||||
visible_por_bounds,
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
// Get player position.
|
||||
@ -812,6 +833,8 @@ impl FigureMgr {
|
||||
} else if vd_frac > 1.0 {
|
||||
state.as_mut().map(|state| state.visible = false);
|
||||
// Keep processing if this might be a shadow caster.
|
||||
// NOTE: Not worth to do for rain_occlusion, since that only happens in closeby
|
||||
// chunks.
|
||||
if !can_shadow_prev {
|
||||
continue;
|
||||
}
|
||||
@ -841,6 +864,7 @@ impl FigureMgr {
|
||||
} else {
|
||||
// Check whether we can shadow.
|
||||
meta.can_shadow_sun = can_shadow_sun(pos, radius);
|
||||
meta.can_occlude_rain = can_occlude_rain(pos, radius);
|
||||
}
|
||||
(in_frustum, lpindex)
|
||||
} else {
|
||||
@ -5551,17 +5575,16 @@ impl FigureMgr {
|
||||
visible_aabb
|
||||
}
|
||||
|
||||
pub fn render_shadows<'a>(
|
||||
fn render_shadow_mapping<'a>(
|
||||
&'a self,
|
||||
drawer: &mut FigureShadowDrawer<'_, 'a>,
|
||||
state: &State,
|
||||
tick: u64,
|
||||
(camera, figure_lod_render_distance): CameraData,
|
||||
filter_state: impl Fn(&FigureStateMeta) -> bool,
|
||||
) {
|
||||
span!(_guard, "render_shadows", "FigureManager::render_shadows");
|
||||
let ecs = state.ecs();
|
||||
let items = ecs.read_storage::<Item>();
|
||||
|
||||
(
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<Pos>(),
|
||||
@ -5590,7 +5613,7 @@ impl FigureMgr {
|
||||
Some(Collider::Volume(vol)) => vol.mut_count,
|
||||
_ => 0,
|
||||
},
|
||||
|state| state.can_shadow_sun(),
|
||||
&filter_state,
|
||||
if matches!(body, Body::ItemDrop(_)) { items.get(entity).map(ItemKey::from) } else { None },
|
||||
) {
|
||||
drawer.draw(model, bound);
|
||||
@ -5598,6 +5621,32 @@ impl FigureMgr {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn render_shadows<'a>(
|
||||
&'a self,
|
||||
drawer: &mut FigureShadowDrawer<'_, 'a>,
|
||||
state: &State,
|
||||
tick: u64,
|
||||
camera_data: CameraData,
|
||||
) {
|
||||
span!(_guard, "render_shadows", "FigureManager::render_shadows");
|
||||
self.render_shadow_mapping(drawer, state, tick, camera_data, |state| {
|
||||
state.can_shadow_sun()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render_rain_occlusion<'a>(
|
||||
&'a self,
|
||||
drawer: &mut FigureShadowDrawer<'_, 'a>,
|
||||
state: &State,
|
||||
tick: u64,
|
||||
camera_data: CameraData,
|
||||
) {
|
||||
span!(_guard, "render_rain_occlusion", "FigureManager::render_rain_occlusion");
|
||||
self.render_shadow_mapping(drawer, state, tick, camera_data, |state| {
|
||||
state.can_occlude_rain()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render<'a>(
|
||||
&'a self,
|
||||
drawer: &mut FigureDrawer<'_, 'a>,
|
||||
@ -6237,6 +6286,7 @@ pub struct FigureStateMeta {
|
||||
last_ori: anim::vek::Quaternion<f32>,
|
||||
lpindex: u8,
|
||||
can_shadow_sun: bool,
|
||||
can_occlude_rain: bool,
|
||||
visible: bool,
|
||||
last_pos: Option<anim::vek::Vec3<f32>>,
|
||||
avg_vel: anim::vek::Vec3<f32>,
|
||||
@ -6253,6 +6303,11 @@ impl FigureStateMeta {
|
||||
// Either visible, or explicitly a shadow caster.
|
||||
self.visible || self.can_shadow_sun
|
||||
}
|
||||
|
||||
pub fn can_occlude_rain(&self) -> bool {
|
||||
// Either visible, or explicitly a rain occluder.
|
||||
self.visible || self.can_occlude_rain
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FigureState<S> {
|
||||
@ -6311,6 +6366,7 @@ impl<S: Skeleton> FigureState<S> {
|
||||
lpindex: 0,
|
||||
visible: false,
|
||||
can_shadow_sun: false,
|
||||
can_occlude_rain: false,
|
||||
last_pos: None,
|
||||
avg_vel: anim::vek::Vec3::zero(),
|
||||
last_light: 1.0,
|
||||
|
@ -183,6 +183,8 @@ impl Lod {
|
||||
}
|
||||
}
|
||||
// Update weather texture
|
||||
// NOTE: consider moving the lerping to a shader if the overhead of uploading to
|
||||
// the gpu each frame becomes an issue.
|
||||
let weather = client.state().weather_grid();
|
||||
let size = weather.size().as_::<u32>();
|
||||
renderer.update_texture(
|
||||
|
@ -65,6 +65,9 @@ const SHADOW_FAR: f32 = 128.0; // Far plane for shadow map point light rendering
|
||||
/// Used for first person camera effects
|
||||
const RUNNING_THRESHOLD: f32 = 0.7;
|
||||
|
||||
/// The threashold for starting calculations with rain.
|
||||
const RAIN_THRESHOLD: f32 = 0.0;
|
||||
|
||||
/// is_daylight, array of active lights.
|
||||
pub type LightData<'a> = (bool, &'a [Light]);
|
||||
|
||||
@ -705,14 +708,19 @@ impl Scene {
|
||||
self.debug.maintain(renderer);
|
||||
|
||||
// Maintain the terrain.
|
||||
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,
|
||||
);
|
||||
let (
|
||||
_visible_bounds,
|
||||
visible_light_volume,
|
||||
visible_psr_bounds,
|
||||
visible_occlusion_volume,
|
||||
visible_por_bounds,
|
||||
) = self.terrain.maintain(
|
||||
renderer,
|
||||
scene_data,
|
||||
focus_pos,
|
||||
self.loaded_distance,
|
||||
&self.camera,
|
||||
);
|
||||
|
||||
// Maintain the figures.
|
||||
let _figure_bounds = self.figure_mgr.maintain(
|
||||
@ -720,6 +728,7 @@ impl Scene {
|
||||
&mut self.trail_mgr,
|
||||
scene_data,
|
||||
visible_psr_bounds,
|
||||
visible_por_bounds,
|
||||
&self.camera,
|
||||
Some(&self.terrain),
|
||||
);
|
||||
@ -1003,7 +1012,7 @@ impl Scene {
|
||||
let weather = client
|
||||
.state()
|
||||
.max_weather_near(focus_off.xy() + cam_pos.xy());
|
||||
if weather.rain > 0.0 {
|
||||
if weather.rain > RAIN_THRESHOLD {
|
||||
let weather = client.state().weather_at(focus_off.xy() + cam_pos.xy());
|
||||
let rain_vel = weather.rain_vel();
|
||||
let rain_view_mat = math::Mat4::look_at_rh(look_at, look_at + rain_vel, up);
|
||||
@ -1139,7 +1148,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 is_rain = state.max_weather_near(cam_pos.xy()).rain > RAIN_THRESHOLD;
|
||||
|
||||
let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
|
||||
|
||||
@ -1178,7 +1187,7 @@ impl Scene {
|
||||
self.terrain
|
||||
.render_rain_occlusion(&mut occlusion_pass.draw_terrain_shadows(), cam_pos);
|
||||
|
||||
self.figure_mgr.render_shadows(
|
||||
self.figure_mgr.render_rain_occlusion(
|
||||
&mut occlusion_pass.draw_figure_shadows(),
|
||||
state,
|
||||
tick,
|
||||
|
@ -18,7 +18,7 @@ use crate::{
|
||||
|
||||
use super::{
|
||||
camera::{self, Camera},
|
||||
math, SceneData,
|
||||
math, SceneData, RAIN_THRESHOLD,
|
||||
};
|
||||
use common::{
|
||||
assets::{self, AssetExt, DotVoxAsset},
|
||||
@ -821,6 +821,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
Vec<math::Vec3<f32>>,
|
||||
math::Aabr<f32>,
|
||||
Vec<math::Vec3<f32>>,
|
||||
math::Aabr<f32>,
|
||||
) {
|
||||
let camera::Dependents {
|
||||
view_mat,
|
||||
@ -1313,6 +1314,9 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
#[cfg(not(feature = "simd"))]
|
||||
return min.partial_cmple(&max).reduce_and();
|
||||
};
|
||||
|
||||
let cam_pos = math::Vec4::from(view_mat.inverted() * Vec4::unit_w()).xyz();
|
||||
|
||||
let (visible_light_volume, visible_psr_bounds) = if ray_direction.z < 0.0
|
||||
&& renderer.pipeline_modes().shadow.is_map()
|
||||
{
|
||||
@ -1335,9 +1339,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
.map(|v| v.as_::<f32>())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let cam_pos = math::Vec4::from(view_mat.inverted() * Vec4::unit_w()).xyz();
|
||||
let up: math::Vec3<f32> = { math::Vec3::unit_y() };
|
||||
|
||||
let ray_mat = math::Mat4::look_at_rh(cam_pos, cam_pos + ray_direction, up);
|
||||
let visible_bounds = math::Aabr::from(math::fit_psr(
|
||||
ray_mat,
|
||||
@ -1407,7 +1409,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
span!(guard, "Rain occlusion magic");
|
||||
// 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 (visible_occlusion_volume, visible_por_bounds) = if max_weather.rain > RAIN_THRESHOLD {
|
||||
let visible_bounding_box = math::Aabb::<f32> {
|
||||
min: math::Vec3::from(visible_bounding_box.min - focus_off),
|
||||
max: math::Vec3::from(visible_bounding_box.max - focus_off),
|
||||
@ -1422,16 +1424,25 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
// 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.
|
||||
math::calc_focused_light_volume_points(
|
||||
let visible_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<_>>()
|
||||
.collect::<Vec<_>>();
|
||||
let ray_mat =
|
||||
math::Mat4::look_at_rh(cam_pos, cam_pos + ray_direction, math::Vec3::unit_y());
|
||||
let visible_bounds = math::Aabr::from(math::fit_psr(
|
||||
ray_mat,
|
||||
visible_volume.iter().copied(),
|
||||
|p| p,
|
||||
));
|
||||
|
||||
(visible_volume, visible_bounds)
|
||||
} else {
|
||||
Vec::new()
|
||||
(Vec::new(), math::Aabr::default())
|
||||
};
|
||||
|
||||
drop(guard);
|
||||
@ -1440,6 +1451,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
visible_light_volume,
|
||||
visible_psr_bounds,
|
||||
visible_occlusion_volume,
|
||||
visible_por_bounds,
|
||||
)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user