From f35c98d1a18096a520fad4e3acf54b0cf64948c7 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 10 May 2022 12:36:44 +0100 Subject: [PATCH] Added LoD distance setting --- assets/voxygen/i18n/en/hud/settings.ron | 1 + client/src/lib.rs | 30 +++++--- common/net/src/msg/server.rs | 2 +- common/src/lod.rs | 13 +--- server/src/lib.rs | 4 +- server/src/lod.rs | 2 +- server/src/sys/msg/terrain.rs | 4 +- voxygen/src/hud/settings_window/video.rs | 46 +++++++++-- voxygen/src/render/mod.rs | 5 +- voxygen/src/render/pipelines/lod_object.rs | 21 ++--- voxygen/src/render/renderer.rs | 2 +- voxygen/src/render/renderer/binding.rs | 4 +- voxygen/src/render/renderer/drawer.rs | 15 ++-- .../src/render/renderer/pipeline_creation.rs | 9 ++- voxygen/src/scene/lod.rs | 62 ++++++++------- voxygen/src/session/settings_change.rs | 9 +++ voxygen/src/settings/graphics.rs | 2 + world/src/layer/tree.rs | 5 +- world/src/lib.rs | 76 ++++++++++--------- world/src/sim/mod.rs | 6 +- world/src/util/structure.rs | 28 ++++--- 21 files changed, 206 insertions(+), 140 deletions(-) diff --git a/assets/voxygen/i18n/en/hud/settings.ron b/assets/voxygen/i18n/en/hud/settings.ron index cfe5ffab23..fc1369da8f 100644 --- a/assets/voxygen/i18n/en/hud/settings.ron +++ b/assets/voxygen/i18n/en/hud/settings.ron @@ -59,6 +59,7 @@ "hud.settings.reset_gameplay": "Reset to Defaults", "hud.settings.view_distance": "View Distance", + "hud.settings.lod_distance": "LoD Distance", "hud.settings.sprites_view_distance": "Sprites View Distance", "hud.settings.figures_view_distance": "Entities View Distance", "hud.settings.maximum_fps": "Maximum FPS", diff --git a/client/src/lib.rs b/client/src/lib.rs index a9a18f2b92..0c8360fe8f 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -35,10 +35,12 @@ use common::{ event::{EventBus, LocalEvent}, grid::Grid, link::Is, + lod, mounting::Rider, outcome::Outcome, recipe::RecipeBook, resources::{PlayerEntity, TimeOfDay}, + spiral::Spiral2d, terrain::{ block::Block, map::MapConfig, neighbors, BiomeKind, SitesKind, SpriteKind, TerrainChunk, TerrainChunkSize, @@ -46,8 +48,6 @@ use common::{ trade::{PendingTrade, SitePrices, TradeAction, TradeId, TradeResult}, uid::{Uid, UidAllocator}, vol::RectVolSize, - spiral::Spiral2d, - lod, }; use common_base::{prof_span, span}; use common_net::{ @@ -206,7 +206,7 @@ pub struct Client { state: State, view_distance: Option, - lod_distance: u32, + lod_distance: f32, // TODO: move into voxygen loaded_distance: f32, @@ -658,7 +658,7 @@ impl Client { tick: 0, state, view_distance: None, - lod_distance: 4, // TODO: Make configurable + lod_distance: 2.0, // TODO: Make configurable loaded_distance: 0.0, pending_chunks: HashMap::new(), @@ -890,6 +890,11 @@ impl Client { self.send_msg(ClientGeneral::SetViewDistance(view_distance)); } + pub fn set_lod_distance(&mut self, lod_distance: u32) { + let lod_distance = lod_distance.max(1).min(1000) as f32 / lod::ZONE_SIZE as f32; + self.lod_distance = lod_distance; + } + pub fn use_slot(&mut self, slot: Slot) { self.control_action(ControlAction::InventoryAction(InventoryAction::Use(slot))) } @@ -1004,9 +1009,7 @@ impl Client { &self.available_recipes } - pub fn lod_zones(&self) -> &HashMap, lod::Zone> { - &self.lod_zones - } + pub fn lod_zones(&self) -> &HashMap, lod::Zone> { &self.lod_zones } /// Returns whether the specified recipe can be crafted and the sprite, if /// any, that is required to do so. @@ -1728,11 +1731,15 @@ impl Client { let lod_zone = pos.0.xy().map(|e| lod::from_wpos(e as i32)); // Request LoD zones that are in range - if self.lod_last_requested.map_or(true, |i| i.elapsed() > Duration::from_secs(5)) { + if self + .lod_last_requested + .map_or(true, |i| i.elapsed() > Duration::from_secs(5)) + { if let Some(rpos) = Spiral2d::new() - .take((1 + self.lod_distance * 2).pow(2) as usize) + .take((1 + self.lod_distance.ceil() as i32 * 2).pow(2) as usize) .filter(|rpos| !self.lod_zones.contains_key(&(lod_zone + *rpos))) .min_by_key(|rpos| rpos.magnitude_squared()) + .filter(|rpos| rpos.map(|e| e as f32).magnitude() < self.lod_distance) { self.send_msg_err(ClientGeneral::LodZoneRequest { key: lod_zone + rpos, @@ -1742,7 +1749,10 @@ impl Client { } // Cull LoD zones out of range - self.lod_zones.retain(|p, _| (*p - lod_zone).magnitude_squared() < (self.lod_distance as i32 + 1).pow(2)); + self.lod_zones.retain(|p, _| { + (*p - lod_zone).map(|e| e as f32).magnitude_squared() + < (self.lod_distance + 1.0).powi(2) + }); } Ok(()) diff --git a/common/net/src/msg/server.rs b/common/net/src/msg/server.rs index d8174d2d7c..c581874345 100644 --- a/common/net/src/msg/server.rs +++ b/common/net/src/msg/server.rs @@ -7,13 +7,13 @@ use common::{ calendar::Calendar, character::{self, CharacterItem}, comp::{self, invite::InviteKind, item::MaterialStatManifest}, + lod, outcome::Outcome, recipe::RecipeBook, resources::TimeOfDay, terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize}, trade::{PendingTrade, SitePrices, TradeId, TradeResult}, uid::Uid, - lod, }; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; diff --git a/common/src/lod.rs b/common/src/lod.rs index 636bc86b05..123ff87277 100644 --- a/common/src/lod.rs +++ b/common/src/lod.rs @@ -1,10 +1,7 @@ -use vek::*; -use serde::{Serialize, Deserialize}; +use crate::{terrain::TerrainChunkSize, vol::RectVolSize}; +use serde::{Deserialize, Serialize}; use strum::EnumIter; -use crate::{ - terrain::TerrainChunkSize, - vol::RectVolSize, -}; +use vek::*; // In chunks pub const ZONE_SIZE: u32 = 32; @@ -35,9 +32,7 @@ pub struct Zone { pub objects: Vec, } -pub fn to_wpos(wpos: i32) -> i32 { - wpos * (TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32 -} +pub fn to_wpos(wpos: i32) -> i32 { wpos * (TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32 } pub fn from_wpos(zone_pos: i32) -> i32 { zone_pos.div_euclid((TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32) diff --git a/server/src/lib.rs b/server/src/lib.rs index ad4fb55e9c..7fb2073d81 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -450,7 +450,9 @@ impl Server { // Insert the world into the ECS (todo: Maybe not an Arc?) let world = Arc::new(world); state.ecs_mut().insert(Arc::clone(&world)); - state.ecs_mut().insert(lod::Lod::from_world(&world, index.as_index_ref())); + state + .ecs_mut() + .insert(lod::Lod::from_world(&world, index.as_index_ref())); state.ecs_mut().insert(index.clone()); // Set starting time for the server. diff --git a/server/src/lod.rs b/server/src/lod.rs index 9a7a02f8ed..8cfb1019ac 100644 --- a/server/src/lod.rs +++ b/server/src/lod.rs @@ -1,7 +1,7 @@ use common::lod; -use world::World; use hashbrown::HashMap; use vek::*; +use world::World; static EMPTY_ZONE: lod::Zone = lod::Zone { objects: Vec::new(), diff --git a/server/src/sys/msg/terrain.rs b/server/src/sys/msg/terrain.rs index d806e36ca9..ab1ffec448 100644 --- a/server/src/sys/msg/terrain.rs +++ b/server/src/sys/msg/terrain.rs @@ -1,4 +1,6 @@ -use crate::{client::Client, lod::Lod, metrics::NetworkRequestMetrics, presence::Presence, ChunkRequest}; +use crate::{ + client::Client, lod::Lod, metrics::NetworkRequestMetrics, presence::Presence, ChunkRequest, +}; use common::{ comp::Pos, event::{EventBus, ServerEvent}, diff --git a/voxygen/src/hud/settings_window/video.rs b/voxygen/src/hud/settings_window/video.rs index 0d85de8537..c0d227f82d 100644 --- a/voxygen/src/hud/settings_window/video.rs +++ b/voxygen/src/hud/settings_window/video.rs @@ -39,6 +39,9 @@ widget_ids! { vd_slider, vd_text, vd_value, + ld_slider, + ld_text, + ld_value, lod_detail_slider, lod_detail_text, lod_detail_value, @@ -280,8 +283,6 @@ impl<'a> Widget for Video<'a> { if let Some(new_val) = ImageSlider::discrete( self.global_state.settings.graphics.view_distance, 1, - // FIXME: Move back to 64 once we support multiple texture atlases, or figure out a - // way to increase the size of the terrain atlas. 65, self.imgs.slider_indicator, self.imgs.slider, @@ -306,9 +307,44 @@ impl<'a> Widget for Video<'a> { .color(TEXT_COLOR) .set(state.ids.vd_value, ui); + // LoD Distance + Text::new(self.localized_strings.get("hud.settings.lod_distance")) + .down_from(state.ids.vd_slider, 10.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.ld_text, ui); + + if let Some(new_val) = ImageSlider::discrete( + self.global_state.settings.graphics.lod_distance, + 0, + 250, + self.imgs.slider_indicator, + self.imgs.slider, + ) + .w_h(104.0, 22.0) + .down_from(state.ids.ld_text, 8.0) + .track_breadth(12.0) + .slider_length(10.0) + .pad_track((5.0, 5.0)) + .set(state.ids.ld_slider, ui) + { + events.push(GraphicsChange::AdjustLodDistance(new_val)); + } + + Text::new(&format!( + "{}", + self.global_state.settings.graphics.lod_distance + )) + .right_from(state.ids.ld_slider, 8.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.ld_value, ui); + // Max FPS Text::new(self.localized_strings.get("hud.settings.maximum_fps")) - .down_from(state.ids.vd_slider, 10.0) + .down_from(state.ids.ld_slider, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) @@ -343,7 +379,7 @@ impl<'a> Widget for Video<'a> { // Max Background FPS Text::new(self.localized_strings.get("hud.settings.background_fps")) - .down_from(state.ids.vd_slider, 10.0) + .down_from(state.ids.ld_slider, 10.0) .right_from(state.ids.max_fps_value, 30.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) @@ -391,7 +427,7 @@ impl<'a> Widget for Video<'a> { // Present Mode Text::new(self.localized_strings.get("hud.settings.present_mode")) - .down_from(state.ids.vd_slider, 10.0) + .down_from(state.ids.ld_slider, 10.0) .right_from(state.ids.max_background_fps_value, 30.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 81adaa28b4..4eee800bfc 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -26,6 +26,7 @@ pub use self::{ Locals as FigureLocals, }, fluid::Vertex as FluidVertex, + lod_object::{Instance as LodObjectInstance, Vertex as LodObjectVertex}, lod_terrain::{LodData, Vertex as LodTerrainVertex}, particle::{Instance as ParticleInstance, Vertex as ParticleVertex}, postprocess::Locals as PostProcessLocals, @@ -35,10 +36,6 @@ pub use self::{ Instance as SpriteInstance, SpriteGlobalsBindGroup, SpriteVerts, Vertex as SpriteVertex, VERT_PAGE_SIZE as SPRITE_VERT_PAGE_SIZE, }, - lod_object::{ - Instance as LodObjectInstance, - Vertex as LodObjectVertex, - }, terrain::{Locals as TerrainLocals, TerrainLayout, Vertex as TerrainVertex}, trail::Vertex as TrailVertex, ui::{ diff --git a/voxygen/src/render/pipelines/lod_object.rs b/voxygen/src/render/pipelines/lod_object.rs index 2276c0a90d..b6a40a6d1e 100644 --- a/voxygen/src/render/pipelines/lod_object.rs +++ b/voxygen/src/render/pipelines/lod_object.rs @@ -37,11 +37,12 @@ impl Vertex { } // impl Default for Vertex { -// fn default() -> Self { Self::new(Vec2::zero(), Vec3::zero(), Vec3::zero()) } -// } +// fn default() -> Self { Self::new(Vec2::zero(), Vec3::zero(), +// Vec3::zero()) } } impl VertexTrait for Vertex { - const QUADS_INDEX: Option = None;//Some(wgpu::IndexFormat::Uint16); + const QUADS_INDEX: Option = None; + //Some(wgpu::IndexFormat::Uint16); const STRIDE: wgpu::BufferAddress = mem::size_of::() as wgpu::BufferAddress; } @@ -53,10 +54,7 @@ pub struct Instance { } impl Instance { - pub fn new( - inst_pos: Vec3, - flags: common::lod::Flags, - ) -> Self { + pub fn new(inst_pos: Vec3, flags: common::lod::Flags) -> Self { Self { inst_pos: inst_pos.into_array(), flags: flags.bits() as u32, @@ -77,8 +75,8 @@ impl Instance { } // impl Default for Instance { -// fn default() -> Self { Self::new(Mat4::identity(), 0.0, 0.0, Vec3::zero(), 0, 1.0, 0.0, 0) } -// } +// fn default() -> Self { Self::new(Mat4::identity(), 0.0, 0.0, +// Vec3::zero(), 0, 1.0, 0.0, 0) } } // TODO: ColLightsWrapper instead? pub struct Locals; @@ -100,10 +98,7 @@ impl LodObjectPipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("LoD object pipeline layout"), push_constant_ranges: &[], - bind_group_layouts: &[ - &global_layout.globals, - &global_layout.shadow_textures, - ], + bind_group_layouts: &[&global_layout.globals, &global_layout.shadow_textures], }); let samples = match aa_mode { diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index f3d6096af3..33dd38667e 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -21,7 +21,7 @@ use super::{ mesh::Mesh, model::{DynamicModel, Model}, pipelines::{ - blit, bloom, clouds, debug, figure, postprocess, shadow, sprite, lod_object, terrain, ui, + blit, bloom, clouds, debug, figure, lod_object, postprocess, shadow, sprite, terrain, ui, GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup, }, texture::Texture, diff --git a/voxygen/src/render/renderer/binding.rs b/voxygen/src/render/renderer/binding.rs index 5e4074a58f..3730886d0b 100644 --- a/voxygen/src/render/renderer/binding.rs +++ b/voxygen/src/render/renderer/binding.rs @@ -1,8 +1,8 @@ use super::{ super::{ pipelines::{ - debug, figure, lod_terrain, shadow, sprite, lod_object, terrain, ui, ColLights, GlobalModel, - GlobalsBindGroup, + debug, figure, lod_object, lod_terrain, shadow, sprite, terrain, ui, ColLights, + GlobalModel, GlobalsBindGroup, }, texture::Texture, }, diff --git a/voxygen/src/render/renderer/drawer.rs b/voxygen/src/render/renderer/drawer.rs index 1bf50519f5..f7cdfa8e8e 100644 --- a/voxygen/src/render/renderer/drawer.rs +++ b/voxygen/src/render/renderer/drawer.rs @@ -4,8 +4,9 @@ use super::{ instances::Instances, model::{DynamicModel, Model, SubModel}, pipelines::{ - blit, bloom, clouds, debug, figure, fluid, lod_terrain, particle, shadow, skybox, - sprite, lod_object, terrain, trail, ui, ColLights, GlobalsBindGroup, ShadowTexturesBindGroup, + blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle, shadow, + skybox, sprite, terrain, trail, ui, ColLights, GlobalsBindGroup, + ShadowTexturesBindGroup, }, }, Renderer, ShadowMap, ShadowMapRenderer, @@ -764,9 +765,7 @@ impl<'pass> FirstPassDrawer<'pass> { } } - pub fn draw_lod_objects<'data: 'pass>( - &mut self, - ) -> LodObjectDrawer<'_, 'pass> { + pub fn draw_lod_objects<'data: 'pass>(&mut self) -> LodObjectDrawer<'_, 'pass> { let mut render_pass = self.render_pass.scope("lod objects", self.borrow.device); render_pass.set_pipeline(&self.pipelines.lod_object.pipeline); @@ -934,10 +933,8 @@ impl<'pass_ref, 'pass: 'pass_ref> LodObjectDrawer<'pass_ref, 'pass> { self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); self.render_pass .set_vertex_buffer(1, instances.buf().slice(..)); - self.render_pass.draw( - 0..model.len() as u32, - 0..instances.count() as u32, - ); + self.render_pass + .draw(0..model.len() as u32, 0..instances.count() as u32); } } diff --git a/voxygen/src/render/renderer/pipeline_creation.rs b/voxygen/src/render/renderer/pipeline_creation.rs index de250809a2..7ce0d19ff6 100644 --- a/voxygen/src/render/renderer/pipeline_creation.rs +++ b/voxygen/src/render/renderer/pipeline_creation.rs @@ -1,8 +1,8 @@ use super::{ super::{ pipelines::{ - blit, bloom, clouds, debug, figure, fluid, lod_terrain, particle, postprocess, shadow, - skybox, sprite, lod_object, terrain, trail, ui, + blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle, + postprocess, shadow, skybox, sprite, terrain, trail, ui, }, AaMode, BloomMode, CloudMode, FluidMode, LightingMode, PipelineModes, RenderError, ShadowMode, @@ -763,7 +763,10 @@ fn create_ingame_and_shadow_pipelines( ((debug, (skybox, figure)), (terrain, (fluid, bloom))), ((sprite, particle), (lod_terrain, (clouds, trail))), ), - (((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)), lod_object), + ( + ((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)), + lod_object, + ), ) = pool.join( || pool.join(|| pool.join(j1, j2), || pool.join(j3, j4)), || pool.join(|| pool.join(j5, j6), j7), diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index bf4b4dd3c3..ec82b6be4e 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -1,19 +1,20 @@ use crate::{ render::{ pipelines::lod_terrain::{LodData, Vertex}, - FirstPassDrawer, LodTerrainVertex, LodObjectVertex, Mesh, Model, Quad, Renderer, Instances, LodObjectInstance, Tri, + FirstPassDrawer, Instances, LodObjectInstance, LodObjectVertex, LodTerrainVertex, Mesh, + Model, Quad, Renderer, Tri, }, scene::GlobalModel, settings::Settings, }; -use hashbrown::HashMap; use client::Client; use common::{ - assets::{ObjAsset, AssetExt}, + assets::{AssetExt, ObjAsset}, + lod, spiral::Spiral2d, util::srgba_to_linear, - lod, }; +use hashbrown::HashMap; use vek::*; pub struct Lod { @@ -31,11 +32,7 @@ pub fn water_color() -> Rgba { } impl Lod { - pub fn new( - renderer: &mut Renderer, - client: &Client, - settings: &Settings, - ) -> Self { + pub fn new(renderer: &mut Renderer, client: &Client, settings: &Settings) -> Self { let data = LodData::new( renderer, client.world_data().chunk_size().as_(), @@ -44,16 +41,22 @@ impl Lod { client.world_data().lod_horizon.raw(), settings.graphics.lod_detail.max(100).min(2500), /* TODO: figure out how we want to do this without color borders? - * water_color().into_array().into(), */ + * water_color().into_array().into(), */ ); Self { zone_objects: HashMap::new(), object_data: [ - (lod::ObjectKind::Oak, make_lod_object("oak", renderer, &data)), - (lod::ObjectKind::Pine, make_lod_object("pine", renderer, &data)), + ( + lod::ObjectKind::Oak, + make_lod_object("oak", renderer, &data), + ), + ( + lod::ObjectKind::Pine, + make_lod_object("pine", renderer, &data), + ), ] - .into_iter() - .collect(), + .into_iter() + .collect(), model: None, data, } @@ -98,13 +101,19 @@ impl Lod { objects .into_iter() .map(|(kind, instances)| { - (kind, renderer.create_instances(&instances).expect("Renderer error?!")) + ( + kind, + renderer + .create_instances(&instances) + .expect("Renderer error?!"), + ) }) .collect() }); } - self.zone_objects.retain(|p, _| client.lod_zones().contains_key(p)); + self.zone_objects + .retain(|p, _| client.lod_zones().contains_key(p)); } pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>) { @@ -159,19 +168,20 @@ fn make_lod_object( ) -> Model { let model = ObjAsset::load_expect(&format!("voxygen.lod.{}", name)); let mesh = model - .read().0 + .read() + .0 .triangles() .map(|vs| { - let [a, b, c] = vs.map(|v| LodObjectVertex::new( - v.position().into(), - v.normal().unwrap_or([0.0, 0.0, 1.0]).into(), - Vec3::broadcast(1.0), - //v.color().unwrap_or([1.0; 3]).into(), - )); + let [a, b, c] = vs.map(|v| { + LodObjectVertex::new( + v.position().into(), + v.normal().unwrap_or([0.0, 0.0, 1.0]).into(), + Vec3::broadcast(1.0), + //v.color().unwrap_or([1.0; 3]).into(), + ) + }); Tri::new(a, b, c) }) .collect(); - renderer - .create_model(&mesh) - .expect("Mesh was empty!") + renderer.create_model(&mesh).expect("Mesh was empty!") } diff --git a/voxygen/src/session/settings_change.rs b/voxygen/src/session/settings_change.rs index 79608fab23..0af724f2aa 100644 --- a/voxygen/src/session/settings_change.rs +++ b/voxygen/src/session/settings_change.rs @@ -69,6 +69,7 @@ pub enum Gameplay { #[derive(Clone)] pub enum Graphics { AdjustViewDistance(u32), + AdjustLodDistance(u32), AdjustLodDetail(u32), AdjustSpriteRenderDistance(u32), AdjustFigureLoDRenderDistance(u32), @@ -344,6 +345,14 @@ impl SettingsChange { settings.graphics.view_distance = view_distance; }, + Graphics::AdjustLodDistance(lod_distance) => { + session_state + .client + .borrow_mut() + .set_lod_distance(lod_distance); + + settings.graphics.lod_distance = lod_distance; + }, Graphics::AdjustLodDetail(lod_detail) => { session_state.scene.lod.set_detail(lod_detail); diff --git a/voxygen/src/settings/graphics.rs b/voxygen/src/settings/graphics.rs index 5c9b8b5f4a..08079e9fe7 100644 --- a/voxygen/src/settings/graphics.rs +++ b/voxygen/src/settings/graphics.rs @@ -30,6 +30,7 @@ impl fmt::Display for Fps { #[serde(default)] pub struct GraphicsSettings { pub view_distance: u32, + pub lod_distance: u32, pub sprite_render_distance: u32, pub particles_enabled: bool, pub lossy_terrain_compression: bool, @@ -51,6 +52,7 @@ impl Default for GraphicsSettings { fn default() -> Self { Self { view_distance: 10, + lod_distance: 100, sprite_render_distance: 100, particles_enabled: true, lossy_terrain_compression: false, diff --git a/world/src/layer/tree.rs b/world/src/layer/tree.rs index d26c4e03e8..73fca950d4 100644 --- a/world/src/layer/tree.rs +++ b/world/src/layer/tree.rs @@ -3,8 +3,7 @@ use crate::{ block::block_from_structure, column::ColumnGen, util::{gen_cache::StructureGenCache, RandomPerm, Sampler, UnitChooser}, - Canvas, - ColumnSample, + Canvas, ColumnSample, }; use common::{ assets::AssetHandle, @@ -41,7 +40,7 @@ pub fn tree_valid_at(col: &ColumnSample, seed: u32) -> bool { || col.water_dist.map(|d| d < 8.0).unwrap_or(false) || col.path.map(|(d, _, _, _)| d < 12.0).unwrap_or(false) { - return false + return false; } if ((seed.wrapping_mul(13)) & 0xFF) as f32 / 256.0 > col.tree_density { diff --git a/world/src/lib.rs b/world/src/lib.rs index bcb98fed2e..d91848059a 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -51,12 +51,12 @@ use common::{ assets, calendar::Calendar, generation::{ChunkSupplement, EntityInfo}, + lod, resources::TimeOfDay, terrain::{ Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize, TerrainGrid, }, vol::{ReadVol, RectVolSize, WriteVol}, - lod, }; use common_net::msg::{world_msg, WorldMapMsg}; use rand::{prelude::*, Rng}; @@ -467,45 +467,51 @@ impl World { } // Zone coordinates - pub fn get_lod_zone( - &self, - pos: Vec2, - index: IndexRef, - ) -> lod::Zone { + pub fn get_lod_zone(&self, pos: Vec2, index: IndexRef) -> lod::Zone { let min_wpos = pos.map(lod::to_wpos); let max_wpos = (pos + 1).map(lod::to_wpos); let mut objects = Vec::new(); - objects.append(&mut self.sim() - .get_area_trees(min_wpos, max_wpos) - .filter_map(|attr| { - ColumnGen::new(self.sim()).get((attr.pos, index, self.sim().calendar.as_ref())) - .filter(|col| layer::tree::tree_valid_at(col, attr.seed)) - .zip(Some(attr)) - }) - .filter_map(|(col, tree)| Some(lod::Object { - kind: match tree.forest_kind { - all::ForestKind::Oak => lod::ObjectKind::Oak, - all::ForestKind::Pine - | all::ForestKind::Frostpine=> lod::ObjectKind::Pine, - _ => lod::ObjectKind::Oak, - }, - pos: { - let rpos = tree.pos - min_wpos; - if rpos.is_any_negative() { - return None - } else { - rpos - .map(|e| e as u16) - .with_z(self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16) - } - }, - flags: lod::Flags::empty() - | if col.snow_cover { lod::Flags::SNOW_COVERED } else { lod::Flags::empty() } - , - })) - .collect()); + objects.append( + &mut self + .sim() + .get_area_trees(min_wpos, max_wpos) + .filter_map(|attr| { + ColumnGen::new(self.sim()) + .get((attr.pos, index, self.sim().calendar.as_ref())) + .filter(|col| layer::tree::tree_valid_at(col, attr.seed)) + .zip(Some(attr)) + }) + .filter_map(|(col, tree)| { + Some(lod::Object { + kind: match tree.forest_kind { + all::ForestKind::Oak => lod::ObjectKind::Oak, + all::ForestKind::Pine | all::ForestKind::Frostpine => { + lod::ObjectKind::Pine + }, + _ => lod::ObjectKind::Oak, + }, + pos: { + let rpos = tree.pos - min_wpos; + if rpos.is_any_negative() { + return None; + } else { + rpos.map(|e| e as u16).with_z( + self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16, + ) + } + }, + flags: lod::Flags::empty() + | if col.snow_cover { + lod::Flags::SNOW_COVERED + } else { + lod::Flags::empty() + }, + }) + }) + .collect(), + ); lod::Zone { objects } } diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 592046c8e2..aef99119db 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -2150,7 +2150,11 @@ impl WorldSim { }) } - pub fn get_area_trees(&self, wpos_min: Vec2, wpos_max: Vec2) -> impl ParallelIterator + '_ { + pub fn get_area_trees( + &self, + wpos_min: Vec2, + wpos_max: Vec2, + ) -> impl ParallelIterator + '_ { self.gen_ctx .structure_gen .par_iter(wpos_min, wpos_max) diff --git a/world/src/util/structure.rs b/world/src/util/structure.rs index be3b6d1aee..2b7b8bfa1a 100644 --- a/world/src/util/structure.rs +++ b/world/src/util/structure.rs @@ -102,21 +102,19 @@ impl StructureGen2d { let x_field = self.x_field; let y_field = self.y_field; let seed_field = self.seed_field; - (0..len) - .into_par_iter() - .map(move |xy| { - let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32); - Self::index_to_sample_internal( - freq, - freq_offset, - spread, - spread_mul, - x_field, - y_field, - seed_field, - index, - ) - }) + (0..len).into_par_iter().map(move |xy| { + let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32); + Self::index_to_sample_internal( + freq, + freq_offset, + spread, + spread_mul, + x_field, + y_field, + seed_field, + index, + ) + }) } }