mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added LoD distance setting
This commit is contained in:
parent
add9e5f9fe
commit
f35c98d1a1
@ -59,6 +59,7 @@
|
|||||||
"hud.settings.reset_gameplay": "Reset to Defaults",
|
"hud.settings.reset_gameplay": "Reset to Defaults",
|
||||||
|
|
||||||
"hud.settings.view_distance": "View Distance",
|
"hud.settings.view_distance": "View Distance",
|
||||||
|
"hud.settings.lod_distance": "LoD Distance",
|
||||||
"hud.settings.sprites_view_distance": "Sprites View Distance",
|
"hud.settings.sprites_view_distance": "Sprites View Distance",
|
||||||
"hud.settings.figures_view_distance": "Entities View Distance",
|
"hud.settings.figures_view_distance": "Entities View Distance",
|
||||||
"hud.settings.maximum_fps": "Maximum FPS",
|
"hud.settings.maximum_fps": "Maximum FPS",
|
||||||
|
@ -35,10 +35,12 @@ use common::{
|
|||||||
event::{EventBus, LocalEvent},
|
event::{EventBus, LocalEvent},
|
||||||
grid::Grid,
|
grid::Grid,
|
||||||
link::Is,
|
link::Is,
|
||||||
|
lod,
|
||||||
mounting::Rider,
|
mounting::Rider,
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
recipe::RecipeBook,
|
recipe::RecipeBook,
|
||||||
resources::{PlayerEntity, TimeOfDay},
|
resources::{PlayerEntity, TimeOfDay},
|
||||||
|
spiral::Spiral2d,
|
||||||
terrain::{
|
terrain::{
|
||||||
block::Block, map::MapConfig, neighbors, BiomeKind, SitesKind, SpriteKind, TerrainChunk,
|
block::Block, map::MapConfig, neighbors, BiomeKind, SitesKind, SpriteKind, TerrainChunk,
|
||||||
TerrainChunkSize,
|
TerrainChunkSize,
|
||||||
@ -46,8 +48,6 @@ use common::{
|
|||||||
trade::{PendingTrade, SitePrices, TradeAction, TradeId, TradeResult},
|
trade::{PendingTrade, SitePrices, TradeAction, TradeId, TradeResult},
|
||||||
uid::{Uid, UidAllocator},
|
uid::{Uid, UidAllocator},
|
||||||
vol::RectVolSize,
|
vol::RectVolSize,
|
||||||
spiral::Spiral2d,
|
|
||||||
lod,
|
|
||||||
};
|
};
|
||||||
use common_base::{prof_span, span};
|
use common_base::{prof_span, span};
|
||||||
use common_net::{
|
use common_net::{
|
||||||
@ -206,7 +206,7 @@ pub struct Client {
|
|||||||
state: State,
|
state: State,
|
||||||
|
|
||||||
view_distance: Option<u32>,
|
view_distance: Option<u32>,
|
||||||
lod_distance: u32,
|
lod_distance: f32,
|
||||||
// TODO: move into voxygen
|
// TODO: move into voxygen
|
||||||
loaded_distance: f32,
|
loaded_distance: f32,
|
||||||
|
|
||||||
@ -658,7 +658,7 @@ impl Client {
|
|||||||
tick: 0,
|
tick: 0,
|
||||||
state,
|
state,
|
||||||
view_distance: None,
|
view_distance: None,
|
||||||
lod_distance: 4, // TODO: Make configurable
|
lod_distance: 2.0, // TODO: Make configurable
|
||||||
loaded_distance: 0.0,
|
loaded_distance: 0.0,
|
||||||
|
|
||||||
pending_chunks: HashMap::new(),
|
pending_chunks: HashMap::new(),
|
||||||
@ -890,6 +890,11 @@ impl Client {
|
|||||||
self.send_msg(ClientGeneral::SetViewDistance(view_distance));
|
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) {
|
pub fn use_slot(&mut self, slot: Slot) {
|
||||||
self.control_action(ControlAction::InventoryAction(InventoryAction::Use(slot)))
|
self.control_action(ControlAction::InventoryAction(InventoryAction::Use(slot)))
|
||||||
}
|
}
|
||||||
@ -1004,9 +1009,7 @@ impl Client {
|
|||||||
&self.available_recipes
|
&self.available_recipes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lod_zones(&self) -> &HashMap<Vec2<i32>, lod::Zone> {
|
pub fn lod_zones(&self) -> &HashMap<Vec2<i32>, lod::Zone> { &self.lod_zones }
|
||||||
&self.lod_zones
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the specified recipe can be crafted and the sprite, if
|
/// Returns whether the specified recipe can be crafted and the sprite, if
|
||||||
/// any, that is required to do so.
|
/// 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));
|
let lod_zone = pos.0.xy().map(|e| lod::from_wpos(e as i32));
|
||||||
|
|
||||||
// Request LoD zones that are in range
|
// 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()
|
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)))
|
.filter(|rpos| !self.lod_zones.contains_key(&(lod_zone + *rpos)))
|
||||||
.min_by_key(|rpos| rpos.magnitude_squared())
|
.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 {
|
self.send_msg_err(ClientGeneral::LodZoneRequest {
|
||||||
key: lod_zone + rpos,
|
key: lod_zone + rpos,
|
||||||
@ -1742,7 +1749,10 @@ impl Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cull LoD zones out of range
|
// 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(())
|
Ok(())
|
||||||
|
@ -7,13 +7,13 @@ use common::{
|
|||||||
calendar::Calendar,
|
calendar::Calendar,
|
||||||
character::{self, CharacterItem},
|
character::{self, CharacterItem},
|
||||||
comp::{self, invite::InviteKind, item::MaterialStatManifest},
|
comp::{self, invite::InviteKind, item::MaterialStatManifest},
|
||||||
|
lod,
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
recipe::RecipeBook,
|
recipe::RecipeBook,
|
||||||
resources::TimeOfDay,
|
resources::TimeOfDay,
|
||||||
terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
||||||
trade::{PendingTrade, SitePrices, TradeId, TradeResult},
|
trade::{PendingTrade, SitePrices, TradeId, TradeResult},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
lod,
|
|
||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
use vek::*;
|
use crate::{terrain::TerrainChunkSize, vol::RectVolSize};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use strum::EnumIter;
|
use strum::EnumIter;
|
||||||
use crate::{
|
use vek::*;
|
||||||
terrain::TerrainChunkSize,
|
|
||||||
vol::RectVolSize,
|
|
||||||
};
|
|
||||||
|
|
||||||
// In chunks
|
// In chunks
|
||||||
pub const ZONE_SIZE: u32 = 32;
|
pub const ZONE_SIZE: u32 = 32;
|
||||||
@ -35,9 +32,7 @@ pub struct Zone {
|
|||||||
pub objects: Vec<Object>,
|
pub objects: Vec<Object>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_wpos(wpos: i32) -> i32 {
|
pub fn to_wpos(wpos: i32) -> i32 { wpos * (TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32 }
|
||||||
wpos * (TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_wpos(zone_pos: i32) -> i32 {
|
pub fn from_wpos(zone_pos: i32) -> i32 {
|
||||||
zone_pos.div_euclid((TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32)
|
zone_pos.div_euclid((TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32)
|
||||||
|
@ -450,7 +450,9 @@ impl Server {
|
|||||||
// Insert the world into the ECS (todo: Maybe not an Arc?)
|
// Insert the world into the ECS (todo: Maybe not an Arc?)
|
||||||
let world = Arc::new(world);
|
let world = Arc::new(world);
|
||||||
state.ecs_mut().insert(Arc::clone(&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());
|
state.ecs_mut().insert(index.clone());
|
||||||
|
|
||||||
// Set starting time for the server.
|
// Set starting time for the server.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use common::lod;
|
use common::lod;
|
||||||
use world::World;
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
use world::World;
|
||||||
|
|
||||||
static EMPTY_ZONE: lod::Zone = lod::Zone {
|
static EMPTY_ZONE: lod::Zone = lod::Zone {
|
||||||
objects: Vec::new(),
|
objects: Vec::new(),
|
||||||
|
@ -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::{
|
use common::{
|
||||||
comp::Pos,
|
comp::Pos,
|
||||||
event::{EventBus, ServerEvent},
|
event::{EventBus, ServerEvent},
|
||||||
|
@ -39,6 +39,9 @@ widget_ids! {
|
|||||||
vd_slider,
|
vd_slider,
|
||||||
vd_text,
|
vd_text,
|
||||||
vd_value,
|
vd_value,
|
||||||
|
ld_slider,
|
||||||
|
ld_text,
|
||||||
|
ld_value,
|
||||||
lod_detail_slider,
|
lod_detail_slider,
|
||||||
lod_detail_text,
|
lod_detail_text,
|
||||||
lod_detail_value,
|
lod_detail_value,
|
||||||
@ -280,8 +283,6 @@ impl<'a> Widget for Video<'a> {
|
|||||||
if let Some(new_val) = ImageSlider::discrete(
|
if let Some(new_val) = ImageSlider::discrete(
|
||||||
self.global_state.settings.graphics.view_distance,
|
self.global_state.settings.graphics.view_distance,
|
||||||
1,
|
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,
|
65,
|
||||||
self.imgs.slider_indicator,
|
self.imgs.slider_indicator,
|
||||||
self.imgs.slider,
|
self.imgs.slider,
|
||||||
@ -306,9 +307,44 @@ impl<'a> Widget for Video<'a> {
|
|||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.set(state.ids.vd_value, ui);
|
.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
|
// Max FPS
|
||||||
Text::new(self.localized_strings.get("hud.settings.maximum_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_size(self.fonts.cyri.scale(14))
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
@ -343,7 +379,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
|
|
||||||
// Max Background FPS
|
// Max Background FPS
|
||||||
Text::new(self.localized_strings.get("hud.settings.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)
|
.right_from(state.ids.max_fps_value, 30.0)
|
||||||
.font_size(self.fonts.cyri.scale(14))
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
@ -391,7 +427,7 @@ impl<'a> Widget for Video<'a> {
|
|||||||
|
|
||||||
// Present Mode
|
// Present Mode
|
||||||
Text::new(self.localized_strings.get("hud.settings.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)
|
.right_from(state.ids.max_background_fps_value, 30.0)
|
||||||
.font_size(self.fonts.cyri.scale(14))
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
|
@ -26,6 +26,7 @@ pub use self::{
|
|||||||
Locals as FigureLocals,
|
Locals as FigureLocals,
|
||||||
},
|
},
|
||||||
fluid::Vertex as FluidVertex,
|
fluid::Vertex as FluidVertex,
|
||||||
|
lod_object::{Instance as LodObjectInstance, Vertex as LodObjectVertex},
|
||||||
lod_terrain::{LodData, Vertex as LodTerrainVertex},
|
lod_terrain::{LodData, Vertex as LodTerrainVertex},
|
||||||
particle::{Instance as ParticleInstance, Vertex as ParticleVertex},
|
particle::{Instance as ParticleInstance, Vertex as ParticleVertex},
|
||||||
postprocess::Locals as PostProcessLocals,
|
postprocess::Locals as PostProcessLocals,
|
||||||
@ -35,10 +36,6 @@ pub use self::{
|
|||||||
Instance as SpriteInstance, SpriteGlobalsBindGroup, SpriteVerts,
|
Instance as SpriteInstance, SpriteGlobalsBindGroup, SpriteVerts,
|
||||||
Vertex as SpriteVertex, VERT_PAGE_SIZE as SPRITE_VERT_PAGE_SIZE,
|
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},
|
terrain::{Locals as TerrainLocals, TerrainLayout, Vertex as TerrainVertex},
|
||||||
trail::Vertex as TrailVertex,
|
trail::Vertex as TrailVertex,
|
||||||
ui::{
|
ui::{
|
||||||
|
@ -37,11 +37,12 @@ impl Vertex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// impl Default for 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 {
|
impl VertexTrait for Vertex {
|
||||||
const QUADS_INDEX: Option<wgpu::IndexFormat> = None;//Some(wgpu::IndexFormat::Uint16);
|
const QUADS_INDEX: Option<wgpu::IndexFormat> = None;
|
||||||
|
//Some(wgpu::IndexFormat::Uint16);
|
||||||
const STRIDE: wgpu::BufferAddress = mem::size_of::<Self>() as wgpu::BufferAddress;
|
const STRIDE: wgpu::BufferAddress = mem::size_of::<Self>() as wgpu::BufferAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,10 +54,7 @@ pub struct Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
pub fn new(
|
pub fn new(inst_pos: Vec3<f32>, flags: common::lod::Flags) -> Self {
|
||||||
inst_pos: Vec3<f32>,
|
|
||||||
flags: common::lod::Flags,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
inst_pos: inst_pos.into_array(),
|
inst_pos: inst_pos.into_array(),
|
||||||
flags: flags.bits() as u32,
|
flags: flags.bits() as u32,
|
||||||
@ -77,8 +75,8 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// impl Default for 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?
|
// TODO: ColLightsWrapper instead?
|
||||||
pub struct Locals;
|
pub struct Locals;
|
||||||
@ -100,10 +98,7 @@ impl LodObjectPipeline {
|
|||||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
label: Some("LoD object pipeline layout"),
|
label: Some("LoD object pipeline layout"),
|
||||||
push_constant_ranges: &[],
|
push_constant_ranges: &[],
|
||||||
bind_group_layouts: &[
|
bind_group_layouts: &[&global_layout.globals, &global_layout.shadow_textures],
|
||||||
&global_layout.globals,
|
|
||||||
&global_layout.shadow_textures,
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let samples = match aa_mode {
|
let samples = match aa_mode {
|
||||||
|
@ -21,7 +21,7 @@ use super::{
|
|||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
model::{DynamicModel, Model},
|
model::{DynamicModel, Model},
|
||||||
pipelines::{
|
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,
|
GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup,
|
||||||
},
|
},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use super::{
|
use super::{
|
||||||
super::{
|
super::{
|
||||||
pipelines::{
|
pipelines::{
|
||||||
debug, figure, lod_terrain, shadow, sprite, lod_object, terrain, ui, ColLights, GlobalModel,
|
debug, figure, lod_object, lod_terrain, shadow, sprite, terrain, ui, ColLights,
|
||||||
GlobalsBindGroup,
|
GlobalModel, GlobalsBindGroup,
|
||||||
},
|
},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
},
|
},
|
||||||
|
@ -4,8 +4,9 @@ use super::{
|
|||||||
instances::Instances,
|
instances::Instances,
|
||||||
model::{DynamicModel, Model, SubModel},
|
model::{DynamicModel, Model, SubModel},
|
||||||
pipelines::{
|
pipelines::{
|
||||||
blit, bloom, clouds, debug, figure, fluid, lod_terrain, particle, shadow, skybox,
|
blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle, shadow,
|
||||||
sprite, lod_object, terrain, trail, ui, ColLights, GlobalsBindGroup, ShadowTexturesBindGroup,
|
skybox, sprite, terrain, trail, ui, ColLights, GlobalsBindGroup,
|
||||||
|
ShadowTexturesBindGroup,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Renderer, ShadowMap, ShadowMapRenderer,
|
Renderer, ShadowMap, ShadowMapRenderer,
|
||||||
@ -764,9 +765,7 @@ impl<'pass> FirstPassDrawer<'pass> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_lod_objects<'data: 'pass>(
|
pub fn draw_lod_objects<'data: 'pass>(&mut self) -> LodObjectDrawer<'_, 'pass> {
|
||||||
&mut self,
|
|
||||||
) -> LodObjectDrawer<'_, 'pass> {
|
|
||||||
let mut render_pass = self.render_pass.scope("lod objects", self.borrow.device);
|
let mut render_pass = self.render_pass.scope("lod objects", self.borrow.device);
|
||||||
|
|
||||||
render_pass.set_pipeline(&self.pipelines.lod_object.pipeline);
|
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(0, model.buf().slice(..));
|
||||||
self.render_pass
|
self.render_pass
|
||||||
.set_vertex_buffer(1, instances.buf().slice(..));
|
.set_vertex_buffer(1, instances.buf().slice(..));
|
||||||
self.render_pass.draw(
|
self.render_pass
|
||||||
0..model.len() as u32,
|
.draw(0..model.len() as u32, 0..instances.count() as u32);
|
||||||
0..instances.count() as u32,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use super::{
|
use super::{
|
||||||
super::{
|
super::{
|
||||||
pipelines::{
|
pipelines::{
|
||||||
blit, bloom, clouds, debug, figure, fluid, lod_terrain, particle, postprocess, shadow,
|
blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle,
|
||||||
skybox, sprite, lod_object, terrain, trail, ui,
|
postprocess, shadow, skybox, sprite, terrain, trail, ui,
|
||||||
},
|
},
|
||||||
AaMode, BloomMode, CloudMode, FluidMode, LightingMode, PipelineModes, RenderError,
|
AaMode, BloomMode, CloudMode, FluidMode, LightingMode, PipelineModes, RenderError,
|
||||||
ShadowMode,
|
ShadowMode,
|
||||||
@ -763,7 +763,10 @@ fn create_ingame_and_shadow_pipelines(
|
|||||||
((debug, (skybox, figure)), (terrain, (fluid, bloom))),
|
((debug, (skybox, figure)), (terrain, (fluid, bloom))),
|
||||||
((sprite, particle), (lod_terrain, (clouds, trail))),
|
((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(|| pool.join(j1, j2), || pool.join(j3, j4)),
|
|| pool.join(|| pool.join(j1, j2), || pool.join(j3, j4)),
|
||||||
|| pool.join(|| pool.join(j5, j6), j7),
|
|| pool.join(|| pool.join(j5, j6), j7),
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
render::{
|
render::{
|
||||||
pipelines::lod_terrain::{LodData, Vertex},
|
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,
|
scene::GlobalModel,
|
||||||
settings::Settings,
|
settings::Settings,
|
||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use common::{
|
use common::{
|
||||||
assets::{ObjAsset, AssetExt},
|
assets::{AssetExt, ObjAsset},
|
||||||
|
lod,
|
||||||
spiral::Spiral2d,
|
spiral::Spiral2d,
|
||||||
util::srgba_to_linear,
|
util::srgba_to_linear,
|
||||||
lod,
|
|
||||||
};
|
};
|
||||||
|
use hashbrown::HashMap;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
pub struct Lod {
|
pub struct Lod {
|
||||||
@ -31,11 +32,7 @@ pub fn water_color() -> Rgba<f32> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Lod {
|
impl Lod {
|
||||||
pub fn new(
|
pub fn new(renderer: &mut Renderer, client: &Client, settings: &Settings) -> Self {
|
||||||
renderer: &mut Renderer,
|
|
||||||
client: &Client,
|
|
||||||
settings: &Settings,
|
|
||||||
) -> Self {
|
|
||||||
let data = LodData::new(
|
let data = LodData::new(
|
||||||
renderer,
|
renderer,
|
||||||
client.world_data().chunk_size().as_(),
|
client.world_data().chunk_size().as_(),
|
||||||
@ -49,8 +46,14 @@ impl Lod {
|
|||||||
Self {
|
Self {
|
||||||
zone_objects: HashMap::new(),
|
zone_objects: HashMap::new(),
|
||||||
object_data: [
|
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()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
@ -98,13 +101,19 @@ impl Lod {
|
|||||||
objects
|
objects
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(kind, instances)| {
|
.map(|(kind, instances)| {
|
||||||
(kind, renderer.create_instances(&instances).expect("Renderer error?!"))
|
(
|
||||||
|
kind,
|
||||||
|
renderer
|
||||||
|
.create_instances(&instances)
|
||||||
|
.expect("Renderer error?!"),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.collect()
|
.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>) {
|
pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>) {
|
||||||
@ -159,19 +168,20 @@ fn make_lod_object(
|
|||||||
) -> Model<LodObjectVertex> {
|
) -> Model<LodObjectVertex> {
|
||||||
let model = ObjAsset::load_expect(&format!("voxygen.lod.{}", name));
|
let model = ObjAsset::load_expect(&format!("voxygen.lod.{}", name));
|
||||||
let mesh = model
|
let mesh = model
|
||||||
.read().0
|
.read()
|
||||||
|
.0
|
||||||
.triangles()
|
.triangles()
|
||||||
.map(|vs| {
|
.map(|vs| {
|
||||||
let [a, b, c] = vs.map(|v| LodObjectVertex::new(
|
let [a, b, c] = vs.map(|v| {
|
||||||
|
LodObjectVertex::new(
|
||||||
v.position().into(),
|
v.position().into(),
|
||||||
v.normal().unwrap_or([0.0, 0.0, 1.0]).into(),
|
v.normal().unwrap_or([0.0, 0.0, 1.0]).into(),
|
||||||
Vec3::broadcast(1.0),
|
Vec3::broadcast(1.0),
|
||||||
//v.color().unwrap_or([1.0; 3]).into(),
|
//v.color().unwrap_or([1.0; 3]).into(),
|
||||||
));
|
)
|
||||||
|
});
|
||||||
Tri::new(a, b, c)
|
Tri::new(a, b, c)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
renderer
|
renderer.create_model(&mesh).expect("Mesh was empty!")
|
||||||
.create_model(&mesh)
|
|
||||||
.expect("Mesh was empty!")
|
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ pub enum Gameplay {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Graphics {
|
pub enum Graphics {
|
||||||
AdjustViewDistance(u32),
|
AdjustViewDistance(u32),
|
||||||
|
AdjustLodDistance(u32),
|
||||||
AdjustLodDetail(u32),
|
AdjustLodDetail(u32),
|
||||||
AdjustSpriteRenderDistance(u32),
|
AdjustSpriteRenderDistance(u32),
|
||||||
AdjustFigureLoDRenderDistance(u32),
|
AdjustFigureLoDRenderDistance(u32),
|
||||||
@ -344,6 +345,14 @@ impl SettingsChange {
|
|||||||
|
|
||||||
settings.graphics.view_distance = view_distance;
|
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) => {
|
Graphics::AdjustLodDetail(lod_detail) => {
|
||||||
session_state.scene.lod.set_detail(lod_detail);
|
session_state.scene.lod.set_detail(lod_detail);
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ impl fmt::Display for Fps {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct GraphicsSettings {
|
pub struct GraphicsSettings {
|
||||||
pub view_distance: u32,
|
pub view_distance: u32,
|
||||||
|
pub lod_distance: u32,
|
||||||
pub sprite_render_distance: u32,
|
pub sprite_render_distance: u32,
|
||||||
pub particles_enabled: bool,
|
pub particles_enabled: bool,
|
||||||
pub lossy_terrain_compression: bool,
|
pub lossy_terrain_compression: bool,
|
||||||
@ -51,6 +52,7 @@ impl Default for GraphicsSettings {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
view_distance: 10,
|
view_distance: 10,
|
||||||
|
lod_distance: 100,
|
||||||
sprite_render_distance: 100,
|
sprite_render_distance: 100,
|
||||||
particles_enabled: true,
|
particles_enabled: true,
|
||||||
lossy_terrain_compression: false,
|
lossy_terrain_compression: false,
|
||||||
|
@ -3,8 +3,7 @@ use crate::{
|
|||||||
block::block_from_structure,
|
block::block_from_structure,
|
||||||
column::ColumnGen,
|
column::ColumnGen,
|
||||||
util::{gen_cache::StructureGenCache, RandomPerm, Sampler, UnitChooser},
|
util::{gen_cache::StructureGenCache, RandomPerm, Sampler, UnitChooser},
|
||||||
Canvas,
|
Canvas, ColumnSample,
|
||||||
ColumnSample,
|
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
assets::AssetHandle,
|
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.water_dist.map(|d| d < 8.0).unwrap_or(false)
|
||||||
|| col.path.map(|(d, _, _, _)| d < 12.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 {
|
if ((seed.wrapping_mul(13)) & 0xFF) as f32 / 256.0 > col.tree_density {
|
||||||
|
@ -51,12 +51,12 @@ use common::{
|
|||||||
assets,
|
assets,
|
||||||
calendar::Calendar,
|
calendar::Calendar,
|
||||||
generation::{ChunkSupplement, EntityInfo},
|
generation::{ChunkSupplement, EntityInfo},
|
||||||
|
lod,
|
||||||
resources::TimeOfDay,
|
resources::TimeOfDay,
|
||||||
terrain::{
|
terrain::{
|
||||||
Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize, TerrainGrid,
|
Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize, TerrainGrid,
|
||||||
},
|
},
|
||||||
vol::{ReadVol, RectVolSize, WriteVol},
|
vol::{ReadVol, RectVolSize, WriteVol},
|
||||||
lod,
|
|
||||||
};
|
};
|
||||||
use common_net::msg::{world_msg, WorldMapMsg};
|
use common_net::msg::{world_msg, WorldMapMsg};
|
||||||
use rand::{prelude::*, Rng};
|
use rand::{prelude::*, Rng};
|
||||||
@ -467,45 +467,51 @@ impl World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Zone coordinates
|
// Zone coordinates
|
||||||
pub fn get_lod_zone(
|
pub fn get_lod_zone(&self, pos: Vec2<i32>, index: IndexRef) -> lod::Zone {
|
||||||
&self,
|
|
||||||
pos: Vec2<i32>,
|
|
||||||
index: IndexRef,
|
|
||||||
) -> lod::Zone {
|
|
||||||
let min_wpos = pos.map(lod::to_wpos);
|
let min_wpos = pos.map(lod::to_wpos);
|
||||||
let max_wpos = (pos + 1).map(lod::to_wpos);
|
let max_wpos = (pos + 1).map(lod::to_wpos);
|
||||||
|
|
||||||
let mut objects = Vec::new();
|
let mut objects = Vec::new();
|
||||||
|
|
||||||
objects.append(&mut self.sim()
|
objects.append(
|
||||||
|
&mut self
|
||||||
|
.sim()
|
||||||
.get_area_trees(min_wpos, max_wpos)
|
.get_area_trees(min_wpos, max_wpos)
|
||||||
.filter_map(|attr| {
|
.filter_map(|attr| {
|
||||||
ColumnGen::new(self.sim()).get((attr.pos, index, self.sim().calendar.as_ref()))
|
ColumnGen::new(self.sim())
|
||||||
|
.get((attr.pos, index, self.sim().calendar.as_ref()))
|
||||||
.filter(|col| layer::tree::tree_valid_at(col, attr.seed))
|
.filter(|col| layer::tree::tree_valid_at(col, attr.seed))
|
||||||
.zip(Some(attr))
|
.zip(Some(attr))
|
||||||
})
|
})
|
||||||
.filter_map(|(col, tree)| Some(lod::Object {
|
.filter_map(|(col, tree)| {
|
||||||
|
Some(lod::Object {
|
||||||
kind: match tree.forest_kind {
|
kind: match tree.forest_kind {
|
||||||
all::ForestKind::Oak => lod::ObjectKind::Oak,
|
all::ForestKind::Oak => lod::ObjectKind::Oak,
|
||||||
all::ForestKind::Pine
|
all::ForestKind::Pine | all::ForestKind::Frostpine => {
|
||||||
| all::ForestKind::Frostpine=> lod::ObjectKind::Pine,
|
lod::ObjectKind::Pine
|
||||||
|
},
|
||||||
_ => lod::ObjectKind::Oak,
|
_ => lod::ObjectKind::Oak,
|
||||||
},
|
},
|
||||||
pos: {
|
pos: {
|
||||||
let rpos = tree.pos - min_wpos;
|
let rpos = tree.pos - min_wpos;
|
||||||
if rpos.is_any_negative() {
|
if rpos.is_any_negative() {
|
||||||
return None
|
return None;
|
||||||
} else {
|
} else {
|
||||||
rpos
|
rpos.map(|e| e as u16).with_z(
|
||||||
.map(|e| e as u16)
|
self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16,
|
||||||
.with_z(self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
flags: lod::Flags::empty()
|
flags: lod::Flags::empty()
|
||||||
| if col.snow_cover { lod::Flags::SNOW_COVERED } else { lod::Flags::empty() }
|
| if col.snow_cover {
|
||||||
,
|
lod::Flags::SNOW_COVERED
|
||||||
}))
|
} else {
|
||||||
.collect());
|
lod::Flags::empty()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
|
||||||
lod::Zone { objects }
|
lod::Zone { objects }
|
||||||
}
|
}
|
||||||
|
@ -2150,7 +2150,11 @@ impl WorldSim {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_area_trees(&self, wpos_min: Vec2<i32>, wpos_max: Vec2<i32>) -> impl ParallelIterator<Item = TreeAttr> + '_ {
|
pub fn get_area_trees(
|
||||||
|
&self,
|
||||||
|
wpos_min: Vec2<i32>,
|
||||||
|
wpos_max: Vec2<i32>,
|
||||||
|
) -> impl ParallelIterator<Item = TreeAttr> + '_ {
|
||||||
self.gen_ctx
|
self.gen_ctx
|
||||||
.structure_gen
|
.structure_gen
|
||||||
.par_iter(wpos_min, wpos_max)
|
.par_iter(wpos_min, wpos_max)
|
||||||
|
@ -102,9 +102,7 @@ impl StructureGen2d {
|
|||||||
let x_field = self.x_field;
|
let x_field = self.x_field;
|
||||||
let y_field = self.y_field;
|
let y_field = self.y_field;
|
||||||
let seed_field = self.seed_field;
|
let seed_field = self.seed_field;
|
||||||
(0..len)
|
(0..len).into_par_iter().map(move |xy| {
|
||||||
.into_par_iter()
|
|
||||||
.map(move |xy| {
|
|
||||||
let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32);
|
let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32);
|
||||||
Self::index_to_sample_internal(
|
Self::index_to_sample_internal(
|
||||||
freq,
|
freq,
|
||||||
|
Loading…
Reference in New Issue
Block a user