From 43d935a150453aa9debb2ea8abe81d349d2d6550 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 14 Jan 2024 21:36:02 +0000 Subject: [PATCH 1/7] Render render LoD terrain on char select, remove old backdrop figure --- assets/voxygen/voxel/fixture/selection_bg.vox | 3 - voxygen/src/menu/char_selection/mod.rs | 19 ++- voxygen/src/render/renderer.rs | 3 +- voxygen/src/scene/simple.rs | 128 ++++++------------ 4 files changed, 57 insertions(+), 96 deletions(-) delete mode 100644 assets/voxygen/voxel/fixture/selection_bg.vox diff --git a/assets/voxygen/voxel/fixture/selection_bg.vox b/assets/voxygen/voxel/fixture/selection_bg.vox deleted file mode 100644 index dfe8546cfd..0000000000 --- a/assets/voxygen/voxel/fixture/selection_bg.vox +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:88283bacea75c38947c0816d7308df198e5771d1853767398af3466d0fb1b106 -size 595784 diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 8fb6707683..7073a773ed 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -27,8 +27,8 @@ impl CharSelectionState { pub fn new(global_state: &mut GlobalState, client: Rc>) -> Self { let scene = Scene::new( global_state.window.renderer_mut(), - Some("fixture.selection_bg"), &client.borrow(), + &global_state.settings, ); let char_selection_ui = CharSelectionUi::new(global_state, &client.borrow()); @@ -199,8 +199,12 @@ impl PlayState for CharSelectionState { as f32, }; - self.scene - .maintain(global_state.window.renderer_mut(), scene_data, loadout); + self.scene.maintain( + global_state.window.renderer_mut(), + scene_data, + loadout, + &client, + ); } // Tick the client (currently only to keep the connection alive). @@ -280,8 +284,13 @@ impl PlayState for CharSelectionState { Self::get_humanoid_body_inventory(&self.char_selection_ui, &client); if let Some(mut first_pass) = drawer.first_pass() { - self.scene - .render(&mut first_pass, client.get_tick(), humanoid_body, loadout); + self.scene.render( + &mut first_pass, + client.get_tick(), + humanoid_body, + loadout, + &client, + ); } if let Some(mut volumetric_pass) = drawer.volumetric_pass() { diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index c91ab2b3a7..7cec6c479f 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -1570,9 +1570,10 @@ pub struct AltIndices { /// The mode with which culling based on the camera position relative to the /// terrain is performed. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Default)] pub enum CullingMode { /// We need to render all elements of the given structure + #[default] None, /// We only need to render surface and shallow (i.e: in the overlapping /// region) elements of the structure diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 8d523a3e4d..568c82b9b3 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -2,7 +2,7 @@ use crate::{ mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_figure}, render::{ create_skybox_mesh, pipelines::FigureSpriteAtlasData, BoneMeshes, Consts, FigureModel, - FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, LodData, Mesh, Model, + FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, Mesh, Model, PointLightMatrix, RainOcclusionLocals, Renderer, Shadow, ShadowLocals, SkyboxVertex, TerrainVertex, }, @@ -12,8 +12,10 @@ use crate::{ load_mesh, FigureAtlas, FigureModelCache, FigureModelEntry, FigureState, FigureUpdateCommonParameters, }, + CloudsLocals, Lod, PostProcessLocals, }, window::{Event, PressState}, + Settings, }; use anim::{ character::{CharacterSkeleton, IdleAnimation, SkeletonAttr}, @@ -29,7 +31,7 @@ use common::{ }, figure::Segment, slowjob::SlowJobPool, - terrain::BlockKind, + terrain::{BlockKind, CoordinateConversions}, vol::{BaseVol, ReadVol}, }; use vek::*; @@ -68,17 +70,16 @@ pub struct Scene { camera: Camera, skybox: Skybox, - lod: LodData, + lod: Lod, map_bounds: Vec2, figure_atlas: FigureAtlas, - backdrop: Option<(FigureModelEntry<1>, FigureState)>, figure_model_cache: FigureModelCache, figure_state: Option>, //turning_camera: bool, turning_character: bool, - char_ori: f32, + char_pos: Vec3, } pub struct SceneData<'a> { @@ -95,8 +96,8 @@ pub struct SceneData<'a> { } impl Scene { - pub fn new(renderer: &mut Renderer, backdrop: Option<&str>, client: &Client) -> Self { - let start_angle = 90.0f32.to_radians(); + pub fn new(renderer: &mut Renderer, client: &Client, settings: &Settings) -> Self { + let start_angle = -90.0f32.to_radians(); let resolution = renderer.resolution().map(|e| e as f32); let map_bounds = Vec2::new( @@ -105,9 +106,8 @@ impl Scene { ); let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson); - camera.set_focus_pos(Vec3::unit_z() * 1.5); camera.set_distance(3.4); - camera.set_orientation(Vec3::new(start_angle, 0.0, 0.0)); + camera.set_orientation(Vec3::new(start_angle, 0.1, 0.0)); let mut figure_atlas = FigureAtlas::new(renderer); @@ -120,9 +120,18 @@ impl Scene { .create_rain_occlusion_bound_locals(&[RainOcclusionLocals::default()]), point_light_matrices: Box::new([PointLightMatrix::default(); 126]), }; - let lod = LodData::dummy(renderer); + let lod = Lod::new(renderer, client, settings); - let globals_bind_group = renderer.bind_globals(&data, &lod); + let globals_bind_group = renderer.bind_globals(&data, lod.get_data()); + + let world = client.world_data(); + let char_chunk = world.chunk_size().map(|e| e as i32 / 2); + let char_pos = char_chunk.cpos_to_wpos().map(|e| e as f32).with_z( + world + .lod_alt + .get(char_chunk) + .map_or(0.0, |z| *z as f32 + 100.0), + ); Self { data, @@ -135,66 +144,13 @@ impl Scene { figure_model_cache: FigureModelCache::new(), figure_state: None, - - backdrop: backdrop.map(|specifier| { - let mut state = FigureState::new(renderer, FixtureSkeleton, ()); - let mut greedy = FigureModel::make_greedy(); - let mut opaque_mesh = Mesh::new(); - let (segment, offset) = load_mesh(specifier, Vec3::new(-55.0, -49.5, -2.0)); - let (_opaque_mesh, bounds) = - generate_mesh(&mut greedy, &mut opaque_mesh, segment, offset, 0); - // NOTE: Since MagicaVoxel sizes are limited to 256 × 256 × 256, and there are - // at most 3 meshed vertices per unique vertex, we know the - // total size is bounded by 2^24 * 3 * 1.5 which is bounded by - // 2^27, which fits in a u32. - let range = 0..opaque_mesh.vertices().len() as u32; - let (atlas_texture_data, atlas_size) = greedy.finalize(); - let model = figure_atlas.create_figure( - renderer, - atlas_texture_data, - atlas_size, - (opaque_mesh, bounds), - [range], - ); - let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; - let common_params = FigureUpdateCommonParameters { - entity: None, - pos: anim::vek::Vec3::zero(), - ori: anim::vek::Quaternion::rotation_from_to_3d( - anim::vek::Vec3::unit_y(), - anim::vek::Vec3::new(start_angle.sin(), -start_angle.cos(), 0.0), - ), - scale: 1.0, - mount_transform_pos: None, - body: None, - tools: (None, None), - col: Rgba::broadcast(1.0), - dt: 15.0, // Want to get there immediately. - _lpindex: 0, - _visible: true, - is_player: false, - _camera: &camera, - terrain: None, - ground_vel: Vec3::zero(), - }; - state.update( - renderer, - None, - &mut buf, - &common_params, - 1.0, - Some(&model), - (), - ); - (model, state) - }), figure_atlas, camera, //turning_camera: false, turning_character: false, - char_ori: -start_angle, + char_pos, } } @@ -224,11 +180,8 @@ impl Scene { true }, Event::CursorMove(delta) => { - /*if self.turning_camera { - self.camera.rotate_by(Vec3::new(delta.x * 0.01, 0.0, 0.0)) - }*/ if self.turning_character { - self.char_ori += delta.x * 0.01; + self.camera.rotate_by(delta.with_z(0.0) * 0.01); } true }, @@ -242,7 +195,10 @@ impl Scene { renderer: &mut Renderer, scene_data: SceneData, inventory: Option<&Inventory>, + client: &Client, ) { + self.camera + .force_focus_pos(self.char_pos + Vec3::unit_z() * 1.5); self.camera.update( scene_data.time, /* 1.0 / 60.0 */ scene_data.delta_time, @@ -254,13 +210,18 @@ impl Scene { view_mat, proj_mat, cam_pos, + proj_mat_inv, + view_mat_inv, .. } = self.camera.dependents(); - const VD: f32 = 115.0; // View Distance + const VD: f32 = 0.0; // View Distance const TIME: f64 = 8.6 * 60.0 * 60.0; - const SHADOW_NEAR: f32 = 1.0; - const SHADOW_FAR: f32 = 25.0; + const SHADOW_NEAR: f32 = 0.25; + const SHADOW_FAR: f32 = 128.0; + + self.lod + .maintain(renderer, client, self.camera.get_focus_pos(), &self.camera); renderer.update_consts(&mut self.data.globals, &[Globals::new( view_mat, @@ -268,7 +229,7 @@ impl Scene { cam_pos, self.camera.get_focus_pos(), VD, - self.lod.tgt_detail as f32, + self.lod.get_data().tgt_detail as f32, self.map_bounds, TIME, scene_data.time, @@ -288,6 +249,8 @@ impl Scene { self.camera.get_mode(), 250.0, )]); + renderer.update_clouds_locals(CloudsLocals::new(proj_mat_inv, view_mat_inv)); + renderer.update_postprocess_locals(PostProcessLocals::new(proj_mat_inv, view_mat_inv)); self.figure_model_cache .clean(&mut self.figure_atlas, scene_data.tick); @@ -348,11 +311,8 @@ impl Scene { let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; let common_params = FigureUpdateCommonParameters { entity: None, - pos: anim::vek::Vec3::zero(), - ori: anim::vek::Quaternion::rotation_from_to_3d( - anim::vek::Vec3::unit_y(), - anim::vek::Vec3::new(self.char_ori.sin(), -self.char_ori.cos(), 0.0), - ), + pos: self.char_pos.into(), + ori: anim::vek::Quaternion::identity().rotated_z(std::f32::consts::PI * -0.5), scale: 1.0, mount_transform_pos: None, body: None, @@ -379,6 +339,7 @@ impl Scene { tick: u64, body: Option, inventory: Option<&Inventory>, + client: &Client, ) { let mut figure_drawer = drawer.draw_figures(); if let Some(body) = body { @@ -403,17 +364,10 @@ impl Scene { } } - if let Some((model, state)) = &self.backdrop { - if let Some(lod) = model.lod_model(0) { - figure_drawer.draw( - lod, - state.bound(), - self.figure_atlas.texture(ModelEntryRef::Figure(model)), - ); - } - } drop(figure_drawer); + self.lod.render(drawer, Default::default()); + drawer.draw_skybox(&self.skybox.model); } } From 5d4133eea52c04af94875c920d046dc116987608 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 14 Jan 2024 21:38:48 +0000 Subject: [PATCH 2/7] Updated changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f495ea27a..c2cffeea45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Linearize light colors on the CPU rather than in shaders on the GPU - You can no longer stack self buffs - Renamed "Burning Potion" to "Potion of Combustion" +- Render LoD terrain on the character selection screen ### Removed - Medium and large potions from all loot tables @@ -95,7 +96,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed french translation "Énergie Consommée" -> "Regain d'Énergie" - Fixed Perforate icon not displaying - Make cave entrances easier to follow -- Renamed Twiggy Shoulders to match the Twig Armor set +- Renamed Twiggy Shoulders to match the Twig Armor set - No longer stack buffs of the same kind with equal attributes, this could lead to a DoS if ie. an entity stayed long enough in lava. ## [0.15.0] - 2023-07-01 From 5bc60f2436783b32ce9f1b929094efbf2deb98a3 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 14 Jan 2024 22:27:34 +0000 Subject: [PATCH 3/7] Add LoD zone data to char select screen --- client/src/lib.rs | 16 +++- common/net/src/msg/client.rs | 5 +- common/net/src/msg/server.rs | 4 +- server/src/client.rs | 2 +- server/src/sys/msg/terrain.rs | 110 +++++++++++++------------ voxygen/src/menu/char_selection/mod.rs | 2 +- voxygen/src/scene/simple.rs | 4 +- 7 files changed, 78 insertions(+), 65 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 6977133a8f..1ea5995b40 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -242,6 +242,7 @@ pub struct Client { available_recipes: HashMap>, lod_zones: HashMap, lod::Zone>, lod_last_requested: Option, + lod_pos_fallback: Option>, force_update_counter: u64, max_group_size: u32, @@ -753,6 +754,7 @@ impl Client { lod_zones: HashMap::new(), lod_last_requested: None, + lod_pos_fallback: None, force_update_counter: 0, @@ -890,7 +892,7 @@ impl Client { | ClientGeneral::DeleteCharacter(_) | ClientGeneral::Character(_, _) | ClientGeneral::Spectate(_) => &mut self.character_screen_stream, - //Only in game + // Only in game ClientGeneral::ControllerInputs(_) | ClientGeneral::ControlEvent(_) | ClientGeneral::ControlAction(_) @@ -911,7 +913,7 @@ impl Client { } &mut self.in_game_stream }, - //Only in game, terrain + // Terrain ClientGeneral::TerrainChunkRequest { .. } | ClientGeneral::LodZoneRequest { .. } => { #[cfg(feature = "tracy")] @@ -920,7 +922,7 @@ impl Client { } &mut self.terrain_stream }, - //Always possible + // Always possible ClientGeneral::ChatMsg(_) | ClientGeneral::Command(_, _) | ClientGeneral::Terminate => &mut self.general_stream, @@ -1196,6 +1198,10 @@ impl Client { pub fn lod_zones(&self) -> &HashMap, lod::Zone> { &self.lod_zones } + /// Set the fallback position used for loading LoD zones when the client + /// entity does not have a position. + pub fn set_lod_pos_fallback(&mut self, pos: Vec2) { self.lod_pos_fallback = Some(pos); } + /// Returns whether the specified recipe can be crafted and the sprite, if /// any, that is required to do so. pub fn can_craft_recipe(&self, recipe: &str, amount: u32) -> (bool, Option) { @@ -2088,9 +2094,11 @@ impl Client { let now = Instant::now(); self.pending_chunks .retain(|_, created| now.duration_since(*created) < Duration::from_secs(3)); + } + if let Some(lod_pos) = pos.map(|p| p.0.xy()).or(self.lod_pos_fallback) { // Manage LoD zones - let lod_zone = pos.0.xy().map(|e| lod::from_wpos(e as i32)); + let lod_zone = lod_pos.map(|e| lod::from_wpos(e as i32)); // Request LoD zones that are in range if self diff --git a/common/net/src/msg/client.rs b/common/net/src/msg/client.rs index f752db223d..be4d2f5e91 100644 --- a/common/net/src/msg/client.rs +++ b/common/net/src/msg/client.rs @@ -128,7 +128,6 @@ impl ClientMsg { | ClientGeneral::ExitInGame | ClientGeneral::PlayerPhysics { .. } | ClientGeneral::TerrainChunkRequest { .. } - | ClientGeneral::LodZoneRequest { .. } | ClientGeneral::UnlockSkill(_) | ClientGeneral::RequestSiteInfo(_) | ClientGeneral::RequestPlayerPhysics { .. } @@ -140,7 +139,9 @@ impl ClientMsg { //Always possible ClientGeneral::ChatMsg(_) | ClientGeneral::Command(_, _) - | ClientGeneral::Terminate => true, + | ClientGeneral::Terminate + // LodZoneRequest is required by the char select screen + | ClientGeneral::LodZoneRequest { .. } => true, } }, ClientMsg::Ping(_) => true, diff --git a/common/net/src/msg/server.rs b/common/net/src/msg/server.rs index d626017eaf..9ad6c8f5b4 100644 --- a/common/net/src/msg/server.rs +++ b/common/net/src/msg/server.rs @@ -324,7 +324,6 @@ impl ServerMsg { | ServerGeneral::InventoryUpdate(_, _) | ServerGeneral::GroupInventoryUpdate(_, _, _) | ServerGeneral::TerrainChunkUpdate { .. } - | ServerGeneral::LodZoneUpdate { .. } | ServerGeneral::TerrainBlockUpdates(_) | ServerGeneral::SetViewDistance(_) | ServerGeneral::Outcomes(_) @@ -348,7 +347,8 @@ impl ServerMsg { | ServerGeneral::CreateEntity(_) | ServerGeneral::DeleteEntity(_) | ServerGeneral::Disconnect(_) - | ServerGeneral::Notification(_) => true, + | ServerGeneral::Notification(_) + | ServerGeneral::LodZoneUpdate { .. } => true, } }, ServerMsg::Ping(_) => true, diff --git a/server/src/client.rs b/server/src/client.rs index d2a76bf44a..47ea174ffa 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -192,7 +192,7 @@ impl Client { | ServerGeneral::SpectatePosition(_) => { PreparedMsg::new(2, &g, &self.in_game_stream_params) }, - //In-game related, terrain + // Terrain ServerGeneral::TerrainChunkUpdate { .. } | ServerGeneral::LodZoneUpdate { .. } | ServerGeneral::TerrainBlockUpdates(_) => { diff --git a/server/src/sys/msg/terrain.rs b/server/src/sys/msg/terrain.rs index 6c81c837a5..46ecff6570 100644 --- a/server/src/sys/msg/terrain.rs +++ b/server/src/sys/msg/terrain.rs @@ -61,61 +61,63 @@ impl<'a> System<'a> for Sys { |(chunk_send_emitter, server_emitter), (entity, client, maybe_presence)| { let mut chunk_requests = Vec::new(); let _ = super::try_recv_all(client, 5, |client, msg| { - let presence = match maybe_presence { - Some(g) => g, - None => { - debug!(?entity, "client is not in_game, ignoring msg"); - trace!(?msg, "ignored msg content"); - if matches!(msg, ClientGeneral::TerrainChunkRequest { .. }) { - network_metrics.chunks_request_dropped.inc(); - } - return Ok(()); - }, - }; - match msg { - ClientGeneral::TerrainChunkRequest { key } => { - let in_vd = if let Some(pos) = positions.get(entity) { - pos.0.xy().map(|e| e as f64).distance_squared( - key.map(|e| e as f64 + 0.5) - * TerrainChunkSize::RECT_SIZE.map(|e| e as f64), - ) < ((presence.terrain_view_distance.current() as f64 - 1.0 - + 2.5 * 2.0_f64.sqrt()) - * TerrainChunkSize::RECT_SIZE.x as f64) - .powi(2) - } else { - true - }; - if in_vd { - if terrain.get_key_arc(key).is_some() { - network_metrics.chunks_served_from_memory.inc(); - chunk_send_emitter.emit(ChunkSendEntry { - chunk_key: key, - entity, - }); - } else { - network_metrics.chunks_generation_triggered.inc(); - chunk_requests.push(ChunkRequest { entity, key }); + // SPECIAL CASE: LOD zone requests can be sent by non-present players + if let ClientGeneral::LodZoneRequest { key } = &msg { + client.send(ServerGeneral::LodZoneUpdate { + key: *key, + zone: lod.zone(*key).clone(), + })?; + } else { + let presence = match maybe_presence { + Some(g) => g, + None => { + debug!(?entity, "client is not in_game, ignoring msg"); + trace!(?msg, "ignored msg content"); + if matches!(msg, ClientGeneral::TerrainChunkRequest { .. }) { + network_metrics.chunks_request_dropped.inc(); } - } else { - network_metrics.chunks_request_dropped.inc(); - } - }, - ClientGeneral::LodZoneRequest { key } => { - client.send(ServerGeneral::LodZoneUpdate { - key, - zone: lod.zone(key).clone(), - })?; - }, - _ => { - debug!( - "Kicking possibly misbehaving client due to invalud terrain \ - request" - ); - server_emitter.emit(ServerEvent::ClientDisconnect( - entity, - common::comp::DisconnectReason::NetworkError, - )); - }, + return Ok(()); + }, + }; + match msg { + ClientGeneral::TerrainChunkRequest { key } => { + let in_vd = if let Some(pos) = positions.get(entity) { + pos.0.xy().map(|e| e as f64).distance_squared( + key.map(|e| e as f64 + 0.5) + * TerrainChunkSize::RECT_SIZE.map(|e| e as f64), + ) < ((presence.terrain_view_distance.current() as f64 - 1.0 + + 2.5 * 2.0_f64.sqrt()) + * TerrainChunkSize::RECT_SIZE.x as f64) + .powi(2) + } else { + true + }; + if in_vd { + if terrain.get_key_arc(key).is_some() { + network_metrics.chunks_served_from_memory.inc(); + chunk_send_emitter.emit(ChunkSendEntry { + chunk_key: key, + entity, + }); + } else { + network_metrics.chunks_generation_triggered.inc(); + chunk_requests.push(ChunkRequest { entity, key }); + } + } else { + network_metrics.chunks_request_dropped.inc(); + } + }, + _ => { + debug!( + "Kicking possibly misbehaving client due to invalud terrain \ + request" + ); + server_emitter.emit(ServerEvent::ClientDisconnect( + entity, + common::comp::DisconnectReason::NetworkError, + )); + }, + } } Ok(()) }); diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 7073a773ed..b60bfed85f 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -27,7 +27,7 @@ impl CharSelectionState { pub fn new(global_state: &mut GlobalState, client: Rc>) -> Self { let scene = Scene::new( global_state.window.renderer_mut(), - &client.borrow(), + &mut client.borrow_mut(), &global_state.settings, ); let char_selection_ui = CharSelectionUi::new(global_state, &client.borrow()); diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 568c82b9b3..047a94d6a4 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -96,7 +96,7 @@ pub struct SceneData<'a> { } impl Scene { - pub fn new(renderer: &mut Renderer, client: &Client, settings: &Settings) -> Self { + pub fn new(renderer: &mut Renderer, client: &mut Client, settings: &Settings) -> Self { let start_angle = -90.0f32.to_radians(); let resolution = renderer.resolution().map(|e| e as f32); @@ -132,6 +132,8 @@ impl Scene { .get(char_chunk) .map_or(0.0, |z| *z as f32 + 100.0), ); + client.set_lod_pos_fallback(char_pos.xy()); + client.set_lod_distance(settings.graphics.lod_distance); Self { data, From 3420e7a227c11db4a12e0457cca15c261129c0b5 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 15 Jan 2024 19:06:01 +0000 Subject: [PATCH 4/7] Appease clippy --- voxygen/src/menu/char_selection/mod.rs | 9 ++---- voxygen/src/scene/simple.rs | 43 ++++++-------------------- 2 files changed, 11 insertions(+), 41 deletions(-) diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index b60bfed85f..0793bd7ff1 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -284,13 +284,8 @@ impl PlayState for CharSelectionState { Self::get_humanoid_body_inventory(&self.char_selection_ui, &client); if let Some(mut first_pass) = drawer.first_pass() { - self.scene.render( - &mut first_pass, - client.get_tick(), - humanoid_body, - loadout, - &client, - ); + self.scene + .render(&mut first_pass, client.get_tick(), humanoid_body, loadout); } if let Some(mut volumetric_pass) = drawer.volumetric_pass() { diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 047a94d6a4..825d00bd52 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -1,17 +1,11 @@ use crate::{ - mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_figure}, render::{ - create_skybox_mesh, pipelines::FigureSpriteAtlasData, BoneMeshes, Consts, FigureModel, - FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, Mesh, Model, - PointLightMatrix, RainOcclusionLocals, Renderer, Shadow, ShadowLocals, SkyboxVertex, - TerrainVertex, + create_skybox_mesh, Consts, FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, + Model, PointLightMatrix, RainOcclusionLocals, Renderer, Shadow, ShadowLocals, SkyboxVertex, }, scene::{ camera::{self, Camera, CameraMode}, - figure::{ - load_mesh, FigureAtlas, FigureModelCache, FigureModelEntry, FigureState, - FigureUpdateCommonParameters, - }, + figure::{FigureAtlas, FigureModelCache, FigureState, FigureUpdateCommonParameters}, CloudsLocals, Lod, PostProcessLocals, }, window::{Event, PressState}, @@ -19,7 +13,6 @@ use crate::{ }; use anim::{ character::{CharacterSkeleton, IdleAnimation, SkeletonAttr}, - fixture::FixtureSkeleton, Animation, }; use client::Client; @@ -29,7 +22,6 @@ use common::{ inventory::{slot::EquipSlot, Inventory}, item::ItemKind, }, - figure::Segment, slowjob::SlowJobPool, terrain::{BlockKind, CoordinateConversions}, vol::{BaseVol, ReadVol}, @@ -48,18 +40,6 @@ impl ReadVol for VoidVol { fn get(&self, _pos: Vec3) -> Result<&'_ Self::Vox, Self::Error> { Ok(&()) } } -fn generate_mesh( - greedy: &mut GreedyMesh<'_, FigureSpriteAtlasData>, - mesh: &mut Mesh, - segment: Segment, - offset: Vec3, - bone_idx: u8, -) -> BoneMeshes { - let (opaque, _, /* shadow */ _, bounds) = - generate_mesh_base_vol_figure(segment, (greedy, mesh, offset, Vec3::one(), bone_idx)); - (opaque /* , shadow */, bounds) -} - struct Skybox { model: Model, } @@ -77,8 +57,7 @@ pub struct Scene { figure_model_cache: FigureModelCache, figure_state: Option>, - //turning_camera: bool, - turning_character: bool, + turning_camera: bool, char_pos: Vec3, } @@ -109,7 +88,7 @@ impl Scene { camera.set_distance(3.4); camera.set_orientation(Vec3::new(start_angle, 0.1, 0.0)); - let mut figure_atlas = FigureAtlas::new(renderer); + let figure_atlas = FigureAtlas::new(renderer); let data = GlobalModel { globals: renderer.create_consts(&[Globals::default()]), @@ -150,8 +129,7 @@ impl Scene { camera, - //turning_camera: false, - turning_character: false, + turning_camera: false, char_pos, } } @@ -173,16 +151,14 @@ impl Scene { }, Event::MouseButton(button, state) => { if state == PressState::Pressed { - //self.turning_camera = button == MouseButton::Right; - self.turning_character = button == MouseButton::Left; + self.turning_camera = button == MouseButton::Left; } else { - //self.turning_camera = false; - self.turning_character = false; + self.turning_camera = false; } true }, Event::CursorMove(delta) => { - if self.turning_character { + if self.turning_camera { self.camera.rotate_by(delta.with_z(0.0) * 0.01); } true @@ -341,7 +317,6 @@ impl Scene { tick: u64, body: Option, inventory: Option<&Inventory>, - client: &Client, ) { let mut figure_drawer = drawer.draw_figures(); if let Some(body) = body { From d51b5c5bea78b6dced66bea8ba7b106be7b864c7 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 15 Jan 2024 22:35:42 +0000 Subject: [PATCH 5/7] Add airship to char select --- assets/voxygen/shaders/include/shadows.glsl | 4 + voxygen/src/lib.rs | 3 +- voxygen/src/menu/char_selection/mod.rs | 4 + voxygen/src/scene/camera.rs | 3 + voxygen/src/scene/figure/cache.rs | 9 +- voxygen/src/scene/figure/mod.rs | 4 +- voxygen/src/scene/mod.rs | 2 +- voxygen/src/scene/simple.rs | 204 ++++++++++++++------ voxygen/src/scene/terrain.rs | 41 ++-- 9 files changed, 189 insertions(+), 85 deletions(-) diff --git a/assets/voxygen/shaders/include/shadows.glsl b/assets/voxygen/shaders/include/shadows.glsl index 25018a00e1..4460c781ce 100644 --- a/assets/voxygen/shaders/include/shadows.glsl +++ b/assets/voxygen/shaders/include/shadows.glsl @@ -151,6 +151,10 @@ float ShadowCalculationPoint(uint lightIndex, vec3 fragToLight, vec3 fragNorm, / float ShadowCalculationDirected(in vec3 fragPos)//in vec4 /*light_pos[2]*/sun_pos, vec3 fragPos) { + // Don't try to calculate directed shadows if there are no directed light sources + // Applies, for example, in the char select menu + if (light_shadow_count.z < 1) { return 1.0; } + float bias = 0.000;//0.0005;//-0.0001;// 0.05 / (2.0 * view_distance.x); float diskRadius = 0.01; const vec3 sampleOffsetDirections[20] = vec3[] diff --git a/voxygen/src/lib.rs b/voxygen/src/lib.rs index 17ec046081..50873fc443 100644 --- a/voxygen/src/lib.rs +++ b/voxygen/src/lib.rs @@ -16,7 +16,8 @@ let_chains, generic_const_exprs, maybe_uninit_uninit_array, - maybe_uninit_array_assume_init + maybe_uninit_array_assume_init, + closure_lifetime_binder )] #![recursion_limit = "2048"] diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 0793bd7ff1..579a275a5c 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -25,10 +25,14 @@ pub struct CharSelectionState { impl CharSelectionState { /// Create a new `CharSelectionState`. pub fn new(global_state: &mut GlobalState, client: Rc>) -> Self { + let sprite_render_state = + (global_state.lazy_init)(global_state.window.renderer_mut()).state; + let scene = Scene::new( global_state.window.renderer_mut(), &mut client.borrow_mut(), &global_state.settings, + sprite_render_state, ); let char_selection_ui = CharSelectionUi::new(global_state, &client.borrow()); diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index 5b8b1850e6..f90bc04a54 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -677,6 +677,9 @@ impl Camera { /// Get the orientation of the camera. pub fn get_orientation(&self) -> Vec3 { self.ori } + /// Get the orientation that the camera is moving toward. + pub fn get_tgt_orientation(&self) -> Vec3 { self.tgt_ori } + /// Get the field of view of the camera in radians, taking into account /// fixation. pub fn get_effective_fov(&self) -> f32 { self.fov * self.fixate } diff --git a/voxygen/src/scene/figure/cache.rs b/voxygen/src/scene/figure/cache.rs index fea728fe2b..549e0c06af 100644 --- a/voxygen/src/scene/figure/cache.rs +++ b/voxygen/src/scene/figure/cache.rs @@ -13,8 +13,7 @@ use crate::{ }, scene::{ camera::CameraMode, - terrain::{get_sprite_instances, BlocksOfInterest, SPRITE_LOD_LEVELS}, - Terrain, + terrain::{get_sprite_instances, BlocksOfInterest, SpriteRenderState, SPRITE_LOD_LEVELS}, }, }; use anim::Skeleton; @@ -632,7 +631,7 @@ where extra: ::Extra, tick: u64, slow_jobs: &SlowJobPool, - terrain: &Terrain, + sprite_render_state: &SpriteRenderState, ) -> (TerrainModelEntryLod<'c>, &'c Skel::Attr) where for<'a> &'a Skel::Body: Into, @@ -695,8 +694,8 @@ where let key = v.key().clone(); let slot = Arc::new(atomic::AtomicCell::new(None)); let manifests = self.manifests.clone(); - let sprite_data = Arc::clone(&terrain.sprite_data); - let sprite_config = Arc::clone(&terrain.sprite_config); + let sprite_data = Arc::clone(&sprite_render_state.sprite_data); + let sprite_config = Arc::clone(&sprite_render_state.sprite_config); let slot_ = Arc::clone(&slot); slow_jobs.spawn("FIGURE_MESHING", move || { diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 3683843c6b..3510a147ee 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -6288,7 +6288,7 @@ impl FigureMgr { Arc::clone(vol), tick, &slow_jobs, - terrain, + &terrain.sprite_render_state, ); let state = self @@ -6315,7 +6315,7 @@ impl FigureMgr { (), tick, &slow_jobs, - terrain, + &terrain.sprite_render_state, ) } else { // No way to determine model (this is okay, we might just not have received diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index a6c1bd245d..167913f647 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -1430,7 +1430,7 @@ impl Scene { // Draws sprites let mut sprite_drawer = first_pass.draw_sprites( &self.terrain.sprite_globals, - &self.terrain.sprite_atlas_textures, + &self.terrain.sprite_render_state.sprite_atlas_textures, ); self.figure_mgr.render_sprites( &mut sprite_drawer, diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 825d00bd52..27caf3c38d 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -6,21 +6,20 @@ use crate::{ scene::{ camera::{self, Camera, CameraMode}, figure::{FigureAtlas, FigureModelCache, FigureState, FigureUpdateCommonParameters}, + terrain::SpriteRenderState, CloudsLocals, Lod, PostProcessLocals, }, window::{Event, PressState}, Settings, }; -use anim::{ - character::{CharacterSkeleton, IdleAnimation, SkeletonAttr}, - Animation, -}; +use anim::{character::CharacterSkeleton, ship::ShipSkeleton, Animation}; use client::Client; use common::{ comp::{ humanoid, inventory::{slot::EquipSlot, Inventory}, item::ItemKind, + ship, }, slowjob::SlowJobPool, terrain::{BlockKind, CoordinateConversions}, @@ -54,11 +53,17 @@ pub struct Scene { map_bounds: Vec2, figure_atlas: FigureAtlas, - figure_model_cache: FigureModelCache, - figure_state: Option>, + sprite_render_state: SpriteRenderState, turning_camera: bool, + char_pos: Vec3, + char_state: Option>, + char_model_cache: FigureModelCache, + + airship_pos: Vec3, + airship_state: Option>, + airship_model_cache: FigureModelCache, } pub struct SceneData<'a> { @@ -75,7 +80,12 @@ pub struct SceneData<'a> { } impl Scene { - pub fn new(renderer: &mut Renderer, client: &mut Client, settings: &Settings) -> Self { + pub fn new( + renderer: &mut Renderer, + client: &mut Client, + settings: &Settings, + sprite_render_state: SpriteRenderState, + ) -> Self { let start_angle = -90.0f32.to_radians(); let resolution = renderer.resolution().map(|e| e as f32); @@ -109,7 +119,7 @@ impl Scene { world .lod_alt .get(char_chunk) - .map_or(0.0, |z| *z as f32 + 100.0), + .map_or(0.0, |z| *z as f32 + 48.0), ); client.set_lod_pos_fallback(char_pos.xy()); client.set_lod_distance(settings.graphics.lod_distance); @@ -123,14 +133,19 @@ impl Scene { lod, map_bounds, - figure_model_cache: FigureModelCache::new(), - figure_state: None, figure_atlas, + sprite_render_state, camera, turning_camera: false, char_pos, + char_state: None, + char_model_cache: FigureModelCache::new(), + + airship_pos: char_pos - Vec3::unit_z() * 10.0, + airship_state: None, + airship_model_cache: FigureModelCache::new(), } } @@ -177,6 +192,9 @@ impl Scene { ) { self.camera .force_focus_pos(self.char_pos + Vec3::unit_z() * 1.5); + let ori = self.camera.get_tgt_orientation(); + self.camera + .set_orientation(Vec3::new(ori.x, ori.y.max(-0.25), ori.z)); self.camera.update( scene_data.time, /* 1.0 / 60.0 */ scene_data.delta_time, @@ -196,7 +214,7 @@ impl Scene { const TIME: f64 = 8.6 * 60.0 * 60.0; const SHADOW_NEAR: f32 = 0.25; - const SHADOW_FAR: f32 = 128.0; + const SHADOW_FAR: f32 = 1.0; self.lod .maintain(renderer, client, self.camera.get_focus_pos(), &self.camera); @@ -230,7 +248,9 @@ impl Scene { renderer.update_clouds_locals(CloudsLocals::new(proj_mat_inv, view_mat_inv)); renderer.update_postprocess_locals(PostProcessLocals::new(proj_mat_inv, view_mat_inv)); - self.figure_model_cache + self.char_model_cache + .clean(&mut self.figure_atlas, scene_data.tick); + self.airship_model_cache .clean(&mut self.figure_atlas, scene_data.tick); let item_info = |equip_slot| { @@ -251,12 +271,37 @@ impl Scene { let hands = (active_tool_hand, second_tool_hand); + fn figure_params( + camera: &Camera, + dt: f32, + pos: Vec3, + ) -> FigureUpdateCommonParameters<'_> { + FigureUpdateCommonParameters { + entity: None, + pos: pos.into(), + ori: anim::vek::Quaternion::identity().rotated_z(std::f32::consts::PI * -0.5), + scale: 1.0, + mount_transform_pos: None, + body: None, + tools: (None, None), + col: Rgba::broadcast(1.0), + dt, + _lpindex: 0, + _visible: true, + is_player: false, + _camera: camera, + terrain: None, + ground_vel: Vec3::zero(), + } + } + if let Some(body) = scene_data.body { - let figure_state = self.figure_state.get_or_insert_with(|| { + let char_state = self.char_state.get_or_insert_with(|| { FigureState::new(renderer, CharacterSkeleton::default(), body) }); - let tgt_skeleton = IdleAnimation::update_skeleton( - figure_state.skeleton_mut(), + let params = figure_params(&self.camera, scene_data.delta_time, self.char_pos.into()); + let tgt_skeleton = anim::character::IdleAnimation::update_skeleton( + char_state.skeleton_mut(), ( active_tool_kind, second_tool_kind, @@ -265,48 +310,74 @@ impl Scene { ), scene_data.time as f32, &mut 0.0, - &SkeletonAttr::from(&body), + &anim::character::SkeletonAttr::from(&body), ); let dt_lerp = (scene_data.delta_time * 15.0).min(1.0); - *figure_state.skeleton_mut() = - Lerp::lerp(&*figure_state.skeleton_mut(), &tgt_skeleton, dt_lerp); - - let model = self - .figure_model_cache - .get_or_create_model( - renderer, - &mut self.figure_atlas, - body, - inventory, - (), - scene_data.tick, - CameraMode::default(), - None, - scene_data.slow_job_pool, - None, - ) - .0; - let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; - let common_params = FigureUpdateCommonParameters { - entity: None, - pos: self.char_pos.into(), - ori: anim::vek::Quaternion::identity().rotated_z(std::f32::consts::PI * -0.5), - scale: 1.0, - mount_transform_pos: None, - body: None, - tools: (None, None), - col: Rgba::broadcast(1.0), - dt: scene_data.delta_time, - _lpindex: 0, - _visible: true, - is_player: false, - _camera: &self.camera, - terrain: None, - ground_vel: Vec3::zero(), - }; - - figure_state.update(renderer, None, &mut buf, &common_params, 1.0, model, body); + *char_state.skeleton_mut() = + Lerp::lerp(&*char_state.skeleton_mut(), &tgt_skeleton, dt_lerp); + let (model, _) = self.char_model_cache.get_or_create_model( + renderer, + &mut self.figure_atlas, + body, + inventory, + (), + scene_data.tick, + CameraMode::default(), + None, + scene_data.slow_job_pool, + None, + ); + char_state.update( + renderer, + None, + &mut [Default::default(); anim::MAX_BONE_COUNT], + ¶ms, + 1.0, + model, + body, + ); } + + let airship_body = ship::Body::DefaultAirship; + let airship_state = self.airship_state.get_or_insert_with(|| { + FigureState::new(renderer, ShipSkeleton::default(), airship_body) + }); + let params = figure_params(&self.camera, scene_data.delta_time, self.airship_pos.into()); + let tgt_skeleton = anim::ship::IdleAnimation::update_skeleton( + airship_state.skeleton_mut(), + ( + None, + None, + scene_data.time as f32, + scene_data.time as f32, + (params.ori * Vec3::unit_y()).into(), + (params.ori * Vec3::unit_y()).into(), + ), + scene_data.time as f32, + &mut 0.0, + &anim::ship::SkeletonAttr::from(&airship_body), + ); + let dt_lerp = (scene_data.delta_time * 15.0).min(1.0); + *airship_state.skeleton_mut() = + Lerp::lerp(&*airship_state.skeleton_mut(), &tgt_skeleton, dt_lerp); + let (model, _) = self.airship_model_cache.get_or_create_terrain_model( + renderer, + &mut self.figure_atlas, + airship_body, + (), + scene_data.tick, + scene_data.slow_job_pool, + &self.sprite_render_state, + ); + airship_state.update( + renderer, + None, + &mut [Default::default(); anim::MAX_BONE_COUNT], + ¶ms, + 1.0, + model, + airship_body, + ); } pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.globals_bind_group } @@ -320,7 +391,7 @@ impl Scene { ) { let mut figure_drawer = drawer.draw_figures(); if let Some(body) = body { - let model = &self.figure_model_cache.get_model( + let model = &self.char_model_cache.get_model( &self.figure_atlas, body, inventory, @@ -330,17 +401,36 @@ impl Scene { None, ); - if let Some((model, figure_state)) = model.zip(self.figure_state.as_ref()) { + if let Some((model, char_state)) = model.zip(self.char_state.as_ref()) { if let Some(lod) = model.lod_model(0) { figure_drawer.draw( lod, - figure_state.bound(), + char_state.bound(), self.figure_atlas.texture(ModelEntryRef::Figure(model)), ); } } } + let model = &self.airship_model_cache.get_model( + &self.figure_atlas, + ship::Body::DefaultAirship, + Default::default(), + tick, + CameraMode::default(), + None, + None, + ); + if let Some((model, airship_state)) = model.zip(self.airship_state.as_ref()) { + if let Some(lod) = model.lod_model(0) { + figure_drawer.draw( + lod, + airship_state.bound(), + self.figure_atlas.texture(ModelEntryRef::Terrain(model)), + ); + } + } + drop(figure_drawer); self.lod.render(drawer, Default::default()); diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 91534ea01c..ea76bf1153 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -483,10 +483,6 @@ pub struct Terrain { /// might significantly reduce the number of textures we need for /// particularly difficult locations. atlas: AtlasAllocator, - /// FIXME: This could possibly become an `AssetHandle`, to get - /// hot-reloading for free, but I am not sure if sudden changes of this - /// value would break something - pub sprite_config: Arc, chunks: HashMap, TerrainChunkData>, /// Temporary storage for dead chunks that might still be shadowing chunks /// in view. We wait until either the chunk definitely cannot be @@ -516,9 +512,8 @@ pub struct Terrain { // GPU data // Maps sprite kind + variant to data detailing how to render it - pub sprite_data: Arc>, + pub sprite_render_state: SpriteRenderState, pub sprite_globals: SpriteGlobalsBindGroup, - pub sprite_atlas_textures: Arc>, /// As stated previously, this is always the very latest texture into which /// we allocate. Code cannot assume that this is the assigned texture /// for any particular chunk; look at the `texture` field in @@ -533,11 +528,19 @@ impl TerrainChunkData { } #[derive(Clone)] -pub struct SpriteRenderContext { - sprite_config: Arc, +pub struct SpriteRenderState { + /// FIXME: This could possibly become an `AssetHandle`, to get + /// hot-reloading for free, but I am not sure if sudden changes of this + /// value would break something + pub sprite_config: Arc, // Maps sprite kind + variant to data detailing how to render it - sprite_data: Arc>, - sprite_atlas_textures: Arc>, + pub sprite_data: Arc>, + pub sprite_atlas_textures: Arc>, +} + +#[derive(Clone)] +pub struct SpriteRenderContext { + pub state: SpriteRenderState, sprite_verts_buffer: Arc, } @@ -705,10 +708,12 @@ impl SpriteRenderContext { let sprite_verts_buffer = renderer.create_sprite_verts(sprite_mesh); Self { - // TODO: these are all Arcs, would it makes sense to factor out the Arc? - sprite_config: Arc::clone(&sprite_config), - sprite_data: Arc::new(sprite_data), - sprite_atlas_textures: Arc::new(sprite_atlas_textures), + state: SpriteRenderState { + // TODO: these are all Arcs, would it makes sense to factor out the Arc? + sprite_config: Arc::clone(&sprite_config), + sprite_data: Arc::new(sprite_data), + sprite_atlas_textures: Arc::new(sprite_atlas_textures), + }, sprite_verts_buffer: Arc::new(sprite_verts_buffer), } }; @@ -732,7 +737,6 @@ impl Terrain { Self { atlas, - sprite_config: sprite_render_context.sprite_config, chunks: HashMap::default(), shadow_chunks: Vec::default(), mesh_send_tmp: send, @@ -740,8 +744,7 @@ impl Terrain { mesh_todo: HashMap::default(), mesh_todos_active: Arc::new(AtomicU64::new(0)), mesh_recv_overflow: 0.0, - sprite_data: sprite_render_context.sprite_data, - sprite_atlas_textures: sprite_render_context.sprite_atlas_textures, + sprite_render_state: sprite_render_context.state, sprite_globals: renderer.bind_sprite_globals( global_model, lod_data, @@ -1227,8 +1230,8 @@ impl Terrain { // Queue the worker thread. let started_tick = todo.started_tick; - let sprite_data = Arc::clone(&self.sprite_data); - let sprite_config = Arc::clone(&self.sprite_config); + let sprite_data = Arc::clone(&self.sprite_render_state.sprite_data); + let sprite_config = Arc::clone(&self.sprite_render_state.sprite_config); let cnt = Arc::clone(&self.mesh_todos_active); cnt.fetch_add(1, Ordering::Relaxed); scene_data From 751df7801fc8d4b4cb86dc2ea0c2d13848c75288 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 15 Jan 2024 22:51:54 +0000 Subject: [PATCH 6/7] Render airship sprites in char select --- voxygen/src/menu/char_selection/mod.rs | 6 ++-- voxygen/src/scene/figure/mod.rs | 2 +- voxygen/src/scene/simple.rs | 47 +++++++++++++++++++++----- voxygen/src/scene/terrain.rs | 2 +- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 579a275a5c..17662ee67f 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -25,14 +25,12 @@ pub struct CharSelectionState { impl CharSelectionState { /// Create a new `CharSelectionState`. pub fn new(global_state: &mut GlobalState, client: Rc>) -> Self { - let sprite_render_state = - (global_state.lazy_init)(global_state.window.renderer_mut()).state; - + let sprite_render_context = (global_state.lazy_init)(global_state.window.renderer_mut()); let scene = Scene::new( global_state.window.renderer_mut(), &mut client.borrow_mut(), &global_state.settings, - sprite_render_state, + sprite_render_context, ); let char_selection_ui = CharSelectionUi::new(global_state, &client.borrow()); diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 3510a147ee..954370c1ee 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -7535,7 +7535,7 @@ impl FigureStateMeta { pub struct FigureState { meta: FigureStateMeta, skeleton: S, - extra: D, + pub extra: D, } impl Deref for FigureState { diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 27caf3c38d..87d8e471e6 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -1,13 +1,15 @@ use crate::{ render::{ - create_skybox_mesh, Consts, FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, - Model, PointLightMatrix, RainOcclusionLocals, Renderer, Shadow, ShadowLocals, SkyboxVertex, + create_skybox_mesh, pipelines::terrain::BoundLocals as BoundTerrainLocals, AltIndices, + Consts, FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, Model, + PointLightMatrix, RainOcclusionLocals, Renderer, Shadow, ShadowLocals, SkyboxVertex, + SpriteGlobalsBindGroup, }, scene::{ camera::{self, Camera, CameraMode}, figure::{FigureAtlas, FigureModelCache, FigureState, FigureUpdateCommonParameters}, - terrain::SpriteRenderState, - CloudsLocals, Lod, PostProcessLocals, + terrain::{SpriteRenderContext, SpriteRenderState}, + CloudsLocals, CullingMode, Lod, PostProcessLocals, }, window::{Event, PressState}, Settings, @@ -54,6 +56,7 @@ pub struct Scene { figure_atlas: FigureAtlas, sprite_render_state: SpriteRenderState, + sprite_globals: SpriteGlobalsBindGroup, turning_camera: bool, @@ -62,7 +65,7 @@ pub struct Scene { char_model_cache: FigureModelCache, airship_pos: Vec3, - airship_state: Option>, + airship_state: Option>, airship_model_cache: FigureModelCache, } @@ -84,7 +87,7 @@ impl Scene { renderer: &mut Renderer, client: &mut Client, settings: &Settings, - sprite_render_state: SpriteRenderState, + sprite_render_context: SpriteRenderContext, ) -> Self { let start_angle = -90.0f32.to_radians(); let resolution = renderer.resolution().map(|e| e as f32); @@ -125,16 +128,21 @@ impl Scene { client.set_lod_distance(settings.graphics.lod_distance); Self { - data, globals_bind_group, skybox: Skybox { model: renderer.create_model(&create_skybox_mesh()).unwrap(), }, - lod, map_bounds, figure_atlas, - sprite_render_state, + sprite_render_state: sprite_render_context.state, + sprite_globals: renderer.bind_sprite_globals( + &data, + lod.get_data(), + &sprite_render_context.sprite_verts_buffer, + ), + lod, + data, camera, @@ -433,6 +441,27 @@ impl Scene { drop(figure_drawer); + let mut sprite_drawer = drawer.draw_sprites( + &self.sprite_globals, + &self.sprite_render_state.sprite_atlas_textures, + ); + if let (Some(sprite_instances), Some(data)) = ( + self.airship_model_cache + .get_sprites(ship::Body::DefaultAirship), + self.airship_state.as_ref().map(|s| &s.extra), + ) { + sprite_drawer.draw( + data, + &sprite_instances[0], + &AltIndices { + deep_end: 0, + underground_end: 0, + }, + CullingMode::None, + ); + } + drop(sprite_drawer); + self.lod.render(drawer, Default::default()); drawer.draw_skybox(&self.skybox.model); diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index ea76bf1153..ed3a8708d4 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -541,7 +541,7 @@ pub struct SpriteRenderState { #[derive(Clone)] pub struct SpriteRenderContext { pub state: SpriteRenderState, - sprite_verts_buffer: Arc, + pub sprite_verts_buffer: Arc, } pub type SpriteRenderContextLazy = Box SpriteRenderContext>; From 64debe2f0ba6391b9d1c8d71b430975f77e9a8be Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 16 Jan 2024 17:47:24 +0000 Subject: [PATCH 7/7] Remove unnecessary conversion --- voxygen/src/scene/simple.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 87d8e471e6..be3515ab76 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -307,7 +307,7 @@ impl Scene { let char_state = self.char_state.get_or_insert_with(|| { FigureState::new(renderer, CharacterSkeleton::default(), body) }); - let params = figure_params(&self.camera, scene_data.delta_time, self.char_pos.into()); + let params = figure_params(&self.camera, scene_data.delta_time, self.char_pos); let tgt_skeleton = anim::character::IdleAnimation::update_skeleton( char_state.skeleton_mut(), ( @@ -350,7 +350,7 @@ impl Scene { let airship_state = self.airship_state.get_or_insert_with(|| { FigureState::new(renderer, ShipSkeleton::default(), airship_body) }); - let params = figure_params(&self.camera, scene_data.delta_time, self.airship_pos.into()); + let params = figure_params(&self.camera, scene_data.delta_time, self.airship_pos); let tgt_skeleton = anim::ship::IdleAnimation::update_skeleton( airship_state.skeleton_mut(), (