mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Use temporal coherence for figure frustum culling, don't process figures if they are not in view frustum
This commit is contained in:
parent
c19c222a90
commit
31d18b3381
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1064,7 +1064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
[[package]]
|
||||
name = "frustum_culling"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.com/yusdacra/frustum_culling#735aef658c7e5eb0c4d543cacbea2f3e06216438"
|
||||
source = "git+https://gitlab.com/yusdacra/frustum_culling#7145dbee5eadf4df0cbe5aeda856a0967f47ace4"
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
|
@ -169,6 +169,8 @@ impl Scene {
|
||||
1.0 / 60.0, // TODO: Use actual deltatime here?
|
||||
1.0,
|
||||
1.0,
|
||||
0,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,6 @@ pub struct FigureMgr {
|
||||
fish_small_states: HashMap<EcsEntity, FigureState<FishSmallSkeleton>>,
|
||||
biped_large_states: HashMap<EcsEntity, FigureState<BipedLargeSkeleton>>,
|
||||
object_states: HashMap<EcsEntity, FigureState<ObjectSkeleton>>,
|
||||
figure_count: usize,
|
||||
visible_figure_count: usize,
|
||||
}
|
||||
|
||||
impl FigureMgr {
|
||||
@ -61,8 +59,6 @@ impl FigureMgr {
|
||||
fish_small_states: HashMap::new(),
|
||||
biped_large_states: HashMap::new(),
|
||||
object_states: HashMap::new(),
|
||||
figure_count: 0,
|
||||
visible_figure_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +66,7 @@ impl FigureMgr {
|
||||
self.model_cache.clean(tick);
|
||||
}
|
||||
|
||||
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
|
||||
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client, camera: &Camera) {
|
||||
let time = client.state().get_time();
|
||||
let tick = client.get_tick();
|
||||
let ecs = client.state().ecs();
|
||||
@ -82,8 +78,6 @@ impl FigureMgr {
|
||||
.get(client.entity())
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
|
||||
self.figure_count = 0;
|
||||
|
||||
for (entity, pos, ori, scale, body, character, last_character, stats) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<Pos>(),
|
||||
@ -96,7 +90,79 @@ impl FigureMgr {
|
||||
)
|
||||
.join()
|
||||
{
|
||||
self.figure_count += 1;
|
||||
// Don't process figures outside the frustum spectrum
|
||||
let frustum = camera.frustum(client);
|
||||
|
||||
let (in_frustum, lpindex) = frustum.test_sphere_coherence(
|
||||
pos.0.into_array(),
|
||||
scale.unwrap_or(&Scale(1.0)).0 * 2.0,
|
||||
match body {
|
||||
Body::Humanoid(_) => {
|
||||
self.character_states.get(&entity).map(|state| state.lpindex)
|
||||
}
|
||||
Body::QuadrupedSmall(_) => {
|
||||
self.quadruped_small_states.get(&entity).map(|state| state.lpindex)
|
||||
}
|
||||
Body::QuadrupedMedium(_) => {
|
||||
self.quadruped_medium_states.get(&entity).map(|state| state.lpindex)
|
||||
}
|
||||
Body::BirdMedium(_) => {
|
||||
self.bird_medium_states.get(&entity).map(|state| state.lpindex)
|
||||
}
|
||||
Body::FishMedium(_) => {
|
||||
self.fish_medium_states.get(&entity).map(|state| state.lpindex)
|
||||
}
|
||||
Body::Dragon(_) => {
|
||||
self.dragon_states.get(&entity).map(|state| state.lpindex)
|
||||
}
|
||||
Body::BirdSmall(_) => {
|
||||
self.bird_small_states.get(&entity).map(|state| state.lpindex)
|
||||
}
|
||||
Body::FishSmall(_) => {
|
||||
self.fish_small_states.get(&entity).map(|state| state.lpindex)
|
||||
}
|
||||
Body::BipedLarge(_) => {
|
||||
self.biped_large_states.get(&entity).map(|state| state.lpindex)
|
||||
}
|
||||
Body::Object(_) => {
|
||||
self.object_states.get(&entity).map(|state| state.lpindex)
|
||||
}
|
||||
}.unwrap_or(0),
|
||||
);
|
||||
|
||||
match body {
|
||||
Body::Humanoid(_) => {
|
||||
self.character_states.get_mut(&entity).map(|state| state.visible = in_frustum);
|
||||
}
|
||||
Body::QuadrupedSmall(_) => {
|
||||
self.quadruped_small_states.get_mut(&entity).map(|state| state.visible = in_frustum);
|
||||
}
|
||||
Body::QuadrupedMedium(_) => {
|
||||
self.quadruped_medium_states.get_mut(&entity).map(|state| state.visible = in_frustum);
|
||||
}
|
||||
Body::BirdMedium(_) => {
|
||||
self.bird_medium_states.get_mut(&entity).map(|state| state.visible = in_frustum);
|
||||
}
|
||||
Body::FishMedium(_) => {
|
||||
self.fish_medium_states.get_mut(&entity).map(|state| state.visible = in_frustum);
|
||||
}
|
||||
Body::Dragon(_) => {
|
||||
self.dragon_states.get_mut(&entity).map(|state| state.visible = in_frustum);
|
||||
}
|
||||
Body::BirdSmall(_) => {
|
||||
self.bird_small_states.get_mut(&entity).map(|state| state.visible = in_frustum);
|
||||
}
|
||||
Body::FishSmall(_) => {
|
||||
self.fish_small_states.get_mut(&entity).map(|state| state.visible = in_frustum);
|
||||
}
|
||||
Body::BipedLarge(_) => {
|
||||
self.biped_large_states.get_mut(&entity).map(|state| state.visible = in_frustum);
|
||||
}
|
||||
Body::Object(_) => {
|
||||
self.object_states.get_mut(&entity).map(|state| state.visible = in_frustum);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't process figures outside the vd
|
||||
let vd_frac = Vec2::from(pos.0 - player_pos)
|
||||
.map2(TerrainChunk::RECT_SIZE, |d: f32, sz| {
|
||||
@ -139,7 +205,7 @@ impl FigureMgr {
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else if vd_frac > 1.0 {
|
||||
} else if vd_frac > 1.0 || !in_frustum {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -320,6 +386,8 @@ impl FigureMgr {
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
lpindex,
|
||||
true,
|
||||
);
|
||||
}
|
||||
Body::QuadrupedSmall(_) => {
|
||||
@ -377,6 +445,8 @@ impl FigureMgr {
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
lpindex,
|
||||
true,
|
||||
);
|
||||
}
|
||||
Body::QuadrupedMedium(_) => {
|
||||
@ -434,6 +504,8 @@ impl FigureMgr {
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
lpindex,
|
||||
true,
|
||||
);
|
||||
}
|
||||
Body::BirdMedium(_) => {
|
||||
@ -489,6 +561,8 @@ impl FigureMgr {
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
lpindex,
|
||||
true,
|
||||
);
|
||||
}
|
||||
Body::FishMedium(_) => {
|
||||
@ -544,6 +618,8 @@ impl FigureMgr {
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
lpindex,
|
||||
true,
|
||||
);
|
||||
}
|
||||
Body::Dragon(_) => {
|
||||
@ -599,6 +675,8 @@ impl FigureMgr {
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
lpindex,
|
||||
true,
|
||||
);
|
||||
}
|
||||
Body::BirdSmall(_) => {
|
||||
@ -654,6 +732,8 @@ impl FigureMgr {
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
lpindex,
|
||||
true,
|
||||
);
|
||||
}
|
||||
Body::FishSmall(_) => {
|
||||
@ -709,6 +789,8 @@ impl FigureMgr {
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
lpindex,
|
||||
true,
|
||||
);
|
||||
}
|
||||
Body::BipedLarge(_) => {
|
||||
@ -764,6 +846,8 @@ impl FigureMgr {
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
lpindex,
|
||||
true,
|
||||
);
|
||||
}
|
||||
Body::Object(_) => {
|
||||
@ -783,6 +867,8 @@ impl FigureMgr {
|
||||
dt,
|
||||
movement_animation_rate,
|
||||
action_animation_rate,
|
||||
lpindex,
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -823,15 +909,11 @@ impl FigureMgr {
|
||||
let tick = client.get_tick();
|
||||
let ecs = client.state().ecs();
|
||||
|
||||
let frustum = camera.frustum(client);
|
||||
|
||||
let character_state_storage = client
|
||||
.state()
|
||||
.read_storage::<common::comp::CharacterState>();
|
||||
let character_state = character_state_storage.get(client.entity());
|
||||
|
||||
self.visible_figure_count = 0;
|
||||
|
||||
for (entity, _, _, body, stats, _) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<Pos>(),
|
||||
@ -841,59 +923,55 @@ impl FigureMgr {
|
||||
ecs.read_storage::<Scale>().maybe(),
|
||||
)
|
||||
.join()
|
||||
// Don't render figures outside of frustum (camera viewport, max draw distance is farplane)
|
||||
.filter(|(_, pos, _, _, _, scale)| {
|
||||
frustum.test_sphere(
|
||||
pos.0.into_array(),
|
||||
scale.unwrap_or(&Scale(1.0)).0 * 2.0,
|
||||
)
|
||||
})
|
||||
// Don't render dead entities
|
||||
.filter(|(_, _, _, _, stats, _)| stats.map_or(true, |s| !s.is_dead))
|
||||
{
|
||||
self.visible_figure_count += 1;
|
||||
if let Some((locals, bone_consts)) = match body {
|
||||
if let Some((locals, bone_consts, visible)) = match body {
|
||||
Body::Humanoid(_) => self
|
||||
.character_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
.map(|state| (state.locals(), state.bone_consts(), state.visible)),
|
||||
Body::QuadrupedSmall(_) => self
|
||||
.quadruped_small_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
.map(|state| (state.locals(), state.bone_consts(), state.visible)),
|
||||
Body::QuadrupedMedium(_) => self
|
||||
.quadruped_medium_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
.map(|state| (state.locals(), state.bone_consts(), state.visible)),
|
||||
Body::BirdMedium(_) => self
|
||||
.bird_medium_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
.map(|state| (state.locals(), state.bone_consts(), state.visible)),
|
||||
Body::FishMedium(_) => self
|
||||
.fish_medium_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
.map(|state| (state.locals(), state.bone_consts(), state.visible)),
|
||||
Body::Dragon(_) => self
|
||||
.dragon_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
.map(|state| (state.locals(), state.bone_consts(), state.visible)),
|
||||
Body::BirdSmall(_) => self
|
||||
.bird_small_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
.map(|state| (state.locals(), state.bone_consts(), state.visible)),
|
||||
Body::FishSmall(_) => self
|
||||
.fish_small_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
.map(|state| (state.locals(), state.bone_consts(), state.visible)),
|
||||
Body::BipedLarge(_) => self
|
||||
.biped_large_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
.map(|state| (state.locals(), state.bone_consts(), state.visible)),
|
||||
Body::Object(_) => self
|
||||
.object_states
|
||||
.get(&entity)
|
||||
.map(|state| (state.locals(), state.bone_consts())),
|
||||
.map(|state| (state.locals(), state.bone_consts(), state.visible)),
|
||||
} {
|
||||
if !visible {
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_player = entity == client.entity();
|
||||
|
||||
let player_camera_mode = if is_player {
|
||||
@ -922,11 +1000,30 @@ impl FigureMgr {
|
||||
}
|
||||
|
||||
pub fn figure_count(&self) -> usize {
|
||||
self.figure_count
|
||||
self.character_states.len()
|
||||
+ self.quadruped_small_states.len()
|
||||
+ self.character_states.len()
|
||||
+ self.quadruped_medium_states.len()
|
||||
+ self.bird_medium_states.len()
|
||||
+ self.fish_medium_states.len()
|
||||
+ self.dragon_states.len()
|
||||
+ self.bird_small_states.len()
|
||||
+ self.fish_small_states.len()
|
||||
+ self.biped_large_states.len()
|
||||
+ self.object_states.len()
|
||||
}
|
||||
|
||||
pub fn figure_count_visible(&self) -> usize {
|
||||
self.visible_figure_count
|
||||
self.character_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self.quadruped_small_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self.quadruped_medium_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self.bird_medium_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self.fish_medium_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self.dragon_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self.bird_small_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self.fish_small_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self.biped_large_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self.object_states.iter().filter(|(_, c)| c.visible).count()
|
||||
}
|
||||
}
|
||||
|
||||
@ -939,6 +1036,8 @@ pub struct FigureState<S: Skeleton> {
|
||||
pos: Vec3<f32>,
|
||||
ori: Vec3<f32>,
|
||||
last_ori: Vec3<f32>,
|
||||
lpindex: u8,
|
||||
visible: bool,
|
||||
}
|
||||
|
||||
impl<S: Skeleton> FigureState<S> {
|
||||
@ -954,6 +1053,8 @@ impl<S: Skeleton> FigureState<S> {
|
||||
pos: Vec3::zero(),
|
||||
ori: Vec3::zero(),
|
||||
last_ori: Vec3::zero(),
|
||||
lpindex: 0,
|
||||
visible: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -968,7 +1069,11 @@ impl<S: Skeleton> FigureState<S> {
|
||||
dt: f32,
|
||||
movement_rate: f32,
|
||||
action_rate: f32,
|
||||
lpindex: u8,
|
||||
visible: bool,
|
||||
) {
|
||||
self.visible = visible;
|
||||
self.lpindex = lpindex;
|
||||
self.last_ori = Lerp::lerp(self.last_ori, ori, 15.0 * dt);
|
||||
|
||||
// Update interpolation values
|
||||
|
@ -301,7 +301,7 @@ impl Scene {
|
||||
);
|
||||
|
||||
// Maintain the figures.
|
||||
self.figure_mgr.maintain(renderer, client);
|
||||
self.figure_mgr.maintain(renderer, client, &self.camera);
|
||||
|
||||
// Remove unused figures.
|
||||
self.figure_mgr.clean(client.get_tick());
|
||||
|
Loading…
Reference in New Issue
Block a user