Merge branch 'yusdacra/tweaks' into 'master'

Improvements to frustum culling and some changes

Closes #210

See merge request veloren/veloren!708
This commit is contained in:
Acrimon 2020-01-08 17:43:40 +00:00
commit 4e7c955490
13 changed files with 410 additions and 101 deletions

17
Cargo.lock generated
View File

@ -1052,11 +1052,6 @@ name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "frustum_query"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fsevent"
version = "0.4.0"
@ -3308,6 +3303,14 @@ dependencies = [
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "treeculler"
version = "0.1.0"
source = "git+https://gitlab.com/yusdacra/treeculler.git#6c0fdf1c1cbf00be22e37410985d6a3973cd9bed"
dependencies = [
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tuple_utils"
version = "0.3.0"
@ -3522,7 +3525,6 @@ dependencies = [
"euc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"fern 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"frustum_query 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx 0.18.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_device_gl 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_window_glutin 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3542,6 +3544,7 @@ dependencies = [
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
"treeculler 0.1.0 (git+https://gitlab.com/yusdacra/treeculler.git)",
"vek 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
"veloren-client 0.4.0",
"veloren-common 0.4.0",
@ -3952,7 +3955,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum frustum_query 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e1771c26abed26b2527d888742fffd27dab86d205bf4846748abf29c06ef5a05"
"checksum fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
"checksum fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
@ -4201,6 +4203,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum tiny_http 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1661fa0a44c95d01604bd05c66732a446c657efb62b5164a7a083a3b552b4951"
"checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20"
"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf"
"checksum treeculler 0.1.0 (git+https://gitlab.com/yusdacra/treeculler.git)" = "<none>"
"checksum tuple_utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44834418e2c5b16f47bedf35c28e148db099187dd5feee6367fb2525863af4f1"
"checksum twoway 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1"
"checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874"

View File

@ -27,7 +27,7 @@ void main() {
// Increase array access by 3 to access positive values
uint norm_dir = ((f_pos_norm >> 29) & 0x1u) * 3u;
// Use an array to avoid conditional branching
vec3 f_norm = normals[norm_axis + norm_dir];
vec3 f_norm = normals[(f_pos_norm >> 29) & 0x7u];
vec3 light, diffuse_light, ambient_light;
get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0);

View File

@ -55,7 +55,7 @@ directories = "2.0.2"
num = "0.2.0"
backtrace = "0.3.40"
rand = "0.7.2"
frustum_query = "0.1.2"
treeculler = { git = "https://gitlab.com/yusdacra/treeculler.git" }
# context for pinning to commit: https://gitlab.com/veloren/veloren/issues/280
rodio = { git = "https://github.com/RustAudio/rodio", rev = "e5474a2"}
cpal = "0.10"

View File

@ -119,6 +119,8 @@ widget_ids! {
loaded_distance,
time,
entity_count,
num_chunks,
num_figures,
// Game Version
version,
@ -172,6 +174,10 @@ pub struct DebugInfo {
pub ping_ms: f64,
pub coordinates: Option<comp::Pos>,
pub velocity: Option<comp::Vel>,
pub num_chunks: u32,
pub num_visible_chunks: u32,
pub num_figures: u32,
pub num_figures_visible: u32,
}
pub enum Event {
@ -979,6 +985,7 @@ impl Hud {
.font_id(self.fonts.cyri)
.font_size(14)
.set(self.ids.time, ui_widgets);
// Number of entities
let entity_count = client.state().ecs().entities().join().count();
Text::new(&format!("Entity count: {}", entity_count))
@ -988,10 +995,32 @@ impl Hud {
.font_size(14)
.set(self.ids.entity_count, ui_widgets);
// Number of chunks
Text::new(&format!(
"Chunks: {} ({} visible)",
debug_info.num_chunks, debug_info.num_visible_chunks,
))
.color(TEXT_COLOR)
.down_from(self.ids.entity_count, 5.0)
.font_id(self.fonts.cyri)
.font_size(14)
.set(self.ids.num_chunks, ui_widgets);
// Number of figures
Text::new(&format!(
"Figures: {} ({} visible)",
debug_info.num_figures, debug_info.num_figures_visible,
))
.color(TEXT_COLOR)
.down_from(self.ids.num_chunks, 5.0)
.font_id(self.fonts.cyri)
.font_size(14)
.set(self.ids.num_figures, ui_widgets);
// Help Window
Text::new("Press 'F1' to show Keybindings")
.color(TEXT_COLOR)
.down_from(self.ids.entity_count, 5.0)
.down_from(self.ids.num_figures, 5.0)
.font_id(self.fonts.cyri)
.font_size(14)
.set(self.ids.help_info, ui_widgets);

View File

@ -4,7 +4,7 @@ use super::{
};
use crate::{
render::AaMode,
ui::{ImageSlider, RadioList, ScaleMode, ToggleButton},
ui::{ImageSlider, ScaleMode, ToggleButton},
GlobalState,
};
use conrod_core::{
@ -84,8 +84,8 @@ widget_ids! {
fov_slider,
fov_text,
fov_value,
aa_radio_buttons,
aa_mode_text,
aa_mode_list,
audio_volume_slider,
audio_volume_text,
sfx_volume_slider,
@ -1332,30 +1332,38 @@ impl<'a> Widget for SettingsWindow<'a> {
.font_id(self.fonts.cyri)
.color(TEXT_COLOR)
.set(state.ids.aa_mode_text, ui);
let mode_label_list = [
(&AaMode::None, "No AA"),
(&AaMode::Fxaa, "FXAA"),
(&AaMode::MsaaX4, "MSAA x4"),
(&AaMode::MsaaX8, "MSAA x8"),
(&AaMode::MsaaX16, "MSAA x16 (experimental)"),
(&AaMode::SsaaX4, "SSAA x4"),
let mode_list = [
AaMode::None,
AaMode::Fxaa,
AaMode::MsaaX4,
AaMode::MsaaX8,
AaMode::MsaaX16,
AaMode::SsaaX4,
];
if let Some((_, mode)) = RadioList::new(
(0..mode_label_list.len())
.find(|i| *mode_label_list[*i].0 == self.global_state.settings.graphics.aa_mode)
.unwrap_or(0),
self.imgs.check,
self.imgs.check_checked,
&mode_label_list,
)
.hover_images(self.imgs.check_mo, self.imgs.check_checked_mo)
.press_images(self.imgs.check_press, self.imgs.check_press)
.down_from(state.ids.aa_mode_text, 8.0)
.text_color(TEXT_COLOR)
.font_size(12)
.set(state.ids.aa_radio_buttons, ui)
let mode_label_list = [
"No AA",
"FXAA",
"MSAA x4",
"MSAA x8",
"MSAA x16 (experimental)",
"SSAA x4",
];
// Get which AA mode is currently active
let selected = mode_list
.iter()
.position(|x| *x == self.global_state.settings.graphics.aa_mode);
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
.w_h(400.0, 22.0)
.color(MENU_BG)
.label_color(TEXT_COLOR)
.label_font_id(self.fonts.cyri)
.down_from(state.ids.aa_mode_text, 8.0)
.set(state.ids.aa_mode_list, ui)
{
events.push(Event::ChangeAaMode(*mode))
events.push(Event::ChangeAaMode(mode_list[clicked]));
}
}

View File

@ -169,6 +169,8 @@ impl Scene {
1.0 / 60.0, // TODO: Use actual deltatime here?
1.0,
1.0,
0,
true,
);
}

View File

@ -236,7 +236,27 @@ impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeli
offs,
&colors, //&[[[colors[1][1][1]; 3]; 3]; 3],
|pos, norm, col, ao, light| {
TerrainVertex::new(pos, norm, col, light.min(ao))
let light = (light.min(ao) * 255.0) as u32;
let norm = if norm.x != 0.0 {
if norm.x < 0.0 {
0
} else {
1
}
} else if norm.y != 0.0 {
if norm.y < 0.0 {
2
} else {
3
}
} else {
if norm.z < 0.0 {
4
} else {
5
}
};
TerrainVertex::new(norm, light, pos, col)
},
&lights,
);

View File

@ -42,26 +42,18 @@ gfx_defines! {
}
impl Vertex {
pub fn new(pos: Vec3<f32>, norm: Vec3<f32>, col: Rgb<f32>, light: f32) -> Self {
let (norm_axis, norm_dir) = norm
.as_slice()
.into_iter()
.enumerate()
.find(|(_i, e)| **e != 0.0)
.unwrap_or((0, &1.0));
let norm_bits = (norm_axis << 1) | if *norm_dir > 0.0 { 1 } else { 0 };
pub fn new(norm_bits: u32, light: u32, pos: Vec3<f32>, col: Rgb<f32>) -> Self {
Self {
pos_norm: 0
| ((pos.x as u32) & 0x00FF) << 0
| ((pos.y as u32) & 0x00FF) << 8
| ((pos.z.max(0.0).min((1 << 13) as f32) as u32) & 0x1FFF) << 16
| ((norm_bits as u32) & 0x7) << 29,
| (norm_bits & 0x7) << 29,
col_light: 0
| ((col.r.mul(255.0) as u32) & 0xFF) << 8
| ((col.g.mul(255.0) as u32) & 0xFF) << 16
| ((col.b.mul(255.0) as u32) & 0xFF) << 24
| ((light.mul(255.0) as u32) & 0xFF) << 0,
| (light & 0xFF) << 0,
}
}
}

View File

@ -1,7 +1,7 @@
use client::Client;
use common::vol::{ReadVol, Vox};
use frustum_query::frustum::Frustum;
use std::f32::consts::PI;
use treeculler::Frustum;
use vek::*;
const NEAR_PLANE: f32 = 0.5;
@ -100,13 +100,10 @@ impl Camera {
(view_mat, proj_mat, cam_pos)
}
pub fn frustum(&self, client: &Client) -> Frustum {
pub fn frustum(&self, client: &Client) -> Frustum<f32> {
let (view_mat, proj_mat, _) = self.compute_dependents(client);
Frustum::from_modelview_and_projection(
&view_mat.into_col_array(),
&proj_mat.into_col_array(),
)
Frustum::from_modelview_projection((proj_mat * view_mat).into_col_arrays())
}
/// Rotate the camera about its focus by the given delta, limiting the input accordingly.

View File

@ -27,6 +27,7 @@ use common::{
use hashbrown::HashMap;
use log::trace;
use specs::{Entity as EcsEntity, Join, WorldExt};
use treeculler::{BVol, BoundingSphere};
use vek::*;
const DAMAGE_FADE_COEFFICIENT: f64 = 5.0;
@ -66,7 +67,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();
@ -133,6 +134,164 @@ impl FigureMgr {
}
continue;
} else if vd_frac > 1.0 {
match body {
Body::Humanoid(_) => {
self.character_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::QuadrupedSmall(_) => {
self.quadruped_small_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::QuadrupedMedium(_) => {
self.quadruped_medium_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::BirdMedium(_) => {
self.bird_medium_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::FishMedium(_) => {
self.fish_medium_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::Dragon(_) => {
self.dragon_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::BirdSmall(_) => {
self.bird_small_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::FishSmall(_) => {
self.fish_small_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::BipedLarge(_) => {
self.biped_large_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::Object(_) => {
self.object_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
}
continue;
}
// Don't process figures outside the frustum spectrum
let frustum = camera.frustum(client);
let (in_frustum, lpindex) =
BoundingSphere::new(pos.0.into_array(), scale.unwrap_or(&Scale(1.0)).0 * 2.0)
.coherent_test_against_frustum(
&frustum,
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),
);
if !in_frustum {
match body {
Body::Humanoid(_) => {
self.character_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::QuadrupedSmall(_) => {
self.quadruped_small_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::QuadrupedMedium(_) => {
self.quadruped_medium_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::BirdMedium(_) => {
self.bird_medium_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::FishMedium(_) => {
self.fish_medium_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::Dragon(_) => {
self.dragon_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::BirdSmall(_) => {
self.bird_small_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::FishSmall(_) => {
self.fish_small_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::BipedLarge(_) => {
self.biped_large_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
Body::Object(_) => {
self.object_states
.get_mut(&entity)
.map(|state| state.visible = false);
}
}
continue;
}
@ -313,6 +472,8 @@ impl FigureMgr {
dt,
movement_animation_rate,
action_animation_rate,
lpindex,
true,
);
}
Body::QuadrupedSmall(_) => {
@ -370,6 +531,8 @@ impl FigureMgr {
dt,
movement_animation_rate,
action_animation_rate,
lpindex,
true,
);
}
Body::QuadrupedMedium(_) => {
@ -427,6 +590,8 @@ impl FigureMgr {
dt,
movement_animation_rate,
action_animation_rate,
lpindex,
true,
);
}
Body::BirdMedium(_) => {
@ -482,6 +647,8 @@ impl FigureMgr {
dt,
movement_animation_rate,
action_animation_rate,
lpindex,
true,
);
}
Body::FishMedium(_) => {
@ -537,6 +704,8 @@ impl FigureMgr {
dt,
movement_animation_rate,
action_animation_rate,
lpindex,
true,
);
}
Body::Dragon(_) => {
@ -592,6 +761,8 @@ impl FigureMgr {
dt,
movement_animation_rate,
action_animation_rate,
lpindex,
true,
);
}
Body::BirdSmall(_) => {
@ -647,6 +818,8 @@ impl FigureMgr {
dt,
movement_animation_rate,
action_animation_rate,
lpindex,
true,
);
}
Body::FishSmall(_) => {
@ -702,6 +875,8 @@ impl FigureMgr {
dt,
movement_animation_rate,
action_animation_rate,
lpindex,
true,
);
}
Body::BipedLarge(_) => {
@ -757,6 +932,8 @@ impl FigureMgr {
dt,
movement_animation_rate,
action_animation_rate,
lpindex,
true,
);
}
Body::Object(_) => {
@ -776,6 +953,8 @@ impl FigureMgr {
dt,
movement_animation_rate,
action_animation_rate,
lpindex,
true,
);
}
}
@ -816,8 +995,6 @@ 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>();
@ -832,60 +1009,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.sphere_intersecting(
&pos.0.x,
&pos.0.y,
&pos.0.z,
&(scale.unwrap_or(&Scale(1.0)).0 * 2.0),
)
})
// Don't render dead entities
.filter(|(_, _, _, _, stats, _)| stats.map_or(true, |s| !s.is_dead))
{
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 {
@ -912,6 +1084,64 @@ impl FigureMgr {
}
}
}
pub fn figure_count(&self) -> usize {
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.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()
}
}
pub struct FigureState<S: Skeleton> {
@ -923,6 +1153,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> {
@ -938,6 +1170,8 @@ impl<S: Skeleton> FigureState<S> {
pos: Vec3::zero(),
ori: Vec3::zero(),
last_ori: Vec3::zero(),
lpindex: 0,
visible: false,
}
}
@ -952,7 +1186,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

View File

@ -94,7 +94,7 @@ impl Scene {
}
}
/// Get a reference to the scene's globals
/// Get a reference to the scene's globals.
pub fn globals(&self) -> &Consts<Globals> {
&self.globals
}
@ -104,6 +104,16 @@ impl Scene {
&self.camera
}
/// Get a reference to the scene's terrain.
pub fn terrain(&self) -> &Terrain<TerrainChunk> {
&self.terrain
}
/// Get a reference to the scene's figure manager.
pub fn figure_mgr(&self) -> &FigureMgr {
&self.figure_mgr
}
/// Get a mutable reference to the scene's camera.
pub fn camera_mut(&mut self) -> &mut Camera {
&mut self.camera
@ -291,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());

View File

@ -16,9 +16,9 @@ use common::{
};
use crossbeam::channel;
use dot_vox::DotVoxData;
use frustum_query::frustum::Frustum;
use hashbrown::{hash_map::Entry, HashMap};
use std::{f32, fmt::Debug, i32, marker::PhantomData, ops::Mul, time::Duration};
use std::{f32, fmt::Debug, i32, marker::PhantomData, time::Duration};
use treeculler::{BVol, Frustum, AABB};
use vek::*;
struct TerrainChunkData {
@ -31,6 +31,7 @@ struct TerrainChunkData {
visible: bool,
z_bounds: (f32, f32),
frustum_last_plane_index: u8,
}
struct ChunkMeshState {
@ -1021,6 +1022,7 @@ impl<V: RectRasterableVol> Terrain<V> {
.expect("Failed to upload chunk locals to the GPU!"),
visible: false,
z_bounds: response.z_bounds,
frustum_last_plane_index: 0,
},
);
@ -1035,10 +1037,7 @@ impl<V: RectRasterableVol> Terrain<V> {
}
// Construct view frustum
let frustum = Frustum::from_modelview_and_projection(
&view_mat.into_col_array(),
&proj_mat.into_col_array(),
);
let frustum = Frustum::from_modelview_projection((proj_mat * view_mat).into_col_arrays());
// Update chunk visibility
let chunk_sz = V::RECT_SIZE.x as f32;
@ -1050,28 +1049,35 @@ impl<V: RectRasterableVol> Terrain<V> {
let in_range = Vec2::<f32>::from(focus_pos).distance_squared(nearest_in_chunk)
< loaded_distance.powf(2.0);
// Ensure the chunk is within the view frustrum
let chunk_mid = Vec3::new(
chunk_pos.x + chunk_sz / 2.0,
chunk_pos.y + chunk_sz / 2.0,
(chunk.z_bounds.0 + chunk.z_bounds.1) * 0.5,
);
let chunk_radius = ((chunk.z_bounds.1 - chunk.z_bounds.0) / 2.0)
.max(chunk_sz / 2.0)
.powf(2.0)
.mul(2.0)
.sqrt();
let in_frustum = frustum.sphere_intersecting(
&chunk_mid.x,
&chunk_mid.y,
&chunk_mid.z,
&chunk_radius,
);
if !in_range {
chunk.visible = in_range;
continue;
}
chunk.visible = in_range && in_frustum;
// Ensure the chunk is within the view frustum
let chunk_min = [chunk_pos.x, chunk_pos.y, chunk.z_bounds.0];
let chunk_max = [
chunk_pos.x + chunk_sz,
chunk_pos.y + chunk_sz,
chunk.z_bounds.1,
];
let (in_frustum, last_plane_index) = AABB::new(chunk_min, chunk_max)
.coherent_test_against_frustum(&frustum, chunk.frustum_last_plane_index);
chunk.frustum_last_plane_index = last_plane_index;
chunk.visible = in_frustum;
}
}
pub fn chunk_count(&self) -> usize {
self.chunks.len()
}
pub fn visible_chunk_count(&self) -> usize {
self.chunks.iter().filter(|(_, c)| c.visible).count()
}
pub fn render(
&self,
renderer: &mut Renderer,

View File

@ -385,6 +385,10 @@ impl PlayState for SessionState {
.read_storage::<Vel>()
.get(self.client.borrow().entity())
.cloned(),
num_chunks: self.scene.terrain().chunk_count() as u32,
num_visible_chunks: self.scene.terrain().visible_chunk_count() as u32,
num_figures: self.scene.figure_mgr().figure_count() as u32,
num_figures_visible: self.scene.figure_mgr().figure_count_visible() as u32,
},
&self.scene.camera(),
clock.get_last_delta(),