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