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.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",
|
||||
|
@ -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<u32>,
|
||||
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<Vec2<i32>, lod::Zone> {
|
||||
&self.lod_zones
|
||||
}
|
||||
pub fn lod_zones(&self) -> &HashMap<Vec2<i32>, 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(())
|
||||
|
@ -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};
|
||||
|
@ -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<Object>,
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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.
|
||||
|
@ -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(),
|
||||
|
@ -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},
|
||||
|
@ -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)
|
||||
|
@ -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::{
|
||||
|
@ -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<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;
|
||||
}
|
||||
|
||||
@ -53,10 +54,7 @@ pub struct Instance {
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub fn new(
|
||||
inst_pos: Vec3<f32>,
|
||||
flags: common::lod::Flags,
|
||||
) -> Self {
|
||||
pub fn new(inst_pos: Vec3<f32>, 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 {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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<f32> {
|
||||
}
|
||||
|
||||
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<LodObjectVertex> {
|
||||
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!")
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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<i32>,
|
||||
index: IndexRef,
|
||||
) -> lod::Zone {
|
||||
pub fn get_lod_zone(&self, pos: Vec2<i32>, 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 }
|
||||
}
|
||||
|
@ -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
|
||||
.structure_gen
|
||||
.par_iter(wpos_min, wpos_max)
|
||||
|
@ -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,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user