mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
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:
commit
4e7c955490
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,6 +169,8 @@ impl Scene {
|
||||
1.0 / 60.0, // TODO: Use actual deltatime here?
|
||||
1.0,
|
||||
1.0,
|
||||
0,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
@ -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(),
|
||||
|
Loading…
Reference in New Issue
Block a user