From c79f512f84dbb83cb82b7954db68ff241dfd8e41 Mon Sep 17 00:00:00 2001 From: Joshua Yanovski Date: Fri, 7 Aug 2020 11:55:20 +0200 Subject: [PATCH] Fix all clippy issues, clean up Rust code. --- client/src/lib.rs | 13 +- common/src/terrain/map.rs | 6 +- voxygen/src/anim/src/vek.rs | 10 - voxygen/src/mesh/greedy.rs | 224 +--- voxygen/src/mesh/mod.rs | 17 +- voxygen/src/mesh/segment.rs | 78 +- voxygen/src/mesh/terrain.rs | 192 +--- voxygen/src/render/consts.rs | 9 - voxygen/src/render/mesh.rs | 1 - voxygen/src/render/mod.rs | 4 +- voxygen/src/render/pipelines/figure.rs | 1 - voxygen/src/render/pipelines/fluid.rs | 32 - voxygen/src/render/pipelines/lod_terrain.rs | 68 +- voxygen/src/render/pipelines/mod.rs | 13 +- voxygen/src/render/pipelines/shadow.rs | 54 +- voxygen/src/render/pipelines/skybox.rs | 1 - voxygen/src/render/pipelines/sprite.rs | 33 +- voxygen/src/render/pipelines/terrain.rs | 67 +- voxygen/src/render/pipelines/ui.rs | 12 - voxygen/src/render/renderer.rs | 405 ++----- voxygen/src/render/texture.rs | 2 - voxygen/src/scene/camera.rs | 2 - voxygen/src/scene/figure/cache.rs | 90 +- voxygen/src/scene/figure/load.rs | 2 +- voxygen/src/scene/figure/mod.rs | 62 +- voxygen/src/scene/lod.rs | 82 +- voxygen/src/scene/math.rs | 262 +---- voxygen/src/scene/mod.rs | 1063 +++++-------------- voxygen/src/scene/simple.rs | 82 +- voxygen/src/scene/terrain.rs | 600 ++--------- 30 files changed, 746 insertions(+), 2741 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 55d8b6e2e5..17ae9b0237 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -233,10 +233,7 @@ impl Client { map_size_lg, core::ops::RangeInclusive::new(0.0, max_height), ); - // map_config.gain = max_height; map_config.horizons = Some(&horizons); - // map_config.light_direction = Vec3::new(1.0, -1.0, 0.0); - // map_config.focus.z = 0.0; let rescale_height = |h: f32| h / max_height; let bounds_check = |pos: Vec2| { pos.reduce_partial_min() >= 0 @@ -308,8 +305,7 @@ impl Client { }, ); let make_raw = |rgba| -> Result<_, Error> { - let mut raw = - vec![0u8; 4 * world_map.len()/*map_size.x * map_size.y*/]; + let mut raw = vec![0u8; 4 * world_map.len()]; LittleEndian::write_u32_into(rgba, &mut raw); Ok(Arc::new( image::DynamicImage::ImageRgba8({ @@ -323,15 +319,14 @@ impl Client { .flipv(), )) }; - let lod_base = rgba; //make_raw(&rgba)?; - let lod_alt = alt; //make_raw(&alt)?; + let lod_base = rgba; + let lod_alt = alt; let world_map = make_raw(&world_map)?; let horizons = (west.0, west.1, east.0, east.1) .into_par_iter() .map(|(wa, wh, ea, eh)| u32::from_le_bytes([wa, wh, ea, eh])) .collect::>(); - let lod_horizon = horizons; //make_raw(&horizons)?; - // TODO: Get sea_level from server. + let lod_horizon = horizons; let map_bounds = Vec2::new(sea_level, max_height); debug!("Done preparing image..."); diff --git a/common/src/terrain/map.rs b/common/src/terrain/map.rs index 545ca7883a..d3efd256c0 100644 --- a/common/src/terrain/map.rs +++ b/common/src/terrain/map.rs @@ -157,7 +157,7 @@ impl MapSizeLg { #[inline(always)] pub const fn new(map_size_lg: Vec2) -> Result { // Assertion on dimensions: must be between - // 0 and MAX_WORLD_BLOCKS_LG] - [TERRAIN_CHUNK_BLOCKS_LG + // 0 and ([MAX_WORLD_BLOCKS_LG] - [TERRAIN_CHUNK_BLOCKS_LG]) let is_le_max = map_size_lg.x <= MAX_WORLD_BLOCKS_LG.x - TERRAIN_CHUNK_BLOCKS_LG && map_size_lg.y <= MAX_WORLD_BLOCKS_LG.y - TERRAIN_CHUNK_BLOCKS_LG; // Assertion on dimensions: chunks must fit in a u16. @@ -667,14 +667,12 @@ impl<'a> MapConfig<'a> { let i_a = Rgb::new(0.1, 0.1, 0.1); // V = direction pointing towards the viewer (e.g. virtual camera). let v = Vec3::new(0.0, 0.0, -1.0).normalized(); - // let v = Vec3::new(0.0, -1.0, 0.0).normalized(); - // + // for each light m, // i_m,d = (RGB) intensity of diffuse component of light source m let i_m_d = Rgb::new(1.0, 1.0, 1.0); // i_m,s = (RGB) intensity of specular component of light source m let i_m_s = Rgb::new(0.45, 0.45, 0.45); - // let i_m_s = Rgb::new(0.45, 0.45, 0.45); // for each light m and point p, // L_m = (normalized) direction vector from point on surface to light source m diff --git a/voxygen/src/anim/src/vek.rs b/voxygen/src/anim/src/vek.rs index 718f267d83..ee9bda3c45 100644 --- a/voxygen/src/anim/src/vek.rs +++ b/voxygen/src/anim/src/vek.rs @@ -6,13 +6,3 @@ pub use ::vek::{ bezier::repr_c::*, geom::repr_c::*, mat::repr_c::column_major::Mat4, ops::*, quaternion::repr_c::*, transform::repr_c::*, transition::*, vec::repr_c::*, }; */ -/* pub use vek::{ - bezier::repr_c::*, - geom::repr_c::*, - mat::repr_simd::column_major::Mat4, - ops::*, - quaternion::repr_simd::*, - transform::repr_c::*, - transition::*, - vec::repr_simd::*, -}; */ diff --git a/voxygen/src/mesh/greedy.rs b/voxygen/src/mesh/greedy.rs index 0ad4bea9f7..93209fa668 100644 --- a/voxygen/src/mesh/greedy.rs +++ b/voxygen/src/mesh/greedy.rs @@ -3,6 +3,13 @@ use vek::*; type TerrainVertex = ::Vertex; +type TodoRect = ( + Vec3, + Vec2>, + guillotiere::Rectangle, + Vec3, +); + /// `max_size`: /// /// `draw_delta`: @@ -162,7 +169,7 @@ impl<'a> GreedyMesh<'a> { FS: for<'r> FnMut(&'r mut D, Vec3, Vec3, Vec2>) -> Option<(bool, M)>, FP: FnMut(Vec2, Vec2>, Vec3, Vec2>, Vec3, &M), { - let (bounds, /* opaque, *//*shadow, */ cont) = greedy_mesh( + let (bounds, cont) = greedy_mesh( &mut self.atlas, &mut self.col_lights_size, self.max_size, @@ -183,7 +190,10 @@ impl<'a> GreedyMesh<'a> { /// Returns the ColLightsInfo corresponding to the consstructed atlas. pub fn finalize(self) -> ColLightInfo { let cur_size = self.col_lights_size; - let col_lights = vec![/*Default::default()*/TerrainVertex::make_col_light(254, Rgb::broadcast(254)); usize::from(cur_size.x) * usize::from(cur_size.y)]; + let col_lights = vec![ + TerrainVertex::make_col_light(254, Rgb::broadcast(254)); + usize::from(cur_size.x) * usize::from(cur_size.y) + ]; let mut col_lights_info = (col_lights, cur_size); self.suspended.into_iter().for_each(|cont| { cont(&mut col_lights_info); @@ -209,12 +219,7 @@ fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FC, FO, FS, FP>( mut should_draw, mut push_quad, }: GreedyConfig, -) -> ( - Aabb, - // Mesh, - // Mesh, - Box>, -) +) -> (Aabb, Box>) where FL: for<'r> FnMut(&'r mut D, Vec3) -> f32 + 'a, FC: for<'r> FnMut(&'r mut D, Vec3) -> Rgb + 'a, @@ -222,24 +227,9 @@ where FS: for<'r> FnMut(&'r mut D, Vec3, Vec3, Vec2>) -> Option<(bool, M)>, FP: FnMut(Vec2, Vec2>, Vec3, Vec2>, Vec3, &M), { - // let mut opaque_mesh = Mesh::new(); - // let mut shadow_mesh = Mesh::new(); - // TODO: Collect information to see if we can choose a good value here. let mut todo_rects = Vec::with_capacity(1024); - /* let mut bounds = Aabb { - min: Vec3::zero(), - max: Vec3::zero(), - }; */ - - /* let compute_bounds = |pos: Vec3, dim: Vec2, uv: Vec2>/*, norm: Vec3, faces_forward: bool*/| { - Aabb { - min: pos, - max: pos + uv.x.map(usize::from) * dim.x + uv.y.map(usize::from) * dim.y, - } - }; */ - // x (u = y, v = z) greedy_mesh_cross_section( Vec3::new(greedy_size.y, greedy_size.z, greedy_size_cross.x), @@ -247,7 +237,7 @@ where should_draw( &mut data, draw_delta + Vec3::new(pos.z, pos.x, pos.y), - Vec3::unit_x(), /* , pos.z, 0, x_size */ + Vec3::unit_x(), Vec2::new(Vec3::unit_y(), Vec3::unit_z()), ) }, @@ -255,7 +245,6 @@ where let pos = Vec3::new(pos.z, pos.x, pos.y); let uv = Vec2::new(Vec3::unit_y(), Vec3::unit_z()); let norm = Vec3::unit_x(); - // bounds.expand_to_contain(compute_bounds(pos, dim, uv)); let atlas_pos = if let Some(atlas_pos) = add_to_atlas( atlas, &mut todo_rects, @@ -267,29 +256,18 @@ where max_size, col_lights_size, ) { - // assert!(atlas_pos.max.x - atlas_pos.min.x == dim.x as i32); - // assert!(atlas_pos.max.y - atlas_pos.min.y == dim.y as i32); atlas_pos } else { return; }; create_quad_greedy( - // &mut shadow_mesh, - // &mut opaque_mesh, - /* Vec3::new(pos.z, pos.x, pos.y) */ pos, dim, uv, norm, faces_forward, - // Rgba::from_opaque(flat_get(pos).color), - // lightm - // ao, meta, atlas_pos, - // |pos| flat_get(pos), - // |pos, norm, meta| create_shadow(pos, norm, meta), - // |atlas_pos, pos, norm, meta| create_opaque(atlas_pos, pos, norm, meta), |atlas_pos, dim, pos, draw_dim, norm, meta| { push_quad(atlas_pos, dim, pos, draw_dim, norm, meta) }, @@ -312,7 +290,6 @@ where let pos = Vec3::new(pos.y, pos.z, pos.x); let uv = Vec2::new(Vec3::unit_z(), Vec3::unit_x()); let norm = Vec3::unit_y(); - // bounds.expand_to_contain(compute_bounds(pos, dim, uv)); let atlas_pos = if let Some(atlas_pos) = add_to_atlas( atlas, &mut todo_rects, @@ -329,18 +306,13 @@ where return; }; create_quad_greedy( - // &mut shadow_mesh, - // &mut opaque_mesh, pos, dim, uv, norm, faces_forward, - // Rgba::from_opaque(flat_get(pos).color), meta, atlas_pos, - // |pos, norm, meta| create_shadow(pos, norm, meta), - // |atlas_pos, pos, norm, meta| create_opaque(atlas_pos, pos, norm, meta), |atlas_pos, dim, pos, draw_dim, norm, meta| { push_quad(atlas_pos, dim, pos, draw_dim, norm, meta) }, @@ -352,25 +324,17 @@ where greedy_mesh_cross_section( Vec3::new(greedy_size.x, greedy_size.y, greedy_size_cross.z), |pos| { - /* if pos.z == 0 { - let pos = pos.map(|e| e as i32) + draw_delta; // - delta; - let to = flat_get(pos).is_opaque(); //map(|v| v.is_opaque()).unwrap_or(false); - if to { Some(false) } else { None } - } else */ - { - should_draw( - &mut data, - draw_delta + Vec3::new(pos.x, pos.y, pos.z), - Vec3::unit_z(), - Vec2::new(Vec3::unit_x(), Vec3::unit_y()), - ) - } + should_draw( + &mut data, + draw_delta + Vec3::new(pos.x, pos.y, pos.z), + Vec3::unit_z(), + Vec2::new(Vec3::unit_x(), Vec3::unit_y()), + ) }, |pos, dim, &(faces_forward, ref meta)| { let pos = Vec3::new(pos.x, pos.y, pos.z); let uv = Vec2::new(Vec3::unit_x(), Vec3::unit_y()); let norm = Vec3::unit_z(); - // bounds.expand_to_contain(compute_bounds(pos, dim, uv)); let atlas_pos = if let Some(atlas_pos) = add_to_atlas( atlas, &mut todo_rects, @@ -387,18 +351,13 @@ where return; }; create_quad_greedy( - // &mut shadow_mesh, - // &mut opaque_mesh, pos, dim, uv, norm, faces_forward, - // Rgba::from_opaque(flat_get(pos).color), meta, atlas_pos, - // |pos, norm, meta| create_shadow(pos, norm, meta), - // |atlas_pos, pos, norm, meta| create_opaque(atlas_pos, pos, norm, meta), |atlas_pos, dim, pos, draw_dim, norm, meta| { push_quad(atlas_pos, dim, pos, draw_dim, norm, meta) }, @@ -406,9 +365,6 @@ where }, ); - // NOTE: Safe because bound dimensions actually fit in a u16. - // let bounds = bounds.map(|e| e as u16); - // NOTE: Safe because draw_delta fits in i16. let bounds = Aabb { min: Vec3::zero(), // NOTE: Safe because greedy_size fit in u16. @@ -416,7 +372,6 @@ where }; ( bounds, - /* opaque_mesh, *//*shadow_mesh, */ Box::new(move |col_lights_info| { let mut data = data; draw_col_lights( @@ -435,7 +390,6 @@ where // Greedy meshing a single cross-section. fn greedy_mesh_cross_section( - /* mask: &mut [bool], */ dims: Vec3, // Should we draw a face here (below this vertex)? If so, provide its meta information. mut draw_face: impl FnMut(Vec3) -> Option, @@ -477,7 +431,7 @@ fn greedy_mesh_cross_section( .count(); let max_y = j + height; // Add quad. - push_quads(Vec3::new(i, j, d /* + 1 */), Vec2::new(width, height), ori); + push_quads(Vec3::new(i, j, d), Vec2::new(width, height), ori); // Unset mask bits in drawn region, so we don't try to re-draw them. (j..max_y).for_each(|l| { mask[l * dims.x + i..l * dims.x + max_x] @@ -498,12 +452,7 @@ fn greedy_mesh_cross_section( fn add_to_atlas( atlas: &mut guillotiere::SimpleAtlasAllocator, - todo_rects: &mut Vec<( - Vec3, - Vec2>, - guillotiere::Rectangle, - Vec3, - )>, + todo_rects: &mut Vec, pos: Vec3, uv: Vec2>, dim: Vec2, @@ -542,7 +491,6 @@ fn add_to_atlas( (max texture size={:?}, so we are discarding this rectangle.", pos, dim, max_size ); - // return None; } // Otherwise, we haven't reached max size yet, so double the size (or reach the // max texture size) and try again. @@ -551,7 +499,6 @@ fn add_to_atlas( max_size.height.min(current_size.height.saturating_mul(2)), ); atlas.grow(new_size); - // atlas.grow((current_size * 2).min(max_size)); } // NOTE: Conversion is correct because our initial max size for the atlas was // a u16 and we never grew the atlas, meaning all valid coordinates within the @@ -561,14 +508,6 @@ fn add_to_atlas( cur_size.y.max(atlas_rect.max.y as u16), ); - /* let (dim, uv, norm) = if faces_forward { - // NOTE: Conversion to u16 safe by function precondition. - (dim.map(|e| e as u16), uv, norm) - } else { - // NOTE: Conversion to u16 safe by function precondition. - (Vec2::new(dim.y as u16, dim.x as u16), Vec2::new(uv.y, uv.x), -norm) - }; */ - // NOTE: pos can be converted safely from usize to i32 because all legal block // coordinates in this chunk must fit in an i32 (actually we have the much // stronger property that this holds across the whole map). @@ -591,46 +530,28 @@ fn add_to_atlas( fn draw_col_lights( (col_lights, cur_size): &mut ColLightInfo, data: &mut D, - todo_rects: Vec<( - Vec3, - Vec2>, - guillotiere::Rectangle, - Vec3, - )>, + todo_rects: Vec, draw_delta: Vec3, mut get_light: impl FnMut(&mut D, Vec3) -> f32, mut get_color: impl FnMut(&mut D, Vec3) -> Rgb, mut get_opacity: impl FnMut(&mut D, Vec3) -> bool, mut make_col_light: impl FnMut(u8, Rgb) -> <::Surface as gfx::format::SurfaceTyped>::DataType, ) { - /* for i in 0..todo_rects.len() { - for j in 0..todo_rects.len() { - if i == j { - continue; - } - - assert!(!todo_rects[i].2.intersects(&todo_rects[j].2)); - } - } */ - todo_rects - .into_iter() - // .rev() - .for_each(|(pos, uv, rect, delta)| { - // NOTE: Conversions are safe because width, height, and offset must be - // non-negative, and because every allocated coordinate in the atlas must be in - // bounds for the original size, max_texture_size, which fit into a u16. - let width = (rect.max.x - rect.min.x) as u16;//rect.width() as u16; - let height = (rect.max.y - rect.min.y) as u16;//rect.height() as u16; - /* if width > 32 || height > 32 { - println!("Rect: {:?}", rect); - } */ - let left = rect.min.x as u16; - let top = rect.min.y as u16; - let uv = uv.map(|e| e.map(i32::from)); - let pos = pos + draw_delta;//Vec3::new(0, 0, z_start - 1);// + mesh_delta;// + draw_delta; - (0..height).for_each(|v| { - let start = usize::from(cur_size.x) * usize::from(top + v) + usize::from(left); - (0..width).zip(&mut col_lights[start..start + usize::from(width)]).for_each(|(u, col_light)| { + todo_rects.into_iter().for_each(|(pos, uv, rect, delta)| { + // NOTE: Conversions are safe because width, height, and offset must be + // non-negative, and because every allocated coordinate in the atlas must be in + // bounds for the original size, max_texture_size, which fit into a u16. + let width = (rect.max.x - rect.min.x) as u16; + let height = (rect.max.y - rect.min.y) as u16; + let left = rect.min.x as u16; + let top = rect.min.y as u16; + let uv = uv.map(|e| e.map(i32::from)); + let pos = pos + draw_delta; + (0..height).for_each(|v| { + let start = usize::from(cur_size.x) * usize::from(top + v) + usize::from(left); + (0..width) + .zip(&mut col_lights[start..start + usize::from(width)]) + .for_each(|(u, col_light)| { let pos = pos + uv.x * i32::from(u) + uv.y * i32::from(v); // TODO: Consider optimizing to take advantage of the fact that this whole // face should be facing nothing but air (this is not currently true, but @@ -642,33 +563,23 @@ fn draw_col_lights( // direct_opacity, and indirect_uv_opacity is multiplied by // the maximum of both of u and v's indirect opacities (since there are // two choices for how to get to the direct surface). - let pos = pos + - if u + 1 == width { -uv.x } else { Vec3::zero() } + - if v + 1 == height { -uv.y } else { Vec3::zero() }; + let pos = pos + + if u + 1 == width { -uv.x } else { Vec3::zero() } + + if v + 1 == height { -uv.y } else { Vec3::zero() }; let uv = Vec2::new( if u + 1 == width { -uv.x } else { uv.x }, - if v + 1 == height { -uv.y } else { uv.y }, + if v + 1 == height { -uv.y } else { uv.y }, ); - let light_pos = pos + /*range.min + */delta; - // let block = flat_get(pos); + let light_pos = pos + delta; // Currently, we assume that direct_opacity is 1 (if it's 0, you can't see // the face anyway, since it's blocked by the block directly in front of it). // TODO: If we add non-0/1 opacities, fix this. - // top-left block - // let direct_opacity = !flat_get(pos + delta).is_opaque(); // bottom-left block let direct_u_opacity = get_opacity(data, light_pos - uv.x); // top-right block let direct_v_opacity = get_opacity(data, light_pos - uv.y); - // top-left block - // NOTE: Currently, since we only have 0 / 1 opacities, we don't worry - // about whether the uv block itself is opaque, because if it is its light - // value will be 0 anyway. But if we add translucent objects, we'll need - // to care about uv's opacity as well. - // let direct_uv_opacity = !flat_get(pos + delta - uv.x - uv.y).is_opaque(); - // let indirect_opacity = direct_uv_opacity && (direct_u_opacity || direct_v_opacity) && direct_opacity; // NOTE: Since we only support 0/1 opacities currently, we asssume // direct_opacity is 1, and the light value will be zero anyway for objects @@ -680,24 +591,26 @@ fn draw_col_lights( // Light from the bottom-right-front block to this vertex always // appears on this face, since it's the block this face is facing (so // it can't be blocked by anything). - if /*direct_u_opacity || direct_v_opacity*/true/* || !flat_get(pos - uv.x - uv.y).is_opaque()*//* || !block.is_opaque()*/ { get_light(data, light_pos) } else { 0.0 } + - if /*direct_opacity || direct_uv_opacity*/true/* || !flat_get(pos - uv.y).is_opaque()*/ { get_light(data, light_pos - uv.x) } else { 0.0 } + - if /*direct_opacity || direct_uv_opacity*/true/* || !flat_get(pos - uv.x).is_opaque()*/ { get_light(data, light_pos - uv.y) } else { 0.0 } + - if direct_u_opacity || direct_v_opacity/* || !block.is_opaque()*/ { get_light(data, light_pos - uv.x - uv.y) } else { 0.0 } + get_light(data, light_pos) + + get_light(data, light_pos - uv.x) + + get_light(data, light_pos - uv.y) + + if direct_u_opacity || direct_v_opacity { + get_light(data, light_pos - uv.x - uv.y) + } else { + 0.0 + } ) / 4.0; - let col = get_color(data, pos);//.map(Rgba::from_opaque).unwrap_or(Rgba::zero()); + let col = get_color(data, pos); let light = (darkness * 255.0) as u8; *col_light = make_col_light(light, col); }); - }); }); + }); } /// Precondition: when this function is called, atlas_pos should reflect an /// actual valid position in a texture atlas (meaning it should fit into a u16). -fn create_quad_greedy( - // shadow_mesh: &mut Mesh, - // opaque_mesh: &mut Mesh, +fn create_quad_greedy( origin: Vec3, dim: Vec2, uv: Vec2>, @@ -705,26 +618,16 @@ fn create_quad_greedy( faces_forward: bool, meta: &M, atlas_pos: guillotiere::Rectangle, - // origin, norm, meta - // create_shadow: impl Fn(Vec3, Vec3, &M) -> S::Vertex, - // create_opaque: impl Fn(Vec2, Vec3, Vec3, &M) -> O::Vertex, mut push_quad: impl FnMut(Vec2, Vec2>, Vec3, Vec2>, Vec3, &M), -) /* -> Quad */ -{ +) { let origin = origin.map(|e| e as f32); - /* // NOTE: Conversion to u16 safe by function precondition. - let dim = uv.map2(dim.map(|e| e as u16), |e, f| e * f); */ // NOTE: Conversion to f32 safe by function precondition (u16 can losslessly // cast to f32, and dim fits in a u16). let draw_dim = uv.map2(dim.map(|e| e as f32), |e, f| e.map(f32::from) * f); let dim = Vec2::new(Vec2::new(dim.x as u16, 0), Vec2::new(0, dim.y as u16)); let (draw_dim, dim, /* uv, */ norm) = if faces_forward { - /* // NOTE: Conversion to u16 safe by function precondition. - (dim.map(|e| e as u16), uv, norm) */ (draw_dim, dim, norm) } else { - /* // NOTE: Conversion to u16 safe by function precondition. - (Vec2::new(dim.y as u16, dim.x as u16), Vec2::new(uv.y, uv.x), -norm) */ ( Vec2::new(draw_dim.y, draw_dim.x), Vec2::new(dim.y, dim.x), @@ -732,21 +635,8 @@ fn create_quad_greedy( ) }; let norm = norm.map(f32::from); - // let draw_dim = draw_dim.map(|e| e.map(f32::from)); // NOTE: Conversion to u16 safe by function precondition. let atlas_pos = Vec2::new(atlas_pos.min.x as u16, atlas_pos.min.y as u16); - /* shadow_mesh.push_quad(Quad::new( - create_shadow(origin, norm, &meta/*, atlas_pos*/), - create_shadow(origin + draw_dim.x, norm, &meta/*, atlas_pos + dim.x*/), - create_shadow(origin + draw_dim.x + draw_dim.y, norm, &meta/*, atlas_pos + dim.x + dim.y*/), - create_shadow(origin + draw_dim.y, norm, &meta/*, atlas_pos + dim.y*/), - )); */ - /* opaque_mesh.push_quad(Quad::new( - create_opaque(atlas_pos, origin, norm, &meta), - create_opaque(atlas_pos + dim.x, origin + draw_dim.x, norm, &meta), - create_opaque(atlas_pos + dim.x + dim.y, origin + draw_dim.x + draw_dim.y, norm, &meta), - create_opaque(atlas_pos + dim.y, origin + draw_dim.y, norm, &meta), - )); */ push_quad(atlas_pos, dim, origin, draw_dim, norm, meta); } @@ -769,9 +659,5 @@ pub fn create_quad( meta, ), create_vertex(atlas_pos + dim.y, origin + draw_dim.y, norm, meta), - /* create_vertex(atlas_pos, origin, norm, meta), - create_vertex(atlas_pos + dim.y, origin + draw_dim.y, norm, meta), - create_vertex(atlas_pos + dim.x + dim.y, origin + draw_dim.x + draw_dim.y, norm, meta), - create_vertex(atlas_pos + dim.x, origin + draw_dim.x, norm, meta), */ ) } diff --git a/voxygen/src/mesh/mod.rs b/voxygen/src/mesh/mod.rs index 24e6774e46..e66b176515 100644 --- a/voxygen/src/mesh/mod.rs +++ b/voxygen/src/mesh/mod.rs @@ -4,6 +4,13 @@ pub mod terrain; use crate::render::{self, Mesh}; +pub type MeshGen = ( + Mesh<>::Pipeline>, + Mesh<>::TranslucentPipeline>, + Mesh<>::ShadowPipeline>, + >::Result, +); + pub trait Meshable { type Pipeline: render::Pipeline; type TranslucentPipeline: render::Pipeline; @@ -12,13 +19,5 @@ pub trait Meshable { type Result; // Generate meshes - one opaque, one translucent, one shadow - fn generate_mesh( - self, - supp: Self::Supplement, - ) -> ( - Mesh, - Mesh, - Mesh, - Self::Result, - ); + fn generate_mesh(self, supp: Self::Supplement) -> MeshGen; } diff --git a/voxygen/src/mesh/segment.rs b/voxygen/src/mesh/segment.rs index 53512afd19..091f8e0fb3 100644 --- a/voxygen/src/mesh/segment.rs +++ b/voxygen/src/mesh/segment.rs @@ -1,7 +1,7 @@ use crate::{ mesh::{ greedy::{self, GreedyConfig, GreedyMesh}, - Meshable, + MeshGen, Meshable, }, render::{self, FigurePipeline, Mesh, ShadowPipeline, SpritePipeline, TerrainPipeline}, }; @@ -32,12 +32,7 @@ where fn generate_mesh( self, (greedy, offs, scale): Self::Supplement, - ) -> ( - Mesh, - Mesh, - Mesh, - Self::Result, - ) { + ) -> MeshGen, Self> { let max_size = greedy.max_size(); // NOTE: Required because we steal two bits from the normal in the shadow uint // in order to store the bone index. The two bits are instead taken out @@ -114,7 +109,7 @@ where } } -impl<'a: 'b, 'b, V: 'a> Meshable> for V +impl<'a: 'b, 'b, V: 'a> Meshable> for V where V: BaseVol + ReadVol + SizedVol, /* TODO: Use VolIterator instead of manually iterating @@ -132,12 +127,7 @@ where fn generate_mesh( self, (greedy, vertical_stripes): Self::Supplement, - ) -> ( - Mesh, - Mesh, - Mesh, - (), - ) { + ) -> MeshGen, Self> { let max_size = greedy.max_size(); // NOTE: Required because we steal two bits from the normal in the shadow uint // in order to store the bone index. The two bits are instead taken out @@ -182,15 +172,8 @@ where vol.get(vox).map(|vox| *vox).unwrap_or(Vox::empty()) }) }; - // NOTE: Conversion to f32 is fine since this i32 is actually in bounds for u16. - // let create_shadow = |pos, norm, _meta| ShadowVertex::new_figure((pos + offs) - // * scale, norm, 0); - let create_opaque = |atlas_pos, pos: Vec3, norm, _meta| { - /* if pos.x >= 15.0 || pos.y >= 15.0 || pos.z >= 63.0 { - println!("{:?}", pos); - } */ - SpriteVertex::new(atlas_pos, pos, norm /* , ao */) - }; + let create_opaque = + |atlas_pos, pos: Vec3, norm, _meta| SpriteVertex::new(atlas_pos, pos, norm); let mut opaque_mesh = Mesh::new(); let _bounds = greedy.push(GreedyConfig { @@ -224,10 +207,8 @@ fn should_draw_greedy( _uv: Vec2>, flat_get: impl Fn(Vec3) -> Cell, ) -> Option<(bool, /* u8 */ ())> { - // TODO: Verify conversion. - // let pos = pos.map(|e| e as i32) + draw_delta; // - delta; - let from = flat_get(pos - delta); // map(|v| v.is_opaque()).unwrap_or(false); - let to = flat_get(pos); //map(|v| v.is_opaque()).unwrap_or(false); + let from = flat_get(pos - delta); + let to = flat_get(pos); let from_opaque = !from.is_empty(); if from_opaque == !to.is_empty() { None @@ -244,52 +225,17 @@ fn should_draw_greedy_ao( delta: Vec3, _uv: Vec2>, flat_get: impl Fn(Vec3) -> Cell, -) -> Option<(bool, /* u8 */ bool)> { - // TODO: Verify conversion. - // let pos = pos.map(|e| e as i32) + draw_delta; // - delta; - let from = flat_get(pos - delta); // map(|v| v.is_opaque()).unwrap_or(false); - let to = flat_get(pos); //map(|v| v.is_opaque()).unwrap_or(false); +) -> Option<(bool, bool)> { + let from = flat_get(pos - delta); + let to = flat_get(pos); let from_opaque = !from.is_empty(); if from_opaque == !to.is_empty() { None } else { let faces_forward = from_opaque; - let ao = /* if delta.z != 0 { - 0u8 - } else { - (pos.z & 1) as u8 - // (((pos.x & 1) as u8) << 1) | (pos.y & 1) as u8 - }*/!vertical_stripes || /*((pos.x & 1) ^ (pos.y & 1))*/(pos.z & 1) != 0/* as u8*/; - /* let (from, delta, uv) = if faces_forward { - (pos - delta - uv.x - uv.y, delta, uv) - } else { - (pos, -delta, Vec2::new(-uv.y, -uv.x)) - }; - let ao_vertex = |from: Vec3, delta: Vec3, uv: Vec2>| { - let corner = !flat_get(from + delta - uv.x - uv.y).is_empty(); - let s1 = !flat_get(from + delta - uv.x).is_empty(); - let s2 = !flat_get(from + delta - uv.y).is_empty(); - if s1 && s2 { - 0 - } else { - 3 - (if corner { 1 } else { 0 } + if s1 { 1 } else { 0 } + if s2 { 1 } else { 0 }) - } - }; - // We only care about the vertices we are *not* merging, since the shared vertices - // by definition have the same AO values. But snce we go both down and right we end up - // needing all but the bottom right vertex. - let ao_corner = ao_vertex(from, delta, uv); - let ao1 = ao_vertex(from + uv.x, delta, uv); - let ao2 = ao_vertex(from + uv.y, delta, uv); - let ao3 = ao_vertex(from + uv.x + uv.y, delta, uv); - // NOTE: ao's 4 values correspond (from 0 to 3) to 0.25, 0.5, 0.75, 1.0. - // - // 0.0 is the None case. - let ao = (ao_corner << 6) | (ao1 << 4) | (ao2 << 2) | ao3; */ - // let ao = ao_vertex(from, delta, uv); + let ao = !vertical_stripes || (pos.z & 1) != 0; // If going from transparent to opaque, backward facing; otherwise, forward // facing. Some((faces_forward, ao)) - // Some((faces_forward, ())) } } diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index e120103b9f..fa1fef2779 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -1,7 +1,7 @@ use crate::{ mesh::{ greedy::{self, GreedyConfig, GreedyMesh}, - Meshable, + MeshGen, Meshable, }, render::{self, ColLightInfo, FluidPipeline, Mesh, ShadowPipeline, TerrainPipeline}, }; @@ -230,12 +230,7 @@ impl<'a, V: RectRasterableVol + ReadVol + Debug> fn generate_mesh( self, (range, max_texture_size): Self::Supplement, - ) -> ( - Mesh, - Mesh, - Mesh, - Self::Result, - ) { + ) -> MeshGen { let mut light = calc_light(range, self); let mut lowest_opaque = range.size().d; @@ -315,180 +310,6 @@ impl<'a, V: RectRasterableVol + ReadVol + Debug> } .min(range.size().d - 1); - // // We use multiple meshes and then combine them later such that we can group - // similar z // levels together (better rendering performance) - // let mut opaque_meshes = vec![Mesh::new(); ((z_end + 1 - z_start).clamped(1, - // 60) as usize / 10).max(1)]; - // let mut opaque_mesh = Mesh::new(); - // let mut fluid_mesh = Mesh::new(); - - /* for x in 1..range.size().w - 1 { - for y in 1..range.size().w - 1 { - let mut blocks = [[[None; 3]; 3]; 3]; - for i in 0..3 { - for j in 0..3 { - for k in 0..3 { - blocks[k][j][i] = Some(flat_get( - Vec3::new(x, y, z_start) + Vec3::new(i as i32, j as i32, k as i32) - - 1, - )); - } - } - } - - let mut lights = [[[None; 3]; 3]; 3]; - for i in 0..3 { - for j in 0..3 { - for k in 0..3 { - lights[k][j][i] = if blocks[k][j][i] - .map(|block| block.is_opaque()) - .unwrap_or(false) - { - None - } else { - Some(light( - Vec3::new( - x + range.min.x, - y + range.min.y, - z_start + range.min.z, - ) + Vec3::new(i as i32, j as i32, k as i32) - - 1, - )) - }; - } - } - } - - let get_color = |maybe_block: Option<&Block>, neighbour: bool| { - maybe_block - .filter(|vox| vox.is_opaque() && (!neighbour || vox.is_blended())) - .and_then(|vox| vox.get_color()) - .map(Rgba::from_opaque) - .unwrap_or(Rgba::zero()) - }; - - for z in z_start..z_end + 1 { - let pos = Vec3::new(x, y, z); - let offs = (pos - Vec3::new(1, 1, -range.min.z)).map(|e| e as f32); - - lights[0] = lights[1]; - lights[1] = lights[2]; - blocks[0] = blocks[1]; - blocks[1] = blocks[2]; - - for i in 0..3 { - for j in 0..3 { - let block = Some(flat_get(pos + Vec3::new(i as i32, j as i32, 2) - 1)); - blocks[2][j][i] = block; - } - } - for i in 0..3 { - for j in 0..3 { - lights[2][j][i] = if blocks[2][j][i] - .map(|block| block.is_opaque()) - .unwrap_or(false) - { - None - } else { - Some(light( - pos + range.min + Vec3::new(i as i32, j as i32, 2) - 1, - )) - }; - } - } - - let block = blocks[1][1][1]; - let colors = if block.map_or(false, |vox| vox.is_blended()) { - let mut colors = [[[Rgba::zero(); 3]; 3]; 3]; - for i in 0..3 { - for j in 0..3 { - for k in 0..3 { - colors[i][j][k] = get_color( - blocks[i][j][k].as_ref(), - i != 1 || j != 1 || k != 1, - ) - } - } - } - colors - } else { - [[[get_color(blocks[1][1][1].as_ref(), false); 3]; 3]; 3] - }; - - // let opaque_mesh_index = ((z - z_start) * opaque_meshes.len() as i32 / (z_end - // + 1 - z_start).max(1)) as usize; let selected_opaque_mesh - // = &mut opaque_meshes[opaque_mesh_index]; Create mesh - // polygons - /* if block.map_or(false, |vox| vox.is_opaque()) { - vol::push_vox_verts( - &mut opaque_mesh, //selected_opaque_mesh, - faces_to_make(&blocks, None, |vox| { - if vox.is_opaque() { - None - } else { - Some(vox.is_fluid()) - } - }), - offs, - &colors, - |pos, norm, col, light, ao, &meta| { - //let light = (light.min(ao) * 255.0) as u32; - let light = (light * 255.0) as u32; - let ao = (ao * 255.0) as u32; - let norm = if norm.x != 0.0 { - if norm.x < 0.0 { 0 } else { 1 } - } else if norm.y != 0.0 { - if norm.y < 0.0 { 2 } else { 3 } - } else { - if norm.z < 0.0 { 4 } else { 5 } - }; - TerrainVertex::new(norm, light, ao, pos, col, meta) - }, - &lights, - ); - } else */if block.map_or(false, |vox| vox.is_fluid()) { - vol::push_vox_verts( - &mut fluid_mesh, - // NOTE: want to skip blocks that aren't either next to air, or next to - // opaque blocks like ground. Addnig the blocks next to ground lets us - // make sure we compute lighting effects both at the water surface, and - // just before hitting the ground. - faces_to_make(&blocks, Some(()), |vox| { - if vox.is_air() { Some(()) } else { None } - }), - offs, - &colors, - |pos, norm, col, light, _ao, _meta| { - /* let rel_pos = pos - offs; - let rel_vox_pos = if rel_pos == offs { - rel_pos + norm + 1.0 - } else { - rel_pos + 1.0 - }.map(|e| e as usize); - let vox_neighbor = blocks[rel_vox_pos.z][rel_vox_pos.y][rel_vox_pos.x]; - if vox_neighbor.is_opaque() { - } else { - } */ - FluidVertex::new(pos, norm, col, light, 0.3) - }, - &lights, - ); - } - } - } - }*/ - - // let opaque_mesh = opaque_meshes - // .into_iter() - // .rev() - // .fold(Mesh::new(), |mut opaque_mesh, m: Mesh| { - // m.verts().chunks_exact(3).rev().for_each(|vs| { - // opaque_mesh.push(vs[0]); - // opaque_mesh.push(vs[1]); - // opaque_mesh.push(vs[2]); - // }); - // opaque_mesh - // }); let max_size = guillotiere::Size::new(i32::from(max_texture_size.x), i32::from(max_texture_size.y)); let greedy_size = Vec3::new( @@ -508,8 +329,6 @@ impl<'a, V: RectRasterableVol + ReadVol + Debug> should_draw_greedy(pos, delta, flat_get) }; // NOTE: Conversion to f32 is fine since this i32 is actually in bounds for u16. - // let create_shadow = |pos, norm, meta| ShadowVertex::new(pos + Vec3::new(0.0, - // 0.0, (z_start + range.min.z) as f32), norm, meta); let mesh_delta = Vec3::new(0.0, 0.0, (z_start + range.min.z) as f32); let create_opaque = |atlas_pos, pos, norm, meta| { TerrainVertex::new(atlas_pos, pos + mesh_delta, norm, meta) @@ -560,7 +379,6 @@ impl<'a, V: RectRasterableVol + ReadVol + Debug> max: bounds.max + mesh_delta, }; let (col_lights, col_lights_size) = greedy.finalize(); - // println!("z_bounds{:?}, bounds: {:?}", (mesh_delta.z, mesh_delta.z + ( opaque_mesh, @@ -576,10 +394,8 @@ fn should_draw_greedy( delta: Vec3, flat_get: impl Fn(Vec3) -> Block, ) -> Option<(bool, FaceKind)> { - // TODO: Verify conversion. - // let pos = pos.map(|e| e as i32) + draw_delta; // - delta; - let from = flat_get(pos - delta); // map(|v| v.is_opaque()).unwrap_or(false); - let to = flat_get(pos); //map(|v| v.is_opaque()).unwrap_or(false); + let from = flat_get(pos - delta); + let to = flat_get(pos); let from_opaque = from.is_opaque(); if from_opaque == to.is_opaque() { // Check the interface of fluid and non-tangible non-fluids (e.g. air). diff --git a/voxygen/src/render/consts.rs b/voxygen/src/render/consts.rs index 3d5d579f2c..1e410d3179 100644 --- a/voxygen/src/render/consts.rs +++ b/voxygen/src/render/consts.rs @@ -17,15 +17,6 @@ impl Consts { } } - /* /// Create a new immutable `Const`. - pub fn new_immutable(factory: &mut gfx_backend::Factory, data: &[T]) -> Result, RenderError> { - Ok(Self { - ibuf: factory - .create_buffer_immutable_raw(gfx::memory::cast_slice(data), core::mem::size_of::(), gfx::buffer::Role::Constant, gfx::memory::Bind::empty()) - .map_err(|err| RenderError::BufferCreationError(err))?, - }) - } */ - /// Update the GPU-side value represented by this constant handle. pub fn update( diff --git a/voxygen/src/render/mesh.rs b/voxygen/src/render/mesh.rs index fc19781c3c..0d4a0d2165 100644 --- a/voxygen/src/render/mesh.rs +++ b/voxygen/src/render/mesh.rs @@ -4,7 +4,6 @@ use std::iter::FromIterator; /// A `Vec`-based mesh structure used to store mesh data on the CPU. pub struct Mesh { verts: Vec, - // textures: Vec<> } impl Clone for Mesh

diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 2a87702811..b8bd57f66b 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -21,7 +21,7 @@ pub use self::{ Locals as FigureLocals, }, fluid::FluidPipeline, - lod_terrain::{Locals as LodTerrainLocals, LodTerrainPipeline}, + lod_terrain::{Locals as LodTerrainLocals, LodData, LodTerrainPipeline}, postprocess::{ create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline, }, @@ -33,7 +33,7 @@ pub use self::{ create_quad as create_ui_quad, create_tri as create_ui_tri, Locals as UiLocals, Mode as UiMode, UiPipeline, }, - Globals, Light, Shadow, + GlobalModel, Globals, Light, Shadow, }, renderer::{ ColLightFmt, ColLightInfo, LodAltFmt, LodColorFmt, LodTextureFmt, Renderer, diff --git a/voxygen/src/render/pipelines/figure.rs b/voxygen/src/render/pipelines/figure.rs index aac7daf33a..a81a3455c9 100644 --- a/voxygen/src/render/pipelines/figure.rs +++ b/voxygen/src/render/pipelines/figure.rs @@ -119,7 +119,6 @@ impl Pipeline for FigurePipeline { pub struct FigureModel { pub bounds: Aabb, pub opaque: Model, - // pub shadow: Model, // TODO: Consider using mipmaps instead of storing multiple texture atlases for different LOD // levels. pub col_lights: Texture, diff --git a/voxygen/src/render/pipelines/fluid.rs b/voxygen/src/render/pipelines/fluid.rs index 73b67c7a46..a871aa3c4a 100644 --- a/voxygen/src/render/pipelines/fluid.rs +++ b/voxygen/src/render/pipelines/fluid.rs @@ -11,7 +11,6 @@ use vek::*; gfx_defines! { vertex Vertex { pos_norm: u32 = "v_pos_norm", - // col_light: u32 = "v_col_light", } pipeline pipe { @@ -41,31 +40,6 @@ gfx_defines! { } impl Vertex { - /* pub fn new(pos: Vec3, norm: Vec3, col: Rgb, light: f32, _opac: f32) -> Self { - let (norm_axis, norm_dir) = norm - .as_slice() - .into_iter() - .enumerate() - .find(|(_i, e)| **e != 0.0) - .unwrap_or((0, &1.0)); - let norm_bits = ((norm_axis << 1) | if *norm_dir > 0.0 { 1 } else { 0 }) as u32; - - const EXTRA_NEG_Z: f32 = 65536.0; - - Self { - pos_norm: 0 - | ((pos.x as u32) & 0x003F) << 0 - | ((pos.y as u32) & 0x003F) << 6 - | (((pos.z + EXTRA_NEG_Z).max(0.0).min((1 << 17) as f32) as u32) & 0x1FFFF) << 12 - | (norm_bits & 0x7) << 29, - col_light: 0 - | ((col.r.mul(200.0) as u32) & 0xFF) << 8 - | ((col.g.mul(200.0) as u32) & 0xFF) << 16 - | ((col.b.mul(200.0) as u32) & 0xFF) << 24 - | ((light.mul(255.0) as u32) & 0xFF) << 0, - //| ((opac.mul(0.4) as u32) & 0xFF) << 0, - } - } */ #[allow(clippy::identity_op)] // TODO: Pending review in #587 #[allow(clippy::into_iter_on_ref)] // TODO: Pending review in #587 pub fn new(pos: Vec3, norm: Vec3) -> Self { @@ -85,12 +59,6 @@ impl Vertex { | ((pos.y as u32) & 0x003F) << 6 | (((pos.z + EXTRA_NEG_Z).max(0.0).min((1 << 17) as f32) as u32) & 0x1FFFF) << 12 | (norm_bits & 0x7) << 29, - /* col_light: 0 - | ((col.r.mul(200.0) as u32) & 0xFF) << 8 - | ((col.g.mul(200.0) as u32) & 0xFF) << 16 - | ((col.b.mul(200.0) as u32) & 0xFF) << 24 - | ((light.mul(255.0) as u32) & 0xFF) << 0, - //| ((opac.mul(0.4) as u32) & 0xFF) << 0, */ } } } diff --git a/voxygen/src/render/pipelines/lod_terrain.rs b/voxygen/src/render/pipelines/lod_terrain.rs index e70e37808c..9003525dc5 100644 --- a/voxygen/src/render/pipelines/lod_terrain.rs +++ b/voxygen/src/render/pipelines/lod_terrain.rs @@ -1,10 +1,13 @@ use super::{ - super::{Pipeline, TgtColorFmt, TgtDepthStencilFmt}, + super::{ + LodAltFmt, LodColorFmt, LodTextureFmt, Pipeline, Renderer, Texture, TgtColorFmt, + TgtDepthStencilFmt, + }, Globals, }; use gfx::{ self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, - gfx_pipeline_inner, gfx_vertex_struct_meta, + gfx_pipeline_inner, gfx_vertex_struct_meta, texture::SamplerInfo, }; use vek::*; @@ -51,3 +54,64 @@ pub struct LodTerrainPipeline; impl Pipeline for LodTerrainPipeline { type Vertex = Vertex; } + +pub struct LodData { + pub map: Texture, + pub alt: Texture, + pub horizon: Texture, + pub tgt_detail: u32, +} + +impl LodData { + pub fn new( + renderer: &mut Renderer, + map_size: Vec2, + lod_base: &[u32], + lod_alt: &[u32], + lod_horizon: &[u32], + tgt_detail: u32, + border_color: gfx::texture::PackedColor, + ) -> Self { + let kind = gfx::texture::Kind::D2(map_size.x, map_size.y, gfx::texture::AaMode::Single); + let info = gfx::texture::SamplerInfo::new( + gfx::texture::FilterMethod::Bilinear, + gfx::texture::WrapMode::Border, + ); + Self { + map: renderer + .create_texture_immutable_raw( + kind, + gfx::texture::Mipmap::Provided, + &[gfx::memory::cast_slice(lod_base)], + SamplerInfo { + border: border_color, + ..info + }, + ) + .expect("Failed to generate map texture"), + alt: renderer + .create_texture_immutable_raw( + kind, + gfx::texture::Mipmap::Provided, + &[gfx::memory::cast_slice(lod_alt)], + SamplerInfo { + border: [0.0, 0.0, 0.0, 0.0].into(), + ..info + }, + ) + .expect("Failed to generate alt texture"), + horizon: renderer + .create_texture_immutable_raw( + kind, + gfx::texture::Mipmap::Provided, + &[gfx::memory::cast_slice(lod_horizon)], + SamplerInfo { + border: [1.0, 0.0, 1.0, 0.0].into(), + ..info + }, + ) + .expect("Failed to generate horizon texture"), + tgt_detail, + } + } +} diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index 1ffd415595..ea7ba0600c 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -8,6 +8,7 @@ pub mod sprite; pub mod terrain; pub mod ui; +use super::Consts; use crate::scene::camera::CameraMode; use common::terrain::BlockKind; use gfx::{self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta}; @@ -25,9 +26,6 @@ gfx_defines! { cam_pos: [f32; 4] = "cam_pos", focus_off: [f32; 4] = "focus_off", focus_pos: [f32; 4] = "focus_pos", - /// NOTE: max_intensity is computed as the ratio between the brightest and least bright - /// intensities among all lights in the scene. - // hdr_ratio: [f32; 4] = "max_intensity", /// NOTE: view_distance.x is the horizontal view distance, view_distance.y is the LOD /// detail, view_distance.z is the /// minimum height over any land chunk (i.e. the sea level), and view_distance.w is the @@ -54,7 +52,6 @@ gfx_defines! { constant Light { pos: [f32; 4] = "light_pos", col: [f32; 4] = "light_col", - // proj: [[f32; 4]; 4] = "light_proj"; } constant Shadow { @@ -201,3 +198,11 @@ impl Shadow { impl Default for Shadow { fn default() -> Self { Self::new(Vec3::zero(), 0.0) } } + +// Global scene data spread across several arrays. +pub struct GlobalModel { + pub globals: Consts, + pub lights: Consts, + pub shadows: Consts, + pub shadow_mats: Consts, +} diff --git a/voxygen/src/render/pipelines/shadow.rs b/voxygen/src/render/pipelines/shadow.rs index 38756b5acf..2333de29b8 100644 --- a/voxygen/src/render/pipelines/shadow.rs +++ b/voxygen/src/render/pipelines/shadow.rs @@ -13,10 +13,7 @@ use vek::*; gfx_defines! { vertex Vertex { - // pos: [f32; 4] = "v_pos", pos_norm: u32 = "v_pos_norm", - // col_light: u32 = "v_col_light", - // atlas_pos: u32 = "v_atlas_pos", } constant Locals { @@ -26,17 +23,10 @@ gfx_defines! { pipeline pipe { // Terrain vertex stuff - vbuf: gfx::VertexBuffer = (), + vbuf: gfx::VertexBuffer = (), locals: gfx::ConstantBuffer = "u_locals", globals: gfx::ConstantBuffer = "u_globals", - // lights: gfx::ConstantBuffer = "u_lights", - // shadows: gfx::ConstantBuffer = "u_shadows", - - // alt: gfx::TextureSampler<[f32; 2]> = "t_map", - // horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", - - // noise: gfx::TextureSampler = "t_noise", // Shadow stuff light_shadows: gfx::ConstantBuffer = "u_light_shadows", @@ -45,23 +35,15 @@ gfx_defines! { fun: gfx::state::Comparison::Less, write: true, }, - // tgt_depth_stencil: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE,//,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), } pipeline figure_pipe { // Terrain vertex stuff - vbuf: gfx::VertexBuffer = (), + vbuf: gfx::VertexBuffer = (), locals: gfx::ConstantBuffer = "u_locals", bones: gfx::ConstantBuffer = "u_bones", globals: gfx::ConstantBuffer = "u_globals", - // lights: gfx::ConstantBuffer = "u_lights", - // shadows: gfx::ConstantBuffer = "u_shadows", - - // alt: gfx::TextureSampler<[f32; 2]> = "t_map", - // horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", - - // noise: gfx::TextureSampler = "t_noise", // Shadow stuff light_shadows: gfx::ConstantBuffer = "u_light_shadows", @@ -70,16 +52,11 @@ gfx_defines! { fun: gfx::state::Comparison::Less, write: true, }, - // tgt_depth_stencil: gfx::DepthTarget = gfx::preset::depth::LESS_WRITE,//,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), } } impl Vertex { - pub fn new( - pos: Vec3, - norm: Vec3, - meta: bool, /* , atlas_pos: Vec2 */ - ) -> Self { + pub fn new(pos: Vec3, norm: Vec3, meta: bool) -> Self { let norm_bits = if norm.x != 0.0 { if norm.x < 0.0 { 0 } else { 1 } } else if norm.y != 0.0 { @@ -89,10 +66,6 @@ impl Vertex { } else { 5 }; - // let ao = 0xFFu32; - // let light = 0xFFu32; - // let col = Rgb::new(1.0f32, 0.0, 0.0); - // let meta = true; const EXTRA_NEG_Z: f32 = 32768.0; @@ -103,23 +76,10 @@ impl Vertex { | (((pos + EXTRA_NEG_Z).z.max(0.0).min((1 << 16) as f32) as u32) & 0xFFFF) << 12 | if meta { 1 } else { 0 } << 28 | (norm_bits & 0x7) << 29, - /* atlas_pos: 0 - | ((atlas_pos.x as u32) & 0xFFFF) << 0 - | ((atlas_pos.y as u32) & 0xFFFF) << 16, */ - /* col_light: 0 - | (((col.r * 255.0) as u32) & 0xFF) << 8 - | (((col.g * 255.0) as u32) & 0xFF) << 16 - | (((col.b * 255.0) as u32) & 0xFF) << 24 - | (ao >> 6) << 6 - | ((light >> 2) & 0x3F) << 0, */ } } - pub fn new_figure( - pos: Vec3, - norm: Vec3, - /* col: Rgb, ao: f32, */ bone_idx: u8, - ) -> Self { + pub fn new_figure(pos: Vec3, norm: Vec3, bone_idx: u8) -> Self { let norm_bits = if norm.x.min(norm.y).min(norm.z) < 0.0 { 0 } else { @@ -133,10 +93,6 @@ impl Vertex { .reduce_bitor() | (((bone_idx & 0xF) as u32) << 27) | (norm_bits << 31), - // col: col - // .map2(Rgb::new(0, 8, 16), |e, shift| ((e * 255.0) as u32) << shift) - // .reduce_bitor(), - // ao_bone: (bone_idx << 2) | ((ao * 3.9999) as u8), } } @@ -172,7 +128,7 @@ impl ShadowPipeline { gfx::texture::AaMode::Single, ), gfx::texture::Mipmap::Provided, - &[&col_lights /* .raw_pixels() */], + &[&col_lights], gfx::texture::SamplerInfo::new( gfx::texture::FilterMethod::Bilinear, gfx::texture::WrapMode::Clamp, diff --git a/voxygen/src/render/pipelines/skybox.rs b/voxygen/src/render/pipelines/skybox.rs index 362f0cf66e..9d2b43be3a 100644 --- a/voxygen/src/render/pipelines/skybox.rs +++ b/voxygen/src/render/pipelines/skybox.rs @@ -29,7 +29,6 @@ gfx_defines! { tgt_color: gfx::RenderTarget = "tgt_color", tgt_depth_stencil: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_TEST, - // tgt_depth_stencil: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, // tgt_depth_stencil: gfx::DepthStencilTarget = (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), } } diff --git a/voxygen/src/render/pipelines/sprite.rs b/voxygen/src/render/pipelines/sprite.rs index 9281671d9d..4580212eb3 100644 --- a/voxygen/src/render/pipelines/sprite.rs +++ b/voxygen/src/render/pipelines/sprite.rs @@ -12,7 +12,6 @@ use vek::*; gfx_defines! { vertex Vertex { pos: [f32; 3] = "v_pos", - // pos_norm: u32 = "v_pos_norm", // Because we try to restrict terrain sprite data to a 128×128 block // we need an offset into the texture atlas. atlas_pos: u32 = "v_atlas_pos", @@ -40,21 +39,17 @@ gfx_defines! { inst_mat1: [f32; 4] = "inst_mat1", inst_mat2: [f32; 4] = "inst_mat2", inst_mat3: [f32; 4] = "inst_mat3", - // inst_mat: [[f32; 4]; 4] = "inst_mat", - // inst_col: [f32; 3] = "inst_col", inst_wind_sway: f32 = "inst_wind_sway", } pipeline pipe { vbuf: gfx::VertexBuffer = (), ibuf: gfx::InstanceBuffer = (), - // ibuf: gfx::/*handle::RawBuffer*/ConstantBuffer = "u_ibuf", col_lights: gfx::TextureSampler<[f32; 4]> = "t_col_light", locals: gfx::ConstantBuffer = "u_locals", // A sprite instance is a cross between a sprite and a terrain chunk. terrain_locals: gfx::ConstantBuffer = "u_terrain_locals", - // locals: gfx::ConstantBuffer = "u_locals", globals: gfx::ConstantBuffer = "u_globals", lights: gfx::ConstantBuffer = "u_lights", shadows: gfx::ConstantBuffer = "u_shadows", @@ -113,24 +108,16 @@ impl Vertex { // | if meta { 1 } else { 0 } << 28 // | (norm_bits & 0x7) << 29, pos: pos.into_array(), - /* col: col - .map2(Rgb::new(0, 8, 16), |e, shift| ((e * 255.0) as u32) << shift) - .reduce_bitor(), */ atlas_pos: 0 | ((atlas_pos.x as u32) & 0xFFFF) << 0 - | ((atlas_pos.y as u32) & 0xFFFF) << 16, /* | axis_bits & 3 */ - norm_ao: norm_bits, /* | (((ao * 3.9999) as u32) << 3) */ + | ((atlas_pos.y as u32) & 0xFFFF) << 16, + norm_ao: norm_bits, } } } impl Instance { - pub fn new( - mat: Mat4, - /* col: Rgb, */ wind_sway: f32, - pos: Vec3, - ori_bits: u8, - ) -> Self { + pub fn new(mat: Mat4, wind_sway: f32, pos: Vec3, ori_bits: u8) -> Self { const EXTRA_NEG_Z: i32 = 32768; let mat_arr = mat.into_col_arrays(); @@ -138,29 +125,19 @@ impl Instance { pos_ori: 0 | ((pos.x as u32) & 0x003F) << 0 | ((pos.y as u32) & 0x003F) << 6 - | (((pos + EXTRA_NEG_Z).z.max(0).min(1 << 16/* as f32*/) as u32) & 0xFFFF) << 12 - // | if meta { 1 } else { 0 } << 28 + | (((pos + EXTRA_NEG_Z).z.max(0).min(1 << 16) as u32) & 0xFFFF) << 12 | (u32::from(ori_bits) & 0x7) << 29, inst_mat0: mat_arr[0], inst_mat1: mat_arr[1], inst_mat2: mat_arr[2], inst_mat3: mat_arr[3], - // inst_mat: mat_arr, - // inst_col: col.into_array(), inst_wind_sway: wind_sway, } } } impl Default for Instance { - fn default() -> Self { - Self::new( - Mat4::identity(), - /* Rgb::broadcast(1.0), */ 0.0, - Vec3::zero(), - 0, - ) - } + fn default() -> Self { Self::new(Mat4::identity(), 0.0, Vec3::zero(), 0) } } impl Default for Locals { diff --git a/voxygen/src/render/pipelines/terrain.rs b/voxygen/src/render/pipelines/terrain.rs index 8984b4556b..3f92daeb2c 100644 --- a/voxygen/src/render/pipelines/terrain.rs +++ b/voxygen/src/render/pipelines/terrain.rs @@ -10,8 +10,6 @@ use vek::*; gfx_defines! { vertex Vertex { - // pos_norm: u32 = "v_pos_norm", - // col_light: u32 = "v_col_light", pos_norm: u32 = "v_pos_norm", atlas_pos: u32 = "v_atlas_pos", } @@ -23,8 +21,7 @@ gfx_defines! { } pipeline pipe { - vbuf: gfx::VertexBuffer = (), - // abuf: gfx::VertexBuffer = (), + vbuf: gfx::VertexBuffer = (), col_lights: gfx::TextureSampler<[f32; 4]> = "t_col_light", locals: gfx::ConstantBuffer = "u_locals", @@ -73,22 +70,10 @@ impl Vertex { atlas_pos: 0 | ((atlas_pos.x as u32) & 0xFFFF) << 0 | ((atlas_pos.y as u32) & 0xFFFF) << 16, - /* col_light: 0 - | (((col.r * 255.0) as u32) & 0xFF) << 8 - | (((col.g * 255.0) as u32) & 0xFF) << 16 - | (((col.b * 255.0) as u32) & 0xFF) << 24 - | (ao >> 6) << 6 - | ((light >> 2) & 0x3F) << 0, */ } } - pub fn new_figure( - // norm: Vec3, - atlas_pos: Vec2, - pos: Vec3, - norm: Vec3, - bone_idx: u8, - ) -> Self { + pub fn new_figure(atlas_pos: Vec2, pos: Vec3, norm: Vec3, bone_idx: u8) -> Self { let norm_bits = if norm.x.min(norm.y).min(norm.z) < 0.0 { 0 } else { @@ -113,57 +98,15 @@ impl Vertex { | ((atlas_pos.x as u32) & 0x7FFF) << 2 | ((atlas_pos.y as u32) & 0x7FFF) << 17 | axis_bits & 3, - /* col_light: 0 - | (((col.r * 255.0) as u32) & 0xFF) << 8 - | (((col.g * 255.0) as u32) & 0xFF) << 16 - | (((col.b * 255.0) as u32) & 0xFF) << 24 - | (ao >> 6) << 6 - | ((light >> 2) & 0x3F) << 0, */ } } - /* pub fn new( - norm_bits: u32, - light: u32, - ao: u32, - pos: Vec3, - col: Rgb, - meta: bool, - ) -> Self { - const EXTRA_NEG_Z: f32 = 32768.0; - - Self { - pos_norm: 0 - | ((pos.x as u32) & 0x003F) << 0 - | ((pos.y as u32) & 0x003F) << 6 - | (((pos + EXTRA_NEG_Z).z.max(0.0).min((1 << 16) as f32) as u32) & 0xFFFF) << 12 - | if meta { 1 } else { 0 } << 28 - | (norm_bits & 0x7) << 29, - col_light: 0 - | ((col.r.mul(255.0) as u32) & 0xFF) << 8 - | ((col.g.mul(255.0) as u32) & 0xFF) << 16 - | ((col.b.mul(255.0) as u32) & 0xFF) << 24 - | (ao >> 6) << 6 - | ((light >> 2) & 0x3F) << 0, - } - } */ - pub fn make_col_light( - light: /* u32 */ u8, - // ao: u32, - // col: Rgb, + light: u8, col: Rgb, ) -> <::Surface as gfx::format::SurfaceTyped>::DataType { - [ - col.r, //.mul(255.0) as u8, - col.g, //.mul(255.0) as u8, - col.b, //.mul(255.0) as u8, - light, - /* | (ao as u8 >> 6) << 6 - * | //((light as u8 >> 2) & 0x3F) << 0, - * | light */ - ] + [col.r, col.g, col.b, light] } pub fn with_bone_idx(self, bone_idx: u8) -> Self { @@ -187,5 +130,5 @@ impl Locals { pub struct TerrainPipeline; impl Pipeline for TerrainPipeline { - type Vertex = Vertex; //<::Surface as gfx::format::SurfaceTyped>::DataType; + type Vertex = Vertex; } diff --git a/voxygen/src/render/pipelines/ui.rs b/voxygen/src/render/pipelines/ui.rs index dc42f2ad94..aed98810dd 100644 --- a/voxygen/src/render/pipelines/ui.rs +++ b/voxygen/src/render/pipelines/ui.rs @@ -131,18 +131,6 @@ pub fn create_quad( v([l, b], [uv_l, uv_b]), v([r, b], [uv_r, uv_b]), ), - /* (true, true) | (false, false) => Quad::new( - v([l, t], [uv_l, uv_t]), - v([r, t], [uv_l, uv_b]), - v([r, b], [uv_r, uv_b]), - v([l, b], [uv_r, uv_t]), - ), - _ => Quad::new( - v([l, t], [uv_l, uv_t]), - v([l, b], [uv_l, uv_b]), - v([r, b], [uv_r, uv_b]), - v([r, t], [uv_r, uv_t]), - ) */ } } diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 488e427e42..a1b19bc47f 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -5,8 +5,8 @@ use super::{ mesh::Mesh, model::{DynamicModel, Model}, pipelines::{ - figure, fluid, lod_terrain, postprocess, shadow, skybox, sprite, terrain, ui, Globals, - Light, Shadow, + figure, fluid, lod_terrain, postprocess, shadow, skybox, sprite, terrain, ui, GlobalModel, + Globals, }, texture::Texture, AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode, @@ -49,13 +49,13 @@ pub type WinColorView = gfx::handle::RenderTargetView; /// Represents the format of LOD shadows. -pub type LodTextureFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Unorm); //[gfx::format::U8Norm; 4]; +pub type LodTextureFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Unorm); /// Represents the format of LOD altitudes. -pub type LodAltFmt = (gfx::format::R16_G16, gfx::format::Unorm); //[gfx::format::U8Norm; 4]; +pub type LodAltFmt = (gfx::format::R16_G16, gfx::format::Unorm); /// Represents the format of LOD map colors. -pub type LodColorFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb); //[gfx::format::U8Norm; 4]; +pub type LodColorFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb); /// Represents the format of greedy meshed color-light textures. pub type ColLightFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb); @@ -420,6 +420,9 @@ impl Renderer { } /// Create textures and views for shadow maps. + // This is a one-use type and the two halves are not guaranteed to remain identical, so we + // disable the type complexity lint. + #[allow(clippy::type_complexity)] fn create_shadow_views( factory: &mut gfx_device_gl::Factory, size: (u16, u16), @@ -457,7 +460,7 @@ impl Renderer { } }))?; - let levels = 1; //10; + let levels = 1; let two_size = vec2_result(size.map(|e| { u16::checked_next_power_of_two(e) .filter(|&e| e <= max_texture_size) @@ -501,67 +504,26 @@ impl Renderer { diag_size )) })?; - /* let color_cty = <::Channel as gfx::format::ChannelTyped - >::get_channel_type(); - let tgt_color_tex = factory.create_texture( - kind, - levels, - gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::RENDER_TARGET, - gfx::memory::Usage::Data, - Some(color_cty), - )?; - let tgt_color_res = factory.view_texture_as_shader_resource::( - &tgt_color_tex, - (0, levels - 1), - gfx::format::Swizzle::new(), - )?; - let tgt_color_view = factory.view_texture_as_render_target(&tgt_color_tex, 0, None)?; - - let depth_stencil_cty = <::Channel as gfx::format::ChannelTyped>::get_channel_type(); - let tgt_depth_stencil_tex = factory.create_texture( - kind, - levels, - gfx::memory::Bind::DEPTH_STENCIL, - gfx::memory::Usage::Data, - Some(depth_stencil_cty), - )?; - let tgt_depth_stencil_view = - factory.view_texture_as_depth_stencil_trivial(&tgt_depth_stencil_tex)?; */ let depth_stencil_cty = <::Channel as gfx::format::ChannelTyped>::get_channel_type(); let point_shadow_tex = factory .create_texture( - gfx::texture::Kind::/*CubeArray*/Cube( - /* max_two_size */ diag_two_size / 4, /* size * 2*//*, 32 */ - ), + gfx::texture::Kind::Cube(diag_two_size / 4), levels as gfx::texture::Level, gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, gfx::memory::Usage::Data, Some(depth_stencil_cty), - /* Some(<::Channel as - * gfx::format::ChannelTyped>::get_channel_type()), */ ) .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?; let point_tgt_shadow_view = factory .view_texture_as_depth_stencil::( &point_shadow_tex, - 0, // levels, - None, // Some(1), + 0, + None, gfx::texture::DepthStencilFlags::empty(), )?; - // let tgt_shadow_view = - // factory.view_texture_as_depth_stencil_trivial(&shadow_tex)?; - /* let tgt_shadow_res = factory.view_texture_as_shader_resource::( - &tgt_color_tex, - (0, levels - 1), - gfx::format::Swizzle::new(), - )?; */ - // let tgt_shadow_view = - // factory.view_texture_as_depth_stencil_trivial(&tgt_color_tex)?; - // let tgt_shadow_view = factory.view_texture_as_shader_resource(&tgt_color_tex, - // 0, None)?; let point_tgt_shadow_res = factory .view_texture_as_shader_resource::( &point_shadow_tex, @@ -569,21 +531,9 @@ impl Renderer { gfx::format::Swizzle::new(), )?; - /* println!( - "size: {:?}, two_size: {:?}, diag_size: {:?}, diag_two_size: {:?}", - size, two_size, diag_size, diag_two_size, - ); */ let directed_shadow_tex = factory .create_texture( - gfx::texture::Kind::D2( - /* size.x,// two_size.x,// 2 * size.x, - size.y,// two_size.y,// 2 * size.y, */ - diag_two_size, /* max_two_size*//*two_size.x */ - diag_two_size, /* max_two_size*//*two_size.y */ - /* 6*//*1, */ gfx::texture::AaMode::Single, - ), - // gfx::texture::Kind::D2Array(max_size/* * 2*/, max_size/* * 2*/, /*6*/1, - // gfx::texture::AaMode::Single), + gfx::texture::Kind::D2(diag_two_size, diag_two_size, gfx::texture::AaMode::Single), levels as gfx::texture::Level, gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, gfx::memory::Usage::Data, @@ -593,8 +543,8 @@ impl Renderer { let directed_tgt_shadow_view = factory .view_texture_as_depth_stencil::( &directed_shadow_tex, - 0, // levels, - None, // Some(1), + 0, + None, gfx::texture::DepthStencilFlags::empty(), )?; let directed_tgt_shadow_res = factory @@ -606,31 +556,14 @@ impl Renderer { let mut sampler_info = gfx::texture::SamplerInfo::new( gfx::texture::FilterMethod::Bilinear, - gfx::texture::WrapMode::Border, //Clamp, + // Lights should always be assumed to flood areas we can't see. + gfx::texture::WrapMode::Border, ); sampler_info.comparison = Some(Comparison::LessEqual); - // sampler_info.lod_bias = (-3.0).into(); - // sampler_info.lod_range = (1.into(), (levels - 1).into()); - // Point lights should clamp to whatever edge value there is. sampler_info.border = [1.0; 4].into(); let point_shadow_tex_sampler = factory.create_sampler(sampler_info); - /* // Directed lights should always be assumed to flood areas we can't see. - sampler_info.wrap_mode = (gfx::texture::WrapMode::Border, gfx::texture::WrapMode::Border, gfx::texture::WrapMode::Border); */ let directed_shadow_tex_sampler = factory.create_sampler(sampler_info); - /* let tgt_sun_res = factory.view_texture_as_depth_stencil::( - &shadow_tex, - 0, - Some(0), - gfx::texture::DepthStencilFlags::RO_DEPTH, - )?; - let tgt_moon_res = factory.view_texture_as_depth_stencil::( - &shadow_tex, - 0, - Some(1), - gfx::texture::DepthStencilFlags::RO_DEPTH, - )?; */ - Ok(( point_tgt_shadow_view, point_tgt_shadow_res, @@ -676,7 +609,6 @@ impl Renderer { // let directed_encoder = &mut shadow_map.directed_encoder; let directed_encoder = &mut self.encoder; directed_encoder.clear_depth(&shadow_map.directed_depth_stencil_view, 1.0); - // encoder.clear_stencil(&shadow_map.depth_stencil_view, 0); } } @@ -693,7 +625,6 @@ impl Renderer { // NOTE: Currently just fail silently rather than complain if the computer is on // a version lower than 3.2, where seamless cubemaps were introduced. if !device.get_info().is_version_supported(3, 2) { - // println!("whoops"); return; } @@ -719,7 +650,6 @@ impl Renderer { // and having depth clamping disabled won't cause undefined // behavior, just incorrect shadowing from objects behind the viewer. if !device.get_info().is_version_supported(3, 3) { - // println!("whoops"); return; } @@ -729,8 +659,6 @@ impl Renderer { // essentially always be safe regardless of the state of the OpenGL // context, so no further checks are needed. device.with_gl(|gl| { - // println!("gl.Enable(gfx_gl::DEPTH_CLAMP) = {:?}", - // gl.IsEnabled(gfx_gl::DEPTH_CLAMP)); if depth_clamp { gl.Enable(gfx_gl::DEPTH_CLAMP); } else { @@ -759,7 +687,7 @@ impl Renderer { } } - /// Perform all queued draw calls for shadows. + /// Perform all queued draw calls for global.shadows. pub fn flush_shadows(&mut self) { if !self.mode.shadow.is_map() { return; @@ -848,14 +776,6 @@ impl Renderer { Ok(consts) } - /* /// Create a raw set of constants with the provided values. - pub fn create_consts_immutable( - &mut self, - vals: &[T], - ) -> Result, RenderError> { - Consts::new_immutable(&mut self.factory, vals) - } */ - /// Update a set of constants with the provided values. pub fn update_consts( &mut self, @@ -865,25 +785,6 @@ impl Renderer { consts.update(&mut self.encoder, vals, 0) } - /* /// Update a set of shadow constants with the provided values. - pub fn update_shadow_consts( - &mut self, - consts: &mut Consts, - vals: &[T], - directed_offset: usize, - point_offset: usize, - ) -> Result<(), RenderError> { - if let Some(shadow_map) = self.shadow_map.as_mut() { - let directed_encoder = &mut shadow_map.directed_encoder; - consts.update(directed_encoder, &vals[directed_offset..point_offset], directed_offset)?; - let point_encoder = &mut shadow_map.point_encoder; - consts.update(point_encoder, &vals[point_offset..], point_offset) - } else { - // Fail silently if shadows aren't working in the first place. - Ok(()) - } - } */ - /// Create a new set of instances with the provided values. pub fn create_instances( &mut self, @@ -1004,22 +905,6 @@ impl Renderer { Texture::new_dynamic(&mut self.factory, dims.x, dims.y) } - /* /// Create a new greedy texture array (of color-lights). - pub fn create_greedy_texture( - &mut self, - kind: gfx::texture::Kind, - mipmap: gfx::texture::MipMap, - data: &[&[::DataType]], - sampler_info: gfx::texture::SamplerInfo, - ) -> Result, RenderError> - where - F::Surface: gfx::format::TextureSurface, - F::Channel: gfx::format::TextureChannel, - ::DataType: Copy, - { - Texture::new_immutable_raw(&mut self.factory, kind, mipmap, data, sampler_info) - } */ - /// Update a texture with the provided offset, size, and data. pub fn update_texture( &mut self, @@ -1082,10 +967,9 @@ impl Renderer { pub fn render_skybox( &mut self, model: &Model, - globals: &Consts, + global: &GlobalModel, locals: &Consts, - alt: &Texture, - horizon: &Texture, + lod: &lod_terrain::LodData, ) { self.encoder.draw( &gfx::Slice { @@ -1099,10 +983,10 @@ impl Renderer { &skybox::pipe::Data { vbuf: model.vbuf.clone(), locals: locals.buf.clone(), - globals: globals.buf.clone(), + globals: global.globals.buf.clone(), noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - alt: (alt.srv.clone(), alt.sampler.clone()), - horizon: (horizon.srv.clone(), horizon.sampler.clone()), + alt: (lod.alt.srv.clone(), lod.alt.sampler.clone()), + horizon: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, @@ -1114,16 +998,11 @@ impl Renderer { &mut self, model: &figure::FigureModel, _col_lights: &Texture, - globals: &Consts, + global: &GlobalModel, locals: &Consts, bones: &Consts, - lights: &Consts, - shadows: &Consts, - light_shadows: &Consts, - alt: &Texture, - horizon: &Texture, + lod: &lod_terrain::LodData, ) { - // return; let (point_shadow_maps, directed_shadow_maps) = if let Some(shadow_map) = &mut self.shadow_map { ( @@ -1144,8 +1023,6 @@ impl Renderer { }; let col_lights = &model.col_lights; let model = &model.opaque; - // let atlas_model = &model.opaque; - // let model = &model.shadow; self.encoder.draw( &gfx::Slice { @@ -1158,20 +1035,18 @@ impl Renderer { &self.figure_pipeline.pso, &figure::pipe::Data { vbuf: model.vbuf.clone(), - // abuf: atlas_model.vbuf.clone(), col_lights: (col_lights.srv.clone(), col_lights.sampler.clone()), - // col_lights: (alt.srv.clone(), alt.sampler.clone()), locals: locals.buf.clone(), - globals: globals.buf.clone(), + globals: global.globals.buf.clone(), bones: bones.buf.clone(), - lights: lights.buf.clone(), - shadows: shadows.buf.clone(), - light_shadows: light_shadows.buf.clone(), + lights: global.lights.buf.clone(), + shadows: global.shadows.buf.clone(), + light_shadows: global.shadow_mats.buf.clone(), point_shadow_maps, directed_shadow_maps, noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - alt: (alt.srv.clone(), alt.sampler.clone()), - horizon: (horizon.srv.clone(), horizon.sampler.clone()), + alt: (lod.alt.srv.clone(), lod.alt.sampler.clone()), + horizon: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, @@ -1183,15 +1058,12 @@ impl Renderer { &mut self, _model: &figure::FigureModel, _col_lights: &Texture, - _globals: &Consts, - _locals: &Consts, + _global: &GlobalModel, _bones: &Consts, - _lights: &Consts, - _shadows: &Consts, - _light_shadows: &Consts, - _alt: &Texture, - _horizon: &Texture, + _lod: &lod_terrain::LodData, + _locals: &Consts, ) { + // FIXME: Consider reenabling at some point. /* let (point_shadow_maps, directed_shadow_maps) = if let Some(shadow_map) = &mut self.shadow_map { ( @@ -1228,18 +1100,18 @@ impl Renderer { vbuf: model.vbuf.clone(), // abuf: atlas_model.vbuf.clone(), col_lights: (col_lights.srv.clone(), col_lights.sampler.clone()), - // col_lights: (alt.srv.clone(), alt.sampler.clone()), + // col_lights: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), locals: locals.buf.clone(), - globals: globals.buf.clone(), + globals: global.globals.buf.clone(), bones: bones.buf.clone(), - lights: lights.buf.clone(), - shadows: shadows.buf.clone(), - light_shadows: light_shadows.buf.clone(), + lights: global.lights.buf.clone(), + shadows: global.shadows.buf.clone(), + light_shadows: global.shadow_mats.buf.clone(), point_shadow_maps, directed_shadow_maps, noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - alt: (alt.srv.clone(), alt.sampler.clone()), - horizon: (horizon.srv.clone(), horizon.sampler.clone()), + alt: (lod.alt.srv.clone(), lod.alt.sampler.clone()), + horizon: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (0, 0) */), }, @@ -1251,14 +1123,10 @@ impl Renderer { &mut self, model: &figure::FigureModel, _col_lights: &Texture, - globals: &Consts, + global: &GlobalModel, locals: &Consts, bones: &Consts, - lights: &Consts, - shadows: &Consts, - light_shadows: &Consts, - alt: &Texture, - horizon: &Texture, + lod: &lod_terrain::LodData, ) { let (point_shadow_maps, directed_shadow_maps) = if let Some(shadow_map) = &mut self.shadow_map { @@ -1280,8 +1148,6 @@ impl Renderer { }; let col_lights = &model.col_lights; let model = &model.opaque; - // let atlas_model = &model.opaque; - // let model = &model.shadow; self.encoder.draw( &gfx::Slice { @@ -1294,20 +1160,18 @@ impl Renderer { &self.figure_pipeline.pso, &figure::pipe::Data { vbuf: model.vbuf.clone(), - // abuf: atlas_model.vbuf.clone(), col_lights: (col_lights.srv.clone(), col_lights.sampler.clone()), - // col_lights: (alt.srv.clone(), alt.sampler.clone()), locals: locals.buf.clone(), - globals: globals.buf.clone(), + globals: global.globals.buf.clone(), bones: bones.buf.clone(), - lights: lights.buf.clone(), - shadows: shadows.buf.clone(), - light_shadows: light_shadows.buf.clone(), + lights: global.lights.buf.clone(), + shadows: global.shadows.buf.clone(), + light_shadows: global.shadow_mats.buf.clone(), point_shadow_maps, directed_shadow_maps, noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - alt: (alt.srv.clone(), alt.sampler.clone()), - horizon: (horizon.srv.clone(), horizon.sampler.clone()), + alt: (lod.alt.srv.clone(), lod.alt.sampler.clone()), + horizon: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, @@ -1318,17 +1182,11 @@ impl Renderer { /// frame. pub fn render_terrain_chunk( &mut self, - // atlas_model: &Model, - // model: &Model, model: &Model, col_lights: &Texture, - globals: &Consts, + global: &GlobalModel, locals: &Consts, - lights: &Consts, - shadows: &Consts, - light_shadows: &Consts, - alt: &Texture, - horizon: &Texture, + lod: &lod_terrain::LodData, ) { let (point_shadow_maps, directed_shadow_maps) = if let Some(shadow_map) = &mut self.shadow_map { @@ -1361,20 +1219,18 @@ impl Renderer { &terrain::pipe::Data { vbuf: model.vbuf.clone(), // TODO: Consider splitting out texture atlas data into a separate vertex buffer, - // since we don't need it for things like shadows. - // abuf: atlas_model.vbuf.clone(), + // since we don't need it for things like global.shadows. col_lights: (col_lights.srv.clone(), col_lights.sampler.clone()), - // col_lights: (alt.srv.clone(), alt.sampler.clone()), locals: locals.buf.clone(), - globals: globals.buf.clone(), - lights: lights.buf.clone(), - shadows: shadows.buf.clone(), - light_shadows: light_shadows.buf.clone(), + globals: global.globals.buf.clone(), + lights: global.lights.buf.clone(), + shadows: global.shadows.buf.clone(), + light_shadows: global.shadow_mats.buf.clone(), point_shadow_maps, directed_shadow_maps, noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - alt: (alt.srv.clone(), alt.sampler.clone()), - horizon: (horizon.srv.clone(), horizon.sampler.clone()), + alt: (lod.alt.srv.clone(), lod.alt.sampler.clone()), + horizon: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, @@ -1386,14 +1242,9 @@ impl Renderer { pub fn render_shadow_point( &mut self, model: &Model, - // model: &Model, - globals: &Consts, + global: &GlobalModel, terrain_locals: &Consts, locals: &Consts, - /* lights: &Consts, - * shadows: &Consts, - * alt: &Texture, - * horizon: &Texture, */ ) { if !self.mode.shadow.is_map() { return; @@ -1420,18 +1271,11 @@ impl Renderer { // Terrain vertex stuff vbuf: model.vbuf.clone(), locals: terrain_locals.buf.clone(), - globals: globals.buf.clone(), - // lights: lights.buf.clone(), - // shadows: shadows.buf.clone(), - // noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - // alt: (alt.srv.clone(), alt.sampler.clone()), - // horizon: (horizon.srv.clone(), horizon.sampler.clone()), + globals: global.globals.buf.clone(), // Shadow stuff light_shadows: locals.buf.clone(), tgt_depth_stencil: shadow_map.point_depth_stencil_view.clone(), - /* tgt_depth_stencil: (self.shadow_depth_stencil_view.clone(), (1, 1)), - * shadow_tex: (self.shadow_res.clone(), self.shadow_sampler.clone()), */ }, ); } @@ -1440,15 +1284,10 @@ impl Renderer { /// the upcoming frame. pub fn render_terrain_shadow_directed( &mut self, - // model: &Model, model: &Model, - globals: &Consts, + global: &GlobalModel, terrain_locals: &Consts, locals: &Consts, - /* lights: &Consts, - * shadows: &Consts, - * alt: &Texture, - * horizon: &Texture, */ ) { if !self.mode.shadow.is_map() { return; @@ -1475,18 +1314,11 @@ impl Renderer { // Terrain vertex stuff vbuf: model.vbuf.clone(), locals: terrain_locals.buf.clone(), - globals: globals.buf.clone(), - // lights: lights.buf.clone(), - // shadows: shadows.buf.clone(), - // noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - // alt: (alt.srv.clone(), alt.sampler.clone()), - // horizon: (horizon.srv.clone(), horizon.sampler.clone()), + globals: global.globals.buf.clone(), // Shadow stuff light_shadows: locals.buf.clone(), tgt_depth_stencil: shadow_map.directed_depth_stencil_view.clone(), - /* tgt_depth_stencil: (self.shadow_depth_stencil_view.clone(), (1, 1)), - * shadow_tex: (self.shadow_res.clone(), self.shadow_sampler.clone()), */ }, ); } @@ -1495,16 +1327,11 @@ impl Renderer { /// the upcoming frame. pub fn render_figure_shadow_directed( &mut self, - // model: &Model, model: &figure::FigureModel, - globals: &Consts, + global: &GlobalModel, figure_locals: &Consts, bones: &Consts, locals: &Consts, - /* lights: &Consts, - * shadows: &Consts, - * alt: &Texture, - * horizon: &Texture, */ ) { if !self.mode.shadow.is_map() { return; @@ -1533,18 +1360,11 @@ impl Renderer { vbuf: model.vbuf.clone(), locals: figure_locals.buf.clone(), bones: bones.buf.clone(), - globals: globals.buf.clone(), - // lights: lights.buf.clone(), - // shadows: shadows.buf.clone(), - // noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - // alt: (alt.srv.clone(), alt.sampler.clone()), - // horizon: (horizon.srv.clone(), horizon.sampler.clone()), + globals: global.globals.buf.clone(), // Shadow stuff light_shadows: locals.buf.clone(), tgt_depth_stencil: shadow_map.directed_depth_stencil_view.clone(), - /* tgt_depth_stencil: (self.shadow_depth_stencil_view.clone(), (1, 1)), - * shadow_tex: (self.shadow_res.clone(), self.shadow_sampler.clone()), */ }, ); } @@ -1554,13 +1374,9 @@ impl Renderer { pub fn render_fluid_chunk( &mut self, model: &Model, - globals: &Consts, + global: &GlobalModel, locals: &Consts, - lights: &Consts, - shadows: &Consts, - light_shadows: &Consts, - alt: &Texture, - horizon: &Texture, + lod: &lod_terrain::LodData, waves: &Texture, ) { let (point_shadow_maps, directed_shadow_maps) = @@ -1594,14 +1410,14 @@ impl Renderer { &fluid::pipe::Data { vbuf: model.vbuf.clone(), locals: locals.buf.clone(), - globals: globals.buf.clone(), - lights: lights.buf.clone(), - shadows: shadows.buf.clone(), - light_shadows: light_shadows.buf.clone(), + globals: global.globals.buf.clone(), + lights: global.lights.buf.clone(), + shadows: global.shadows.buf.clone(), + light_shadows: global.shadow_mats.buf.clone(), point_shadow_maps, directed_shadow_maps, - alt: (alt.srv.clone(), alt.sampler.clone()), - horizon: (horizon.srv.clone(), horizon.sampler.clone()), + alt: (lod.alt.srv.clone(), lod.alt.sampler.clone()), + horizon: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), waves: (waves.srv.clone(), waves.sampler.clone()), tgt_color: self.tgt_color_view.clone(), @@ -1616,17 +1432,11 @@ impl Renderer { &mut self, model: &Model, col_lights: &Texture, - globals: &Consts, + global: &GlobalModel, terrain_locals: &Consts, locals: &Consts, - // instance_count: usize, - // instances: &Consts, instances: &Instances, - lights: &Consts, - shadows: &Consts, - light_shadows: &Consts, - alt: &Texture, - horizon: &Texture, + lod: &lod_terrain::LodData, ) { let (point_shadow_maps, directed_shadow_maps) = if let Some(shadow_map) = &mut self.shadow_map { @@ -1652,26 +1462,25 @@ impl Renderer { start: model.vertex_range().start, end: model.vertex_range().end, base_vertex: 0, - instances: Some((instances.count()/*instance_count*/ as u32, 0)), + instances: Some((instances.count() as u32, 0)), buffer: gfx::IndexBuffer::Auto, }, &self.sprite_pipeline.pso, &sprite::pipe::Data { vbuf: model.vbuf.clone(), ibuf: instances.ibuf.clone(), - // ibuf: instances.buf.clone(), col_lights: (col_lights.srv.clone(), col_lights.sampler.clone()), terrain_locals: terrain_locals.buf.clone(), locals: locals.buf.clone(), - globals: globals.buf.clone(), - lights: lights.buf.clone(), - shadows: shadows.buf.clone(), - light_shadows: light_shadows.buf.clone(), + globals: global.globals.buf.clone(), + lights: global.lights.buf.clone(), + shadows: global.shadows.buf.clone(), + light_shadows: global.shadow_mats.buf.clone(), point_shadow_maps, directed_shadow_maps, noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - alt: (alt.srv.clone(), alt.sampler.clone()), - horizon: (horizon.srv.clone(), horizon.sampler.clone()), + alt: (lod.alt.srv.clone(), lod.alt.sampler.clone()), + horizon: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, @@ -1683,11 +1492,9 @@ impl Renderer { pub fn render_lod_terrain( &mut self, model: &Model, - globals: &Consts, + global: &GlobalModel, locals: &Consts, - map: &Texture, - alt: &Texture, - horizon: &Texture, + lod: &lod_terrain::LodData, ) { self.encoder.draw( &gfx::Slice { @@ -1701,11 +1508,11 @@ impl Renderer { &lod_terrain::pipe::Data { vbuf: model.vbuf.clone(), locals: locals.buf.clone(), - globals: globals.buf.clone(), + globals: global.globals.buf.clone(), noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - map: (map.srv.clone(), map.sampler.clone()), - alt: (alt.srv.clone(), alt.sampler.clone()), - horizon: (horizon.srv.clone(), horizon.sampler.clone()), + map: (lod.map.srv.clone(), lod.map.sampler.clone()), + alt: (lod.alt.srv.clone(), lod.alt.sampler.clone()), + horizon: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, @@ -1926,13 +1733,6 @@ fn create_pipelines( ) .unwrap(); - /* let directed_shadow_geom = - &assets::load_watched::( - "voxygen.shaders.light-shadows-directed-geom", - shader_reload_indicator, - ) - .unwrap(); */ - let directed_shadow_frag = &assets::load_watched::( "voxygen.shaders.light-shadows-directed-frag", shader_reload_indicator, @@ -2094,8 +1894,7 @@ fn create_pipelines( .unwrap(), &include_ctx, gfx::state::CullFace::Back, - None, - // Some(gfx::state::Offset(2, /* 10 */ 0)), + None, // Some(gfx::state::Offset(2, 0)) ) { Ok(pipe) => Some(pipe), Err(err) => { @@ -2109,14 +1908,11 @@ fn create_pipelines( factory, shadow::pipe::new(), &terrain_directed_shadow_vert, - None, // &directed_shadow_geom, + None, &directed_shadow_frag, &include_ctx, gfx::state::CullFace::Back, - /* None, */ - /* Some(gfx::state::Offset(4, 10)), */ - None, - // Some(gfx::state::Offset(2, /*10*/1)), + None, // Some(gfx::state::Offset(2, 1)) ) { Ok(pipe) => Some(pipe), Err(err) => { @@ -2133,14 +1929,11 @@ fn create_pipelines( factory, shadow::figure_pipe::new(), &figure_directed_shadow_vert, - None, // &directed_shadow_geom, + None, &directed_shadow_frag, &include_ctx, gfx::state::CullFace::Back, - /* None, */ - /* Some(gfx::state::Offset(4, 10)), */ - /*Some(gfx::state::Offset(2, 1))*/None, - /* Some(gfx::state::Offset(2, 10)), */ + None, // Some(gfx::state::Offset(2, 1)) ) { Ok(pipe) => Some(pipe), Err(err) => { @@ -2230,14 +2023,14 @@ fn create_shadow_pipeline( // Second-depth shadow mapping: should help reduce z-fighting provided all objects // are "watertight" (every triangle edge is shared with at most one other // triangle); this *should* be true for Veloren. - cull_face: /*gfx::state::CullFace::Nothing*/match cull_face { - gfx::state::CullFace::Front => gfx::state::CullFace::Back, - gfx::state::CullFace::Back => gfx::state::CullFace::Front, - gfx::state::CullFace::Nothing => gfx::state::CullFace::Nothing, - }, + cull_face: match cull_face { + gfx::state::CullFace::Front => gfx::state::CullFace::Back, + gfx::state::CullFace::Back => gfx::state::CullFace::Front, + gfx::state::CullFace::Nothing => gfx::state::CullFace::Nothing, + }, method: gfx::state::RasterMethod::Fill, offset, - samples: None, // Some(gfx::state::MultiSample), + samples: None, }, pipe, )?, diff --git a/voxygen/src/render/texture.rs b/voxygen/src/render/texture.rs index e0733a4f06..1c4cb1fa50 100644 --- a/voxygen/src/render/texture.rs +++ b/voxygen/src/render/texture.rs @@ -139,8 +139,6 @@ where ) .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?; - // device.cleanup(); - let srv = factory .view_texture_as_shader_resource::(&tex, levels, swizzle) .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Resource(err)))?; diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index 7120af0d23..be3c600305 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -91,8 +91,6 @@ impl Camera { (_, Err(_)) => self.dist, } .max(0.0) - // .max(NEAR_PLANE) - // self.dist.max(0.0) }; self.dependents.view_mat = Mat4::::identity() diff --git a/voxygen/src/scene/figure/cache.rs b/voxygen/src/scene/figure/cache.rs index ad801989e4..24a1798f33 100644 --- a/voxygen/src/scene/figure/cache.rs +++ b/voxygen/src/scene/figure/cache.rs @@ -936,45 +936,49 @@ impl FigureModelCache { .unwrap_or_else(::default); let manifest_indicator = &mut self.manifest_indicator; - let mut make_model = |generate_mesh: for<'a> fn(&mut GreedyMesh<'a>, _, _) -> _| { - let mut greedy = FigureModel::make_greedy(); - let mut opaque = Mesh::new(); - let mut figure_bounds = Aabb { - min: Vec3::zero(), - max: Vec3::zero(), + let mut make_model = + |generate_mesh: for<'a> fn(&mut GreedyMesh<'a>, _, _) -> _| { + let mut greedy = FigureModel::make_greedy(); + let mut opaque = Mesh::new(); + let mut figure_bounds = Aabb { + min: Vec3::zero(), + max: Vec3::zero(), + }; + Self::bone_meshes( + body, + loadout, + character_state, + camera_mode, + manifest_indicator, + |segment, offset| generate_mesh(&mut greedy, segment, offset), + ) + .iter() + .enumerate() + .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm))) + .for_each( + |(i, (opaque_mesh, bounds))| { + opaque.push_mesh_map(opaque_mesh, |vert| { + vert.with_bone_idx(i as u8) + }); + figure_bounds.expand_to_contain(*bounds); + }, + ); + col_lights + .create_figure(renderer, greedy, (opaque, figure_bounds)) + .unwrap() }; - // let mut shadow = Mesh::new(); - Self::bone_meshes( - body, - loadout, - character_state, - camera_mode, - manifest_indicator, - |segment, offset| generate_mesh(&mut greedy, segment, offset), - ) - .iter() - // .zip(&mut figure_bounds) - .enumerate() - .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm))) - .for_each(|(i, (opaque_mesh/*, shadow_mesh*/, bounds)/*, bone_bounds*/)| { - // opaque.push_mesh_map(opaque_mesh, |vert| vert.with_bone_idx(i as u8)); - opaque.push_mesh_map(opaque_mesh, |vert| vert.with_bone_idx(i as u8)); - figure_bounds.expand_to_contain(*bounds); - // shadow.push_mesh_map(shadow_mesh, |vert| vert.with_bone_idx(i as u8)); - }); - col_lights.create_figure(renderer, greedy, (opaque/*, shadow*/, figure_bounds)).unwrap() - }; fn generate_mesh<'a>( greedy: &mut GreedyMesh<'a>, segment: Segment, offset: Vec3, ) -> BoneMeshes { - let (opaque, _, /*shadow*/_, bounds) = Meshable::::generate_mesh( - segment, - (greedy, offset, Vec3::one()), - ); - (opaque/*, shadow*/, bounds) + let (opaque, _, _, bounds) = + Meshable::::generate_mesh( + segment, + (greedy, offset, Vec3::one()), + ); + (opaque, bounds) } fn generate_mesh_lod_mid<'a>( @@ -983,11 +987,12 @@ impl FigureModelCache { offset: Vec3, ) -> BoneMeshes { let lod_scale = Vec3::broadcast(0.6); - let (opaque, _, /*shadow*/_, bounds) = Meshable::::generate_mesh( - segment.scaled_by(lod_scale), - (greedy, offset * lod_scale, Vec3::one() / lod_scale), - ); - (opaque/*, shadow*/, bounds) + let (opaque, _, _, bounds) = + Meshable::::generate_mesh( + segment.scaled_by(lod_scale), + (greedy, offset * lod_scale, Vec3::one() / lod_scale), + ); + (opaque, bounds) } fn generate_mesh_lod_low<'a>( @@ -997,11 +1002,12 @@ impl FigureModelCache { ) -> BoneMeshes { let lod_scale = Vec3::broadcast(0.3); let segment = segment.scaled_by(lod_scale); - let (opaque, _, /*shadow*/_, bounds) = Meshable::::generate_mesh( - segment, - (greedy, offset * lod_scale, Vec3::one() / lod_scale), - ); - (opaque/*, shadow*/, bounds) + let (opaque, _, _, bounds) = + Meshable::::generate_mesh( + segment, + (greedy, offset * lod_scale, Vec3::one() / lod_scale), + ); + (opaque, bounds) } ( diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 181837fef8..57bc888455 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -793,7 +793,7 @@ impl HumMainWeaponSpec { let tool_kind = if let Some(ItemKind::Tool(Tool { kind, .. })) = item_kind { kind } else { - return (Mesh::new() /* , Mesh::new() */, Aabb::default()); + return (Mesh::new(), Aabb::default()); }; let spec = match self.0.get(tool_kind) { diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 8e87b8c23b..cc503f9baf 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -8,8 +8,8 @@ use crate::{ ecs::comp::Interpolated, mesh::greedy::GreedyMesh, render::{ - BoneMeshes, ColLightFmt, Consts, FigureBoneData, FigureLocals, FigureModel, Globals, Light, - RenderError, Renderer, Shadow, ShadowLocals, ShadowPipeline, Texture, + BoneMeshes, ColLightFmt, Consts, FigureBoneData, FigureLocals, FigureModel, GlobalModel, + RenderError, Renderer, ShadowPipeline, Texture, }, scene::{ camera::{Camera, CameraMode, Dependents}, @@ -48,6 +48,9 @@ const DAMAGE_FADE_COEFFICIENT: f64 = 5.0; const MOVING_THRESHOLD: f32 = 0.7; const MOVING_THRESHOLD_SQR: f32 = MOVING_THRESHOLD * MOVING_THRESHOLD; +/// camera data, fiigure LOD render distance. +pub type CameraData<'a> = (&'a Camera, f32); + struct FigureMgrStates { character_states: HashMap>, quadruped_small_states: HashMap>, @@ -1996,12 +1999,9 @@ impl FigureMgr { renderer: &mut Renderer, state: &State, tick: u64, - globals: &Consts, - shadow_mats: &Consts, - is_daylight: bool, - _light_data: &[Light], - camera: &Camera, - figure_lod_render_distance: f32, + global: &GlobalModel, + (is_daylight, _light_data): super::LightData, + (camera, figure_lod_render_distance): CameraData, ) { let ecs = state.ecs(); @@ -2034,10 +2034,10 @@ impl FigureMgr { ) { renderer.render_figure_shadow_directed( model, - globals, + global, locals, bone_consts, - shadow_mats, + &global.shadow_mats, ); } }); @@ -2051,13 +2051,9 @@ impl FigureMgr { state: &State, player_entity: EcsEntity, tick: u64, - globals: &Consts, - lights: &Consts, - shadows: &Consts, - shadow_mats: &Consts, + global: &GlobalModel, lod: &LodData, - camera: &Camera, - figure_lod_render_distance: f32, + (camera, figure_lod_render_distance): CameraData, ) { let ecs = state.ecs(); @@ -2096,14 +2092,10 @@ impl FigureMgr { renderer.render_figure( model, &col_lights.col_lights, - globals, + global, locals, bone_consts, - lights, - shadows, - shadow_mats, - &lod.alt, - &lod.horizon, + lod, ); } } @@ -2117,13 +2109,9 @@ impl FigureMgr { state: &State, player_entity: EcsEntity, tick: u64, - globals: &Consts, - lights: &Consts, - shadows: &Consts, - shadow_mats: &Consts, + global: &GlobalModel, lod: &LodData, - camera: &Camera, - figure_lod_render_distance: f32, + (camera, figure_lod_render_distance): CameraData, ) { let ecs = state.ecs(); @@ -2160,26 +2148,18 @@ impl FigureMgr { renderer.render_player( model, &col_lights.col_lights, - globals, + global, locals, bone_consts, - lights, - shadows, - shadow_mats, - &lod.alt, - &lod.horizon, + lod, ); renderer.render_player_shadow( model, &col_lights.col_lights, - globals, - locals, + global, bone_consts, - lights, - shadows, - shadow_mats, - &lod.alt, - &lod.horizon, + lod, + &global.shadow_mats, ); } } diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index 24f48d0397..01c80c73f0 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -1,89 +1,24 @@ use crate::{ render::{ - pipelines::lod_terrain::{Locals, Vertex}, - Consts, Globals, LodAltFmt, LodColorFmt, LodTerrainPipeline, LodTextureFmt, Mesh, Model, - Quad, Renderer, Texture, + pipelines::lod_terrain::{Locals, LodData, Vertex}, + Consts, GlobalModel, LodTerrainPipeline, Mesh, Model, Quad, Renderer, }, settings::Settings, }; use client::Client; use common::{spiral::Spiral2d, util::srgba_to_linear}; -use gfx::texture::SamplerInfo; use vek::*; -pub struct LodData { - pub map: Texture, - pub alt: Texture, - pub horizon: Texture, - pub tgt_detail: u32, -} - pub struct Lod { model: Option<(u32, Model)>, locals: Consts, data: LodData, } -impl LodData { - pub fn new( - renderer: &mut Renderer, - map_size: Vec2, - lod_base: &[u32], - lod_alt: &[u32], - lod_horizon: &[u32], - tgt_detail: u32, - border_color: gfx::texture::PackedColor, - ) -> Self { - let kind = gfx::texture::Kind::D2(map_size.x, map_size.y, gfx::texture::AaMode::Single); - let info = gfx::texture::SamplerInfo::new( - gfx::texture::FilterMethod::Bilinear, - gfx::texture::WrapMode::Border, - ); - Self { - map: renderer - .create_texture_immutable_raw( - kind, - gfx::texture::Mipmap::Provided, - &[gfx::memory::cast_slice(lod_base)], - SamplerInfo { - border: border_color, - ..info - }, - ) - .expect("Failed to generate map texture"), - alt: renderer - .create_texture_immutable_raw( - kind, - gfx::texture::Mipmap::Provided, - &[gfx::memory::cast_slice(lod_alt)], - SamplerInfo { - border: [0.0, 0.0, 0.0, 0.0].into(), - ..info - }, - ) - .expect("Failed to generate alt texture"), - horizon: renderer - .create_texture_immutable_raw( - kind, - gfx::texture::Mipmap::Provided, - &[gfx::memory::cast_slice(lod_horizon)], - SamplerInfo { - // filter: gfx::texture::FilterMethod::Nearest, - // filter: gfx::texture::FilterMethod::TriLinear, - border: [1.0, 0.0, 1.0, 0.0].into(), - ..info - }, - ) - .expect("Failed to generate horizon texture"), - tgt_detail, - } - } -} - // TODO: Make constant when possible. pub fn water_color() -> Rgba { /* Rgba::new(0.2, 0.5, 1.0, 0.0) */ - srgba_to_linear(Rgba::new(0.0, 0.25, 0.5, 0.0)/* * 0.5*/) + srgba_to_linear(Rgba::new(0.0, 0.25, 0.5, 0.0)) } impl Lod { @@ -123,16 +58,9 @@ impl Lod { } } - pub fn render(&self, renderer: &mut Renderer, globals: &Consts) { + pub fn render(&self, renderer: &mut Renderer, global: &GlobalModel) { if let Some((_, model)) = self.model.as_ref() { - renderer.render_lod_terrain( - &model, - globals, - &self.locals, - &self.data.map, - &self.data.alt, - &self.data.horizon, - ); + renderer.render_lod_terrain(&model, global, &self.locals, &self.data); } } } diff --git a/voxygen/src/scene/math.rs b/voxygen/src/scene/math.rs index 27047a132a..57c8476a1c 100644 --- a/voxygen/src/scene/math.rs +++ b/voxygen/src/scene/math.rs @@ -103,16 +103,6 @@ pub fn clip_points_by_plane + core::fmt::Deb plane: (Vec3, T), intersection_points: &mut Vec>, ) -> bool { - /* enum Intersection { - /// Previous point was inside the plane. - Inside, - /// Previous line segment was completely outside the plane. - Outside, - /// Previous line segment went from inside the plane to outside it. - InsideOut, - } */ - // println!("points@clip_points_by_plane before clipping by {:?}: {:?}", plane, - // points); if points.len() < 3 { return false; } @@ -135,36 +125,12 @@ pub fn clip_points_by_plane + core::fmt::Deb }; let last_is_outside = point_before_plane(current_point, plane); let mut is_outside = last_is_outside; - /* // Might not actually be total, but if it is partial and the point is inside it will be - // written regardless, and if it is partial and the point is outside, it means the - // second-to-last point is inside; thus, the second-to-last point will be written regardless, - // current_point will hold the new intersection point, and is_total will be false, when the - // loop ends; thus all we need to do to take this case into account is to push current_point - // onto the points vector if (is_total || is_outside) is false at the end of the loop. - let mut is_total = true; */ let mut old_points = Vec::with_capacity((3 * points.len()) / 2); mem::swap(&mut old_points, points); old_points.into_iter().for_each(|point| { - /* let prev_point = current_point; - // Swap point i with the previous point in the polygon, so it is the one we normally save - // when we return false. - mem::swap(&mut current_point, point); */ let prev_point = mem::replace(&mut current_point, point); - /* if point_before_plane(current_point) { - // If we are an outside point, we should only calculate an intersection if the previous - // point was inside. - if - is_outside s - // point was outside. - } else { - // If we are an inside point, then we should only calculate an intersection if the previous - // point was outside. - } */ let before_plane = point_before_plane(current_point, plane); let prev_is_outside = mem::replace(&mut is_outside, before_plane); - // println!("points@clip_points_by_plane clipping segment by {:?} (prev={:?} / - // outside={:?}, current={:?} / outside={:?})", plane, prev_point, - // prev_is_outside, current_point, is_outside); if !prev_is_outside { // Push previous point. points.push(prev_point); @@ -176,115 +142,7 @@ pub fn clip_points_by_plane + core::fmt::Deb points.push(intersection_point); } } - /* let prev_is_total = mem::replace( - &mut is_total, - // Save the intersection point only if we go from outside to inside or inside to - // outside, and definitely intersect the plane edge. - prev_is_outside != is_outside && - - .map(|intersection_point| { - intersection_points.push(intersection_point); - if prev_is_outside { - // If the previous point is outside, we know - *point = intersection_point; - } else { - // i o i o - // - // i o (2) - // i i/o o/i (3) - // - // i o i (3) - // i i/o o/i i (4) - // - // i o i o (4) - // i i/o o/i i i/o o/i (6) - // - // i o i o i (5) - // i i/o o/i i i/o o/i i (7) - // - // i o i o i o (6) - // i i/o o/i i i/o o/i i i/o o/i (9) - current_point = intersection_point; - } - false - }) - .is_none(), - ); - // Save the previous point if it is either inside, or has been replaced by an intersection - // point. - !prev_is_outside || prev_is_total - /* match (prev_is_outside, is_outside) { - (true, true) => { - prev_is_total - }, - (true, false) => { - // Outside to inside, so save the previous point only if it's been replaced by an - // intersection point. - do_intersection(); - prev_is_total - }, - (false, true) => { - // Inside to outside, so always save the previous point, and save the intersection - // point only if we definitively intersect the plane edge. - false - }, - (false, false) => { - // Both points inside the plane, so always save the previous point. - false - } - } */ */ }); - /* if !(is_total || is_outside) { - points.push(current_point); - } - /* match (before_plane, is_outside) { - (true, Previous::Outside) => { - - } - } - let cur_is_outside = { - if let Intersection::Inside = is_outside { - } else { - } - let prev_is_outside = mem::replace(&mut is_outside, { - let if let Intersection::Inside = is_outside { - true - } else { - false - } point_before_plane(current_point) { - }); - match (prev_is_outside, is_outside) { - (true, Some(is_outside)) => { - // Both points outside the plane, so save the previous point only if it's been - // replaced by an intersection point. - is_outside - }, - (true, false) => { - // Outside to inside, so calculate the intersection, and save it. - intersect_points.push(*point); - false - }, - (false, true) => { - // Inside to outside, so calculate the intersection, and save it and the current - // point. - intersect_points.push(*point); - false - }, - (false, false) => { - // Both points inside the plane, so save previous point - *point = * - false - } - } - if is_outside { - if prev_is_outside { - } else { - } - } else { - if prev_is_outside { - } - } - });*/ }*/ last_is_outside } @@ -338,11 +196,14 @@ fn append_intersection_points( // We use floating points rounded to tolerance in order to make our HashMap // lookups work. Otherwise we'd have to use a sorted structure, like a // btree, which wouldn't be the end of the world but would have - // theoretically worse complexity. NOTE: Definitely non-ideal that we - // panic if the rounded value can't fit in an i64... TODO: If necessary, - // let the caller specify how to hash these keys, since in cases where - // we know the kind of floating point we're using we can just cast to bits or - // something. + // theoretically worse complexity. + // + // NOTE: Definitely non-ideal that we panic if the rounded value can't fit in an + // i64... + // + // TODO: If necessary, let the caller specify how to hash these keys, since in + // cases where we know the kind of floating point we're using we can + // just cast to bits or something. point.map(|e| { (e * tol) .round() @@ -362,45 +223,17 @@ fn append_intersection_points( // than lines). (u_key != make_key(v)).then_some((u_key, v)) }); - // .map(|uv| (make_key(uv[0]), uv[1])) - if let Some((last_key, first)) = lines_iter.next() - /* [last, first, rest @ ..] = &*intersection_points = &*intersection_points */ - { + if let Some((last_key, first)) = lines_iter.next() { let lines = lines_iter.collect::>(); - /* if rest.len() < 4 { - // You need at least 3 sides for a polygon - return; - } - let lines = rest - .chunks_exact(2) - .filter_map(|uv| { - let u_key = make_key(uv[0]); - let v = uv[1]; - (u_key != make_key(v)).then_some((u_key, v)) - }) - // .map(|uv| (make_key(uv[0]), uv[1])) - .collect::>(); */ if lines.len() < 2 { // You need at least 3 sides for a polygon return; } - // println!("lines@append_intersection_points before merging points (last={:?}, - // cur={:?}): {:?}", last, cur, lines); - // let mut poly = Vec::with_capacity(lines.len() + 1); - // poly.push(first); // NOTE: Guaranteed to terminate, provided we have no cycles besides the one // that touches every point (which should be the case given how these // points were generated). - let /*mut */poly_iter = iter::successors(Some(first), |&cur| lines.get(&make_key(cur)).copied()); - /* poly.extend(poly_iter.next()); - // TODO: If we were smart and pre-tested whether (last, first) was a dup (guaranteeing we - // started on a non-dup), we would not need the take_while part. - poly.extend(poly_iter.take_while(|&cur| make_key(cur) != make_key(first))); - /* while let Some(&v) = lines.get(&make_key(cur)) { - cur = v; - poly.push(cur); - } */ */ + let poly_iter = iter::successors(Some(first), |&cur| lines.get(&make_key(cur)).copied()); let poly: Vec<_> = poly_iter.collect(); // We have to check to make sure we really went through the whole cycle. // TODO: Consider adaptively decreasing precision until we can make the cycle @@ -421,7 +254,6 @@ pub fn clip_object_by_plane + core::fmt::Deb polys.drain_filter(|points| { let len = intersection_points.len(); let outside_first = clip_points_by_plane(points, plane, &mut intersection_points); - // println!("points@clip_object_by_plane after clipping by {:?} (outside_first={:?}, intersection_points={:?}): {:?}", plane, outside_first, intersection_points, points); // Only remember intersections that are not coplanar with this side; i.e. those // that have segment length 2. if len + 2 != intersection_points.len() { @@ -444,8 +276,6 @@ pub fn clip_object_by_plane + core::fmt::Deb // Remove polygon if it was clipped away points.is_empty() }); - // println!("polys@clip_object_by_plane after clipping by {:?} (before appending - // interection points {:?}): {:?}", plane, intersection_points, polys); // Add a polygon of all intersection points with the plane to close out the // object. append_intersection_points(polys, intersection_points, tolerance); @@ -457,11 +287,8 @@ pub fn clip_object_by_aabb + core::fmt::Debu tolerance: T, ) { let planes = aabb_to_planes(bounds); - // println!("planes@clip_object_by_aabb: {:?}", planes); planes.iter().for_each(|&plane| { clip_object_by_plane(polys, plane, tolerance); - // println!("polys@clip_object_by_aabb (after clipping by {:?}): - // {:?}", plane, polys); }); } @@ -469,7 +296,6 @@ pub fn clip_object_by_aabb + core::fmt::Debu /// test plane. Otherwise 'None' is returned in which case the line /// segment is entirely clipped. pub fn clip_test(p: T, q: T, (u1, u2): (T, T)) -> Option<(T, T)> { - /* let res = */ if p == T::zero() { if q >= T::zero() { Some((u1, u2)) } else { None } } else { @@ -485,9 +311,7 @@ pub fn clip_test(p: T, q: T, (u1, u2): (T, T)) -> O } else { Some((u1, if r < u2 { r } else { u2 })) } - } /*; - // println!("clip_test@(p={:?}, q={:?}, (u1, u2)=({:?}. {:?})): - // res={:?}", p, q, u1, u2, res); res*/ + } } pub fn intersection_line_aabb + core::fmt::Debug>( @@ -495,9 +319,6 @@ pub fn intersection_line_aabb + core::fmt::D dir: Vec3, bounds: Aabb, ) -> Option> { - // println!("before@intersection_line_aabb: p={:?} dir={:?} bounds={:?}", p, - // dir, bounds); - /* let res = */ clip_test(-dir.z, p.z - bounds.min.z, (T::zero(), T::infinity())) .and_then(|t| clip_test(dir.z, bounds.max.z - p.z, t)) .and_then(|t| clip_test(-dir.y, p.y - bounds.min.y, t)) @@ -512,9 +333,7 @@ pub fn intersection_line_aabb + core::fmt::D } else { None } - }) /*; - //println!("after@intersection_line_aabb (p={:?} dir={:?} bounds={:?}): - // {:?}", p, dir, bounds, res); res */ + }) } pub fn include_object_light_volume< @@ -525,12 +344,12 @@ pub fn include_object_light_volume< light_dir: Vec3, bounds: Aabb, ) -> impl Iterator> { - /* obj.filter_map(move |pt| intersection_line_aabb(pt, -light_dir, bounds)) */ - // obj.map(move |pt| intersection_line_aabb(pt, -light_dir, - // bounds).unwrap_or(pt)) obj.flat_map(move |pt| iter::once(pt).chain(intersection_line_aabb(pt, -light_dir, bounds))) } +// NOTE: Currently specialized to skip extending to the end of the light ray, +// since our light ray is already infinite. Correct code is commented out +// below. pub fn calc_focused_light_volume_points + core::fmt::Debug>( inv_proj_view: Mat4, _light_dir: Vec3, @@ -538,13 +357,8 @@ pub fn calc_focused_light_volume_points + co tolerance: T, ) -> impl Iterator> { let world_pts = calc_view_frustum_world_coord(inv_proj_view); - // println!("world_pts: {:?}", world_pts); let mut world_frust_object = calc_view_frust_object(&world_pts); - // println!("world_frust_object: {:?}", world_frust_object); clip_object_by_aabb(&mut world_frust_object, scene_bounding_box, tolerance); - // println!("world_frust_object@clip_object_by_aabb: {:?}", world_frust_object); - /* let object_points = world_frust_object.into_iter().flat_map(|e| e.into_iter()); - object_points.clone().chain(include_object_light_volume(object_points, light_dir, scene_bounding_box)) */ world_frust_object.into_iter().flat_map(|e| e.into_iter()) /* include_object_light_volume( world_frust_object.into_iter().flat_map(|e| e.into_iter()), @@ -574,50 +388,4 @@ pub fn fit_psr< min: min.xyz(), max: max.xyz(), } - /* let mut make_p = |x: f32, y: f32, z: f32| -> Vec3 { - do_p(mat * Vec4::new(x, y, z, 1.0)) - }; - let p1 = make_p(bounds.min.x, bounds.min.y, bounds.min.z); - let p2 = make_p(bounds.max.x, bounds.min.y, bounds.min.z); - let p3 = make_p(bounds.min.x, bounds.max.y, bounds.min.z); - let p4 = make_p(bounds.max.x, bounds.max.y, bounds.min.z); - let p5 = make_p(bounds.min.x, bounds.min.y, bounds.max.z); - let p6 = make_p(bounds.max.x, bounds.min.y, bounds.max.z); - let p7 = make_p(bounds.min.x, bounds.max.y, bounds.max.z); - let p8 = make_p(bounds.max.x, bounds.max.y, bounds.max.z); - // let p1: Vec4 = mat * Vec4::new(bounds.min.x, bounds.min.y, bounds.min.z, 1.0); - // let p2: Vec4 = mat * Vec4::new(0.0, bounds.min.y, 0.0, 1.0); - // let p3: Vec4 = mat * Vec4::new(0.0, 0.0, bounds.min.z, 1.0); - // let p4: Vec4 = mat * Vec4::new(bounds.max.x, 0.0, 0.0, 1.0); - // let p5: Vec4 = mat * Vec4::new(0.0, bounds.max.y, 0.0, 1.0); - // let p6: Vec4 = mat * Vec4::new(bounds.max.x, bounds.max.y, bounds.max.z, 1.0); - // println!("p1 p6 {:?} {:?}", p1, p6); - // let xmin = p1.x.min(p6.x); - // let xmax = p1.x.max(p6.x); - // println!("p1 p2 p3 p4 p5 p6: {:?} {:?} {:?} {:?} {:?} {:?}", p1, p2, p3, p4, p5, p6); - let xmin = p1.x.min(p2.x.min(p3.x.min(p4.x.min(p5.x.min(p6.x.min(p7.x.min(p8.x))))))); - let xmax = p1.x.max(p2.x.max(p3.x.max(p4.x.max(p5.x.max(p6.x.max(p7.x.max(p8.x))))))); - // let xmin = p1.x.min(p2.x.min(p3.x.min(p4.x.min(p5.x.min(p6.x))))); - // let xmax = p1.x.max(p2.x.max(p3.x.max(p4.x.max(p5.x.max(p6.x))))); - // println!("xmin: {:?}, xmax: {:?}", xmin, xmax); - // let ymin = p1.y.min(p6.y); - // let ymax = p1.y.max(p6.y); - let ymin = p1.y.min(p2.y.min(p3.y.min(p4.y.min(p5.y.min(p6.y.min(p7.y.min(p8.y))))))); - let ymax = p1.y.max(p2.y.max(p3.y.max(p4.y.max(p5.y.max(p6.y.max(p7.y.max(p8.y))))))); - // println!("ymin: {:?}, ymax: {:?}", ymin, ymax); - - // let p1: Vec4 = view_mat * Vec4::new(scene_bounds.min.x, scene_bounds.min.y, scene_bounds.min.z, 1.0); - // let p2: Vec4 = view_mat * Vec4::new(0.0, scene_bounds.min.y, 0.0, 1.0); - // let p3: Vec4 = view_mat * Vec4::new(0.0, 0.0, scene_bounds.min.z, 1.0); - // let p4: Vec4 = view_mat * Vec4::new(scene_bounds.max.x, scene_bounds.max.y, scene_bounds.max.z, 1.0); - // let p5: Vec4 = view_mat * Vec4::new(0.0, scene_bounds.max.y, 0.0, 1.0); - // let p6: Vec4 = view_mat * Vec4::new(0.0, 0.0, scene_bounds.max.z, 1.0); - // println!("p1 p2 p3 p4 p5 p6: {:?} {:?} {:?} {:?} {:?} {:?}", p1, p2, p3, p4, p5, p6); - // println!("p1 p4 {:?} {:?}", p1, p4); - let zmin = p1.z.min(p2.z.min(p3.z.min(p4.z.min(p5.z.min(p6.z.min(p7.z.min(p8.z))))))); - let zmax = p1.z.max(p2.z.max(p3.z.max(p4.z.max(p5.z.max(p6.z.max(p7.z.max(p8.z))))))); - Aabb { - min: Vec3::new(xmin, ymin, zmin), - max: Vec3::new(xmax, ymax, zmax), - } */ } diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index c42365c46e..b7e543e201 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -8,14 +8,15 @@ pub mod terrain; use self::{ camera::{Camera, CameraMode}, figure::FigureMgr, - lod::{Lod, LodData}, + lod::Lod, terrain::Terrain, }; use crate::{ audio::{music::MusicMgr, sfx::SfxMgr, AudioFrontend}, render::{ - create_pp_mesh, create_skybox_mesh, Consts, Globals, Light, Model, PostProcessLocals, - PostProcessPipeline, Renderer, Shadow, ShadowLocals, SkyboxLocals, SkyboxPipeline, + create_pp_mesh, create_skybox_mesh, Consts, GlobalModel, Globals, Light, LodData, Model, + PostProcessLocals, PostProcessPipeline, Renderer, Shadow, ShadowLocals, SkyboxLocals, + SkyboxPipeline, }, settings::Settings, window::{AnalogGameInput, Event}, @@ -44,16 +45,16 @@ const SHADOW_MAX_DIST: f32 = 96.0; // The distance beyond which shadows may not /// The minimum sin γ we will use before switching to uniform mapping. const EPSILON_UPSILON: f64 = -1.0; -// const NEAR_PLANE: f32 = 0.5; -// const FAR_PLANE: f32 = 100000.0; - -const SHADOW_NEAR: f32 = 0.25; //1.0; //0.5;//1.0; // Near plane for shadow map rendering. -const SHADOW_FAR: f32 = 128.0; //100000.0;//128.0; //25.0; //100000.0;//25.0; // Far plane for shadow map rendering. +const SHADOW_NEAR: f32 = 0.25; // Near plane for shadow map point light rendering. +const SHADOW_FAR: f32 = 128.0; // Far plane for shadow map point light rendering. /// Above this speed is considered running /// Used for first person camera effects const RUNNING_THRESHOLD: f32 = 0.7; +/// is_daylight, array of active lights. +pub type LightData<'a> = (bool, &'a [Light]); + struct Skybox { model: Model, locals: Consts, @@ -65,10 +66,7 @@ struct PostProcess { } pub struct Scene { - globals: Consts, - lights: Consts, - shadow_mats: Consts, - shadows: Consts, + data: GlobalModel, camera: Camera, camera_input_state: Vec2, @@ -153,17 +151,7 @@ fn compute_scalar_fov(_near_plane: F, fov: F, aspect: F) -> F { let two = F::one() + F::one(); let theta_y = fov / two; let theta_x = (aspect * theta_y.tan()).atan(); - /* let h = (fov / two).tan().recip(); - let w = h / aspect; - let theta_y = (h / two).atan(); - let theta_x = (w / two).atan(); */ - /* // let theta_x = ((aspect * (fov / two).tan()).recip()/* / (two * near_plane)*/).atan(); - // let theta_y = ((fov / two).tan().recip()/* / (two * near_plane)*/).atan(); - let theta_x = ((aspect * (fov / two).tan()) / ).atan(); - let theta_y = ((fov / two).tan().recip()/* / (two * near_plane)*/).atan(); */ theta_x.min(theta_y) - // near_plane.recip().atan() - /* fov / two */ } /// Compute a near-optimal warping parameter that helps minimize error in a @@ -249,7 +237,7 @@ fn compute_warping_parameter_perspective( theta, theta + (three / ten) * (F::FRAC_PI_2() - theta), ), - (-two/*F::one()*/ / ten, F::zero()), + (-two / ten, F::zero()), ) } @@ -259,16 +247,18 @@ impl Scene { let resolution = renderer.get_resolution().map(|e| e as f32); Self { - globals: renderer.create_consts(&[Globals::default()]).unwrap(), - lights: renderer - .create_consts(&[Light::default(); MAX_LIGHT_COUNT]) - .unwrap(), - shadows: renderer - .create_consts(&[Shadow::default(); MAX_SHADOW_COUNT]) - .unwrap(), - shadow_mats: renderer - .create_consts(&[ShadowLocals::default(); MAX_LIGHT_COUNT * 6 + 6]) - .unwrap(), + data: GlobalModel { + globals: renderer.create_consts(&[Globals::default()]).unwrap(), + lights: renderer + .create_consts(&[Light::default(); MAX_LIGHT_COUNT]) + .unwrap(), + shadows: renderer + .create_consts(&[Shadow::default(); MAX_SHADOW_COUNT]) + .unwrap(), + shadow_mats: renderer + .create_consts(&[ShadowLocals::default(); MAX_LIGHT_COUNT * 6 + 6]) + .unwrap(), + }, camera: Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson), camera_input_state: Vec2::zero(), @@ -296,7 +286,7 @@ impl Scene { } /// Get a reference to the scene's globals. - pub fn globals(&self) -> &Consts { &self.globals } + pub fn globals(&self) -> &Consts { &self.data.globals } /// Get a reference to the scene's camera. pub fn camera(&self) -> &Camera { &self.camera } @@ -499,7 +489,7 @@ impl Scene { lights.sort_by_key(|light| light.get_pos().distance_squared(player_pos) as i32); lights.truncate(MAX_LIGHT_COUNT); renderer - .update_consts(&mut self.lights, &lights) + .update_consts(&mut self.data.lights, &lights) .expect("Failed to update light constants"); // Update shadow constants @@ -531,7 +521,7 @@ impl Scene { shadows.sort_by_key(|shadow| shadow.get_pos().distance_squared(player_pos) as i32); shadows.truncate(MAX_SHADOW_COUNT); renderer - .update_consts(&mut self.shadows, &shadows) + .update_consts(&mut self.data.shadows, &shadows) .expect("Failed to update light constants"); // Remember to put the new loaded distance back in the scene. @@ -544,7 +534,7 @@ impl Scene { // Update global constants. renderer - .update_consts(&mut self.globals, &[Globals::new( + .update_consts(&mut self.data.globals, &[Globals::new( view_mat, proj_mat, cam_pos, @@ -576,11 +566,7 @@ impl Scene { self.lod.maintain(renderer, time_of_day); // Maintain the terrain. - let ( - /* _scene_bounds, visible_bounds, _psc_bounds */ _visible_bounds, - visible_light_volume, - visible_psr_bounds, - ) = self.terrain.maintain( + let (_visible_bounds, visible_light_volume, visible_psr_bounds) = self.terrain.maintain( renderer, &scene_data, focus_pos, @@ -595,52 +581,11 @@ impl Scene { .maintain(renderer, scene_data, visible_psr_bounds, &self.camera); let sun_dir = scene_data.get_sun_dir(); - let is_daylight = sun_dir.z < 0.0/*0.6*/; + let is_daylight = sun_dir.z < 0.0; if renderer.render_mode().shadow.is_map() && (is_daylight || !lights.is_empty()) { - /* // We treat the actual scene bounds as being clipped by the horizontal terrain bounds, but - // expanded to contain the z values of all NPCs. This is potentially important to make - // sure we don't clip out figures in front of the camera. - let visible_bounds = Aabb { - min: Vec3::new(visible_bounds.min.x, visible_bounds.min.y, visible_bounds.min.z.min(figure_bounds.min.z)), - max: Vec3::new(visible_bounds.max.x, visible_bounds.max.y, visible_bounds.max.z.max(figure_bounds.max.z)), - }; */ - - // let focus_frac = focus_pos.map(|e| e.fract()); - /* let visible_bounds = math::Aabb:: { - min: math::Vec3::from(visible_bounds.min - focus_off), - max: math::Vec3::from(visible_bounds.max - focus_off), - }; - let visible_bounds_fine = math::Aabb { - min: visible_bounds.min.map(f64::from), - max: visible_bounds.max.map(f64::from), - }; - /* let visible_bounds = fit_psr(proj_mat * view_mat, visible_bounds, |p| (Vec3::from(p) / p.w)/*.map(|e| e.clamped(-1.0, 1.0))*/); - // clip bounding box points to positions that are actually visible. - // let visible_bounds_projected: aabb = fit_psr(proj_mat * view_mat, visible_bounds); - let inverse_visible: Mat4 = (proj_mat * view_mat - // .scaled_3d(vec3::new(proj_mat[(0, 0)], proj_mat[(1, 1)], 1.0)) - ).inverted();/* Mat4::identity();*/ - let visible_bounds = fit_psr(inverse_visible, visible_bounds, |p| Vec3::from(p) / p.w); */ - // let visible_pts = aabb_to_points(visible_bounds); - /* let scene_bounds = Aabb { - min: (scene_bounds.min - focus_off), - max: (scene_bounds.max - focus_off), - }; - let scene_bounds_fine = Aabb { - min: scene_bounds.min.map(f64::from), - max: scene_bounds.max.map(f64::from), - }; */ - let inv_proj_view = math::Mat4::from_col_arrays( - (proj_mat * view_mat/* * Mat4::translation_3d(-focus_off)*/).into_col_arrays(), - ) - .map(f64::from) - .inverted(); */ - let fov = self.camera.get_fov(); let aspect_ratio = self.camera.get_aspect_ratio(); - /* println!("view_mat: {:?}", view_mat); - println!("scene_bounds: {:?} visible_bounds: {:?}", scene_bounds, visible_bounds); */ let view_dir = ((focus_pos.map(f32::fract)) - cam_pos).normalized(); let (point_shadow_res, _directed_shadow_res) = renderer.get_shadow_resolution(); // NOTE: The aspect ratio is currently always 1 for our cube maps, since they @@ -649,29 +594,6 @@ impl Scene { // Construct matrices to transform from world space to light space for the sun // and moon. let directed_light_dir = math::Vec3::from(sun_dir); - /* let light_volume = calc_focused_light_volume_points(inv_proj_view, directed_light_dir.map(f64::from), scene_bounds_fine, 1e-3) - // .map(|e| e - focus_off) - // NOTE: Hopefully not out of bounds. - .map(|v| v.map(|e| e as f32)) - .collect::>(); - // println!("light_volume: {:?}", light_volume); */ - // let visible_light_volume = light_volume.clone(); - /* let visible_light_volume = math::calc_focused_light_volume_points(inv_proj_view, directed_light_dir.map(f64::from), visible_bounds_fine, 1e-6) - // .map(|e| e - focus_off) - // NOTE: Hopefully not out of bounds. - .map(|v| v.map(|e| e as f32)) - .collect::>(); */ - // println!("visible_light_volume: {:?}", visible_light_volume); - // let bounds0 = fit_psr(Mat4::identity()/* * inverse_visible*/, - // light_volume.iter().copied(), |p| Vec3::from(p) / p.w); - /* let light_volume = calc_focused_light_volume_points(inv_proj_view, directed_light_dir.map(f64::from), Aabb { - min: visible_bounds.min.map(f64::from), - max: visible_bounds.max.map(f64::from), - }, 1e-3) - // .map(|e| e - focus_off) - // NOTE: Hopefully not out of bounds. - .map(|v| v.map(|e| e as f32)) - .collect::>(); */ // First, add a projected matrix for our directed hard lights. // NOTE: This can be hard, so we should probably look at techniques for // restricting what's in the light frustum for things like sunlight @@ -681,7 +603,7 @@ impl Scene { // however, there is probably a much smarter way to do this. // NOTE: Multiplying by 1.5 as an approxmiation for √(2)/2, to make sure we // capture all chunks. - let radius = /*loaded_distance;// *//*/*scene_bounds*/scene_bounds.half_size().reduce_partial_max() * 1.5*/0.75/*bounds0/*scene_bounds*/.half_size().reduce_partial_max()*/; + let radius = 0.75; // Optimal warping for directed lights: // @@ -689,24 +611,8 @@ impl Scene { // // where n is near plane, f is far plane, y is the tilt angle between view and // light directon, and n_opt is the optimal near plane. - let directed_near = 1.0/*0.5*/; - let _directed_far = /*128.0*/directed_near + /*loaded_distance * 2.0*/2.0 * radius; - /* let directed_proj_mat = Mat4::orthographic_rh_no/*orthographic_without_depth_planes*/(FrustumPlanes { - // TODO: Consider adjusting resolution based on view distance. - left: -/*loaded_distance*/radius, - // left: -(directed_shadow_res.x as f32) / 2.0, - right: /*loaded_distance*/radius, - // right: directed_shadow_res.x as f32 / 2.0, - bottom: -/*loaded_distance*/radius, - // bottom: -(directed_shadow_res.y as f32) / 2.0, - top: /*loaded_distance*/radius, - // top: directed_shadow_res.y as f32 / 2.0, - // TODO: Swap fixed near and far planes for something dependent on the height of the - // current scene. - near: directed_near, - far: directed_far, - }); */ - // let directed_proj_mat = Mat4::identity(); + let directed_near = 1.0; + let _directed_far = directed_near + 2.0 * radius; // We also want a way to transform and scale this matrix (* 0.5 + 0.5) in order // to transform it correctly into texture coordinates, as well as // OpenGL coordinates. Note that the matrix for directional light @@ -716,648 +622,233 @@ impl Scene { // to the translated ones we use when multiplying by the light space // matrix; this helps avoid precision loss during the // multiplication. - - // let moon_dir = scene_data.get_moon_dir(); - // let moon_dir = Vec3::new(-angle_rad.sin(), 0.0, angle_rad.cos() - 0.5); - // Parallel light is aimed dead at the nearest integer to our focus position; if - // we were to offset by focus_off, it would be *at* our focus - // position, but using zero may result in less precision loss - // overall. NOTE: We could also try to use the offset of the - // *camera* position from the focus spot, to make shadows near the - // eye as sharp as possible. NOTE: If there's precision loss during - // the matrix *calcuation*, how much could be resolved by just using - // f64 in Rust for the computation, and switching to f32 afterwards - // just for the GPU? - // let look_at = bounds0.center();//Vec3::zero();// - // scene_bounds.center();//Vec3::zero(); let look_at = - // bounds0.center(); - let look_at = /*Vec3::zero()*/math::Vec3::from(cam_pos); // /*Vec3::zero()*/scene_bounds.center()/*cam_pos*/;// - focus_off;// focus_off; - let _light_scale = 1.5 * /*(directed_near + directed_far) / 2.0*/radius; + let look_at = math::Vec3::from(cam_pos); + let _light_scale = 1.5 * radius; // We upload view matrices as well, to assist in linearizing vertex positions. // (only for directional lights, so far). let mut directed_shadow_mats = Vec::with_capacity(6); let new_dir = math::Vec3::from(view_dir); - // let new_dir: math::Vec3::<_> = - // /*light_volume*/visible_light_volume.iter().copied().map(math::Vec3::from). - // map(|p| p - look_at).sum(); let new_dir = new_dir.normalized(); - /* let cos_gamma = f64::from(directed_light_dir.dot(new_dir)); - let sin_gamma = (1.0 - cos_gamma * cos_gamma).sqrt(); - // let sin_gamma = 0.0; - let new_dir = if /*sin_gamma > EPISLON_GAMMA*/factor > EPSILON_UPSILON { - new_dir - } else { - // For uniform mapping, align shadow map t axis with viewer's y axis to maximize - // utilization of the shadow map. - Vec3::from(view_mat * Vec4::from_direction(Vec3::up())) - .normalized() - }; */ - let up: math::Vec3 = { - /* (directed_light_dir) - .cross(new_dir) - .cross(directed_light_dir) - .normalized() */ - math::Vec3::up() - }; - // let up = Vec3::up(); - // let up: Vec3 = Vec3::from(Mat4::::look_at_rh(look_at - sun_dir, - // look_at, -Vec3::from(view_dir)) * Vec4::::forward_rh()); - // println!("bounds0: {:?}, scene_bounds: {:?}", bounds0, scene_bounds); + let up: math::Vec3 = math::Vec3::up(); directed_shadow_mats.push(math::Mat4::look_at_rh( look_at, look_at + directed_light_dir, - /* Vec3::up()*//*Vec3::from(view_dir)*//*up*//*Vec3::down() */ up, + up, )); - // directed_shadow_mats.push(Mat4::look_at_rh(look_at - sun_dir * light_scale, - // look_at, /*Vec3::up()*//*Vec3::from(view_dir)*//*up*//*Vec3::down()*/up)); - // directed_shadow_mats.push(Mat4::look_at_rh(look_at - moon_dir * light_scale, - // look_at, Vec3::up())); This leaves us with four dummy slots, - // which we push as defaults. + // This leaves us with five dummy slots, which we push as defaults. directed_shadow_mats .extend_from_slice(&[math::Mat4::default(); 6 - NUM_DIRECTED_LIGHTS] as _); // Now, construct the full projection matrices in the first two directed light // slots. let mut shadow_mats = Vec::with_capacity(6 * (lights.len() + 1)); - // let cam_pos = self.camera.dependents().cam_pos - focus_off; - /* let all_mat = /*proj_mat * */view_mat - .scaled_3d(Vec3::new(proj_mat[(0, 0)], proj_mat[(1, 1)], 1.0)); - let focus_off = focus_pos.map(|e| e.trunc()); */ - let z_n = 1.0; //f64::from(camera::NEAR_PLANE); + let z_n = 1.0; let _z_f = f64::from(camera::FAR_PLANE); - let _scalar_fov = /*f64::from(fov / 2.0)*/compute_scalar_fov(z_n, f64::from(fov), f64::from(aspect_ratio)); - shadow_mats.extend(directed_shadow_mats.iter().enumerate().map(move |(idx, &light_view_mat)| { - if idx >= NUM_DIRECTED_LIGHTS { - return ShadowLocals::new(Mat4::identity(), Mat4::identity()); - } - /* let visible_light_volume = { - let light_view_mat = light_view_mat.map(f64::from); - // (See http://www.songho.ca/opengl/gl_normaltransform.html) - // NOTE: What we really need here is the transpose of the matrix inverse: - // (M⁻¹)ᵀ - // - // where M is the light projection-view matrix. - // - // However, since we (hopefully) only have rotational transformations and - // transpositions for directional lights, and transpositions can be ignored by - // setting the w component of a vector to 0 (which is what we do when multiplying - // by the normal vector), we can treat M as an orthogonal matrix when multiplying - // by the normal. Thus the matrix inverse M⁻¹ can be treated as equal to its - // transpose Mᵀ, so the transpose of the inverse can be treated as equal to - // (Mᵀ)ᵀ = M for this purpose. - let inv_light_view_mat_transpose = light_view_mat; - let world_pts = calc_view_frustum_world_coord(light_view_mat * inv_proj_view); - // println!("world_pts: {:?}", world_pts); - let mut world_frust_object = calc_view_frust_object(&world_pts); - // println!("world_frust_object: {:?}", world_frust_object); - // clip_object_by_aabb(&mut world_frust_object, scene_bounding_box, tolerance); - { - let mut planes = aabb_to_planes(Aabb { - min: visible_bounds.min.map(f64::from), - max: visible_bounds.max.map(f64::from), - }); - /* let new_origin = light_view_mat * Vec4::unit_w(); - let new_origin = Vec3::from(new_origin) / new_origin.w; */ - planes.iter_mut().for_each(|plane| { - println!("old plane: {:?}", plane); - // NOTE: We may be able to simplify this to one matrix multiplication in - // this case (avoiding handling w separately) using the adjunction, but - // it's not clear whether it would be a performance win if it requires - // calculating the full matrix inverse. - let new_plane = inv_light_view_mat_transpose * Vec4::from_direction(plane.0); - /* let new_plane = light_view_mat * Vec4::new(plane.0.x, plane.0.y, plane.0.z, plane.1); */ - /* let new_plane = light_view_mat * Vec4::new(plane.0.x * plane.1, plane.0.y * plane.1, plane.0.z * plane.1, /*1.0*/0.0); */ - // We can easily find a point on the plane by multiplying the normal by the - // distance, and of course we only need to transform this point using the - // original matrix to find its new position. - let new_point = light_view_mat * Vec4::from_point(plane.0 * plane.1); - // NOTE: We currently assume no scaling, so length is 1.0. - let length: f64 = 1.0/*Vec3::from(new_plane).magnitude()*/; - let new_norm = Vec3::from(new_plane) / length; - // The new distance to the origin is the dot product of the transformed - // point on the plane's 3D coordinates, and the vector normal to the plane; - // this is because we have - // cos θ_new_point,new_norm = new_point ⋅ new_norm / (||origin|| ||new_norm||) - // = new_point ⋅ new_norm / ||origin|| - // ||origin|| cos θ_new_point,new_norm = new_point ⋅ new_norm - // which is exactly the projection of the vector from the origin to - // new_point onto the plane normal new_norm, i.e. the plane's distance - // from the origin. - *plane = (new_norm, Vec3::from(new_point).dot(new_norm)); - /* *plane = (Vec3::from(new_plane) / length, length); */ - /* let sgn = new_plane.w.signum(); - *plane = (sgn * Vec3::from(new_plane) / length, sgn * new_plane.w * length); */ - println!("new plane: {:?}", plane); - /* let new_plane = Vec3::from(light_view_mat * Vec4::from_direction(plane.0)); - *plane = (new_plane / new_plane.w, plane.1 / new_plane.w); */ - }); - // println!("planes@clip_object_by_aabb: {:?}", planes); - planes.iter().for_each(|&plane| { - clip_object_by_plane(&mut world_frust_object, plane, 1e-3); - // println!("polys@clip_object_by_aabb (after clipping by {:?}): {:?}", plane, polys); - }); + let _scalar_fov = compute_scalar_fov(z_n, f64::from(fov), f64::from(aspect_ratio)); + shadow_mats.extend(directed_shadow_mats.iter().enumerate().map( + move |(idx, &light_view_mat)| { + if idx >= NUM_DIRECTED_LIGHTS { + return ShadowLocals::new(Mat4::identity(), Mat4::identity()); } - world_frust_object.into_iter().flat_map(|e| e.into_iter()) - .map(|v| v.map(|e| e as f32)) - .collect::>() - // - // println!("world_frust_object@clip_object_by_aabb: {:?}", world_frust_object); - // include_object_light_volume(world_frust_object.into_iter().flat_map(|e| e.into_iter()), Vec3::forward_rh(), scene_bounding_box) - }; - println!("visible_light_volume: {:?}", visible_light_volume); */ - // let mut e_p: Vec4 = light_view_mat * Vec4::new(cam_pos.x, cam_pos.y, cam_pos.z, 1.0); - /* let mut v_p: Vec4 = /*directed_proj_mat * */light_view_mat * Vec4::from_direction(/*up*/new_dir);// Vec4::new(view_dir.x, view_dir.y, view_dir.z, 1.0); - // - // gluLookAt(e, p, y') / - // Mat4::look_at_rh(eye, target, up) / - // MathStuff::look(output, pos, dir, up) ~ Mat4::look_at_rh(pos, pos + dir, -up) - // - // eye point e = eye - // point p to look at = target - // up vector y' = up - // - // Let - // c = normalize(e - p) - // a = (y' × c) / ||y'|| = normalize(y' × c) - // b = c × a - // - // Then M_v = - // (a_x a_y a_z -(a⋅e) - // b_x b_y b_z -(b⋅e) - // c_x c_y c_z -(c⋅e) - // 0 0 0 1) - // - // c = -lightDir - // y' = -viewDir - // - // MathStuff::look(output, pos, dir, up) ~ Mat4::look_at_rh(pos, pos + dir, up): - // e = pos - // c = normalize(pos - (pos + dir)) = normalize(-dir) = -normalize(dir) = -dirN - // a = normalize(-up × c) = normalize(up × -normalize(dir)) = normalize(-(up × dir)) - // = normalize(dir × up) = lftN - // b = c × a = -normalize(dir) × lftN = normalize(-(dir × lftN)) - // = normalize(lftN × dir) = upN - // output = - // (lftN_x lftN_y lftN_z -(lftN⋅pos) - // upN_x upN_y upN_z -(upN⋅pos) - // -dirN_x -dirN_y -dirN_z dirN⋅pos - // 0 0 0 1) = - // (a_x a_y a_z -(a⋅e) - // b_x b_y b_z -(b⋅e) - // -(-c)_x -(-c)_y -(-c)_z (-c)⋅e - // 0 0 0 1) = - // (a_x a_y a_z -(a⋅e) - // b_x b_y b_z -(b⋅e) - // c_x c_y c_z -(c⋅e) - // 0 0 0 1) - // - let mut e_p: Vec3 = Vec3::zero(); - v_p.z = 0.0; */ - let v_p_orig = math::Vec3::from(light_view_mat * math::Vec4::from_direction(new_dir)); - let mut v_p = v_p_orig.normalized(); - // let cos_gamma = f64::from(v_p.z); - let cos_gamma = new_dir.map(f64::from).dot(directed_light_dir.map(f64::from)); - let sin_gamma = (1.0 - cos_gamma * cos_gamma).sqrt(); - let gamma = sin_gamma.asin()/*cos_gamma.acos()*/; - let view_mat = math::Mat4::from_col_array(view_mat.into_col_array()); - let bounds1 = math::fit_psr(view_mat.map_cols(math::Vec4::from), visible_light_volume.iter().copied(), math::Vec4::homogenized); - let n_e = f64::from(-bounds1.max.z); - // let f_e = f64::from(-bounds1.min.z); - // let fov = 2.0 * aspect_ratio * (fov / 2.0).tan(); - let factor = compute_warping_parameter_perspective(gamma, /*f64::from(camera::NEAR_PLANE)*/n_e, f64::from(/*fov*//*50.0.to_radians()*/fov/* / 2.0*/), f64::from(aspect_ratio)); - /* if v_p.z > 0.5 { - -1.0 - } else { - 0.0 - }; */ - /* let factor = if factor > 0.0 { - -1.0 - } else { - factor - };*/ - - v_p.z = 0.0; - v_p.normalize(); - let l_r: math::Mat4 = if /*v_p.magnitude_squared() > 1e-3*//*sin_gamma > EPISLON_GAMMA*/factor > EPSILON_UPSILON { - math::Mat4::look_at_rh(math::Vec3::zero(), math::Vec3::forward_rh(), v_p) - } else { - math::Mat4::identity() - }; - // let factor = -1.0; - // let l_r: Mat4 = Mat4::look_at_rh(/*Vec3::from(e_p) - Vec3::from(v_p)*//*Vec3::up()*/e_p, /*Vec3::from(e_p)*//*Vec3::zero()*/e_p + Vec3::forward_rh(), Vec3::from(v_p)); - // let l_r: Mat4 = Mat4::look_at_rh(/*Vec3::from(e_p) - Vec3::from(v_p)*//*Vec3::up()*/-Vec3::from(v_p), /*Vec3::from(e_p)*/Vec3::zero(), Vec3::back_rh()); - // let l_r: Mat4 = Mat4::identity();//Mat4::look_at_rh(/*Vec3::from(e_p) - Vec3::from(v_p)*//*Vec3::up()*/-Vec3::from(v_p), /*Vec3::from(e_p)*/Vec3::zero(), Vec3::back_rh()); - // let l_r: Mat4 = Mat4::look_at_rh(/*Vec3::from(e_p) - Vec3::from(v_p)*//*Vec3::up()*/-Vec3::from(v_p), /*Vec3::from(e_p)*/Vec3::zero(), Vec3::back_rh()); - // let l_r: Mat4 = Mat4::look_at_rh(Vec3::from(e_p) - Vec3::from(v_p), Vec3::from(e_p), Vec3::forward_rh()); - // let l_r: Mat4 = Mat4::look_at_rh(/*Vec3::from(e_p) - Vec3::from(v_p)*/Vec3::zero(), /*Vec3::from(e_p)*/-Vec3::forward_rh(), /*Vec3::up()*/-Vec3::from(v_p)); - // let l_r: Mat4 = Mat4::look_at_rh(/*Vec3::from(e_p) - Vec3::from(v_p)*/Vec3::back_rh(), /*Vec3::from(e_p)*/Vec3::zero(), /*Vec3::up()*/Vec3::from(v_p)); - // let l_r: Mat4 = Mat4::identity(); - /* let bounds0 = math::fit_psr(light_view_mat, visible_light_volume.iter().copied(), /*|p| math::Vec3::from(p) / p.w*/math::Vec4::homogenized); */ - let directed_proj_mat = /*math::Mat4::orthographic_rh_no(FrustumPlanes { - // TODO: Consider adjusting resolution based on view distance. - left: bounds0.min.x, - right: bounds0.max.x, - bottom: bounds0.min.y, - top: bounds0.max.y, - near: bounds0.min.z, - far: bounds0.max.z, - })*//* /Mat4::identity() */math::Mat4::new( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, -1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - ); - - let light_all_mat = l_r * directed_proj_mat * light_view_mat; - // let bounds1 = fit_psr(light_all_mat/* * inverse_visible*/, light_volume.iter().copied(), |p| Vec3::from(p) / p.w); - let bounds0 = math::fit_psr(/*l_r*/light_all_mat/* * inverse_visible*/, visible_light_volume.iter().copied(), /*|p| math::Vec3::from(p) / p.w*/math::Vec4::homogenized); - // Vague idea: project z_n from the camera view to the light view (where it's - // tilted by γ). - let (z_0, z_1) = { - let p_z = bounds1.max.z; - let p_y = bounds0.min.y; - let p_x = bounds0.center().x; - // println!("p_x (light near plane, s-axis) = {:?}, p_y (light xy plane, t-axis) = {:?}, p_z (near plane, z-axis) = {:?}", p_x, p_y, p_z); - let view_inv = view_mat.inverted(); - let light_all_inv = light_all_mat.inverted(); - - let view_point = view_inv * math::Vec4::new(0.0, 0.0, p_z, 1.0); - let view_plane = view_inv * math::Vec4::from_direction(math::Vec3::unit_z()); - - let light_point = light_all_inv * math::Vec4::new(0.0, p_y, 0.0, 1.0); - let light_plane = light_all_inv * math::Vec4::from_direction(math::Vec3::unit_y()); - - let shadow_point = light_all_inv * math::Vec4::new(p_x, 0.0, 0.0, 1.0); - let shadow_plane = light_all_inv * math::Vec4::from_direction(math::Vec3::unit_x()); - - let solve_p0 = math::Mat4::new( - view_plane.x, view_plane.y, view_plane.z, -view_plane.dot(view_point), - light_plane.x, light_plane.y, light_plane.z, -light_plane.dot(light_point), - shadow_plane.x, shadow_plane.y, shadow_plane.z, -shadow_plane.dot(shadow_point), - 0.0, 0.0, 0.0, 1.0, + let v_p_orig = + math::Vec3::from(light_view_mat * math::Vec4::from_direction(new_dir)); + let mut v_p = v_p_orig.normalized(); + let cos_gamma = new_dir + .map(f64::from) + .dot(directed_light_dir.map(f64::from)); + let sin_gamma = (1.0 - cos_gamma * cos_gamma).sqrt(); + let gamma = sin_gamma.asin(); + let view_mat = math::Mat4::from_col_array(view_mat.into_col_array()); + let bounds1 = math::fit_psr( + view_mat.map_cols(math::Vec4::from), + visible_light_volume.iter().copied(), + math::Vec4::homogenized, + ); + let n_e = f64::from(-bounds1.max.z); + let factor = compute_warping_parameter_perspective( + gamma, + n_e, + f64::from(fov), + f64::from(aspect_ratio), ); - // let _w_p_arr = solve_p0.cols.iter().map(|e| (e.x, e.y, e.z, e.w)).collect::>(); - // println!("mat4 solve_p0 = mat4(vec4{:?}, vec4{:?}, vec4{:?}, vec4{:?});", w_p_arr[0], w_p_arr[1], w_p_arr[2], w_p_arr[3]); - - let p0_world = solve_p0.inverted() * math::Vec4::unit_w(); - let p0 = light_all_mat * p0_world; - let mut p1 = p0; - p1.y = bounds0.max.y; - // println!("p0 = {:?}, p1 = {:?}", p0, p1); - - let view_from_light_mat = view_mat * light_all_inv; - let z0 = view_from_light_mat * p0; - let z1 = view_from_light_mat * p1; - // println!("z0 = {:?}, z1 = {:?}", z0, z1); - - (f64::from(z0.z), f64::from(z1.z)) - }; - - // let bounds1 = fit_psr(light_all_mat/* * inverse_visible*/, aabb_to_points(visible_bounds).iter().copied(), |p| Vec3::from(p) / p.w); - // let mut light_focus_pos: Vec3 = Vec3::from(light_all_mat * Vec4::from_point(focus_pos.map(f32::fract))); - let mut light_focus_pos: math::Vec3 = math::Vec3::zero()/*bounds0.center()*/;// l_r * directed_proj_mat * light_view_mat * Vec4::from_point(focus_pos.map(|e| e.fract())); - light_focus_pos.x = bounds0.center().x; - light_focus_pos.y = bounds0.min.y/*z_0 as f32*/; - light_focus_pos.z = bounds0.center().z; - // let mut light_focus_pos: Vec3 = bounds0.center();// l_r * directed_proj_mat * light_view_mat * Vec4::from_point(focus_pos.map(|e| e.fract())); - // println!("cam_pos: {:?}, focus_pos: {:?}, light_focus_pos: {:?}, v_p: {:?} bounds: {:?}, l_r: {:?}, light_view_mat: {:?}, light_all_mat: {:?}", cam_pos, focus_pos - focus_off, light_focus_pos, v_p, /*bounds1*/bounds0, l_r, light_view_mat, light_all_mat); - // let w_v = Mat4::translation_3d(-Vec3::new(xmax + xmin, ymax + ymin, /*zmax + zmin*/0.0) / 2.0); - - // let cos_gamma = /*new_dir*//*up_dir*/view_dir.map(f64::from).dot(directed_light_dir.map(f64::from)); - // let sin_gamma = (1.0 - cos_gamma * cos_gamma).sqrt();//.clamped(1e-1, 1.0); - // let sin_gamma = 0.0; - // let factor = -1.0;//1.0 / sin_gamma; - // println!("Warp factor for γ (sin γ = {:?}, γ = {:?}, near_plane = {:?}, fov = {:?}, scalar fov = {:?}, aspect ratio = {:?}): η = {:?}", sin_gamma, gamma.to_degrees(), camera::NEAR_PLANE, fov.to_degrees(), scalar_fov.to_degrees(), aspect_ratio, factor); - /* v ---l - \ Θ| - \| */ - - // let directed_near = /*0.5*//*0.25*/f64::from(camera::NEAR_PLANE);/*1.0*/;//bounds0.min.y.max(1.0); - // let z_n = /*f64::from(bounds0.min.y)*//*factor * *//*f64::from(*/directed_near/*)*/;// / /*sin_gamma*/scalar_fov.cos();// / sin_gamma; //often 1 - let d = f64::from(bounds0.max.y - bounds0.min.y/*directed_near*/).abs(); //perspective transform depth //light space y extents - // let z_f = z_n + d * camera::FAR_PLANE/* / scalar_fov.cos()*/; - // let z_0 = f64::from(bounds0.min.y); - - /* let v_p_orig: math::Vec3:: = math::Vec3::from(light_all_mat * math::Vec4::from_direction(new_dir)); - let n_e: f64 = /*bounds0.y.min() * scalar_fov.cos() *//*bounds0.min.y / scalar_fov.cos();*/f64::from(camera::NEAR_PLANE) * f64::from(v_p_orig.y); - let f_e = /*bounds0.size().y / scalar_fov.cos();*//*f64::from(camera::FAR_PLANE);*//*f64::from(camera::FAR_PLANE) * v_p_orig*/ - d - /*d * scalar_fov.cos()*/; - - // See Lloyd's thesis, section 5.2 (p. 104-105). - let w_e = 2.0 * n_e * scalar_fov.tan(); - - let w_n = w_e; - // let w_f = w_n * f_e / n_e; - let w_s = (f_e - n_e) / scalar_fov.cos(); - - let w_n_ = w_n * gamma.cos(); - let w_s_1_ = w_s * (1.0 - (scalar_fov - gamma).cos()); - let w_s_2_ = w_s * (scalar_fov - gamma).sin(); - - /* let w_l_y = w_n_ + w_s_2_ + if gamma < scalar_fov { - w_s_1_ - } else { - 0.0 - }; */ - let v_s_1 = if gamma < scalar_fov { - w_s_1_ / w_l_y - } else { - 0.0 - }; - let v_s_2 = v_s_1 + w_n_ / w_l_y; - let d_e = |v: f64| n_e + (f_e - n_e) * - (w_l_y * (v_s_1 - v) / w_s_1_) - .max(0.0) - .max(w_l_y * (1.0 - v) / w_s_2_); */ - - /* let w_l_x = (n_ + w_l_y) * if gamma < scalar_fov { - w_f / n_ - } else { - w_f / (n_ + w_s_1_) - }; */ - - /* let z_0 = /*z_n*//*z_n*/n_e/* / sin_gamma*/;// / sin_gamma;// / sin_gamma; - // let z_1 = z_0 + d; - // Vague idea: project d from the light view back to the camera view (undoing the - // tilt by γ). - let z_1 = /*z_n*/z_0/*n_e*/ + d * /*sin_gamma*/f64::from(v_p_orig.y)/* * sin_gamma*/; - // 1/φ' (zn + √(zn(zn + (f - n)φ'))) - // (f-n)/φ' (zn + √(zn(zn + (f - n)φ'))) - // zn/φ' (1 + zn√(1 + (f - n)φ' / zn)) */ - let w_l_y = /* z_f - z_n */d;/*/*f64::from(camera::FAR_PLANE - camera::NEAR_PLANE)*//*(z_f - z_n)*/d * scalar_fov.cos();*/ - // let z_f = z_n + d; - // let near_dist = directed_near; - // let factor = -1.0; - /* let factor = if factor == -1.0 { - -1.0 - } else { - 0.0 - }; */ - - // NOTE: See section 5.1.2.2 of Lloyd's thesis. - let alpha = z_1 / z_0/*z_f / z_n*/; - let alpha_sqrt = alpha.sqrt(); - let directed_near_normal = if factor < 0.0 { - // Standard shadow map to LiSPSM - (1.0 + alpha_sqrt - factor * (alpha - 1.0)) / ((alpha - 1.0) * (factor + 1.0)) - // 1+sqrt(z_f/z_n)/((z_f/z_n - 1)*2) - // - // η = 0: - // (1 + √(z₁/z₀)) / (z₁ / z₀ - 1) - // (z₀ + √(z₀z₁)) / (z₁ - z₀) - } else { - // LiSPSM to PSM - ((alpha_sqrt - 1.0) * (factor * alpha_sqrt + 1.0)).recip() - // LiSPSM: 1 / ((√α - 1) * (η√α + 1)) - // = 1 / ((√α - 1)(1)) - // = 1 / (√α - 1) - // = (1 + √α) / (α - 1) - // = (1 + √(z₁/z₀)) / (z₁ / z₀ - 1) - }; - // let factor = -1.0; - // (f - n) * (1 + √(z₁/z₀) - sin γ * (z₁/z₀ - 1)) / ((z₁/z₀ - 1) * (sin γ + 1)) - // - // (f - n) * (1 + √(z_f/z_n) - (-1 / sin γ) * (z_f/z_n - 1)) / ((z_f/z_n - 1) * ((-1 / sin γ) + 1)) - // (f - n) * (1 + √(z_f/z_n) + 1 / sin γ * (z_f/z_n - 1)) / ((z_f/z_n - 1) * (1 - 1 / sin γ)) - // (f - n) * (1 + √(z_f/z_n) + 1 / sin γ * (z_f/z_n - 1)) / ((1 / sin γ)((z_f/z_n - 1) * (sin γ - 1))) - // (f - n)sin γ * (1 + √(z_f/z_n) + 1 / sin γ * (z_f/z_n - 1)) / ((z_f/z_n - 1) * (sin γ - 1)) - // (f - n)sin γ / sin γ * (sin γ + √(z_f/z_n)sin γ + (z_f/z_n - 1)) / ((z_f/z_n - 1) * (sin γ - 1)) - // (f - n) * (sin γ + √(z_f/z_n)sin γ + (z_f/z_n - 1)) / ((z_f/z_n - 1) * (sin γ - 1)) - // (f - n) * (sin γ + √(z_f/z_n)sin γ + (z_f/z_n - 1)) / ((1 / z_n)(z_f - z_n) * (sin γ - 1)) - // (f - n)z_n * (sin γ + √(z_f/z_n)sin γ + (z_f/z_n - 1)) / ((z_f - z_n) * (sin γ - 1)) - // (f - n)z_n / z_n * (z_n sin γ + √(z_f z_n)sin γ + (z_f - z_n)) / ((z_f - z_n) * (sin γ - 1)) - // (f - n) (z_n sin γ + √(z_f z_n)sin γ + (z_f - z_n)) / ((z_f - z_n) * (sin γ - 1)) - // - // (f - n) * (1 + √(f_e/n_e) - F * (f_e/n_e - 1)) / ((f_e/n_e - 1) * (F + 1)) - // (f - n) * n_e / n_e (n_e + √(n_e * f_e) - F * (f_e - n_e)) / ((f_e - n_e) * (F + 1)) - // (f - n) (n_e + √(n_e * f_e) - F * (f_e - n_e)) / ((f_e - n_e) * (F + 1)) - // - // (f - n) (n_e + √(n_e * f_e) - (sin γ - 1) * (f_e - n_e)) / ((f_e - n_e) * ((sin γ - 1) + 1)) - // (f - n) (n_e + √(n_e * f_e) - (f_e - n_e) sin γ + f_e - n_e) / ((f_e - n_e) * sin γ) - // (f - n) (√(n_e * f_e) - (f_e - n_e) sin γ + f_e) / ((f_e - n_e) * sin γ) - - // Equation 5.14 - 5.16 - // let directed_near_normal = 1.0 / d * (z_0 + (z_0 * z_1).sqrt()); - // let directed_near = w_l_y / d * (z_0 + (z_0 * z_1).sqrt()); - /* let directed_near = directed_near_normal as f32; - let directed_far = (directed_near_normal + d) as f32; */ - let y_ = |v: f64| w_l_y * (v + directed_near_normal).abs(); - let directed_near = y_(0.0) as f32;// (w_l_y * directed_near_normal).abs() as f32; - let directed_far = y_(1.0) as f32;// (w_l_y * (directed_near_normal + 1.0)).abs() as f32; - /* let directed_far = (w_l_y * (directed_near_normal + 1.0)).abs() as f32; - let (directed_near, directed_far) = (directed_near.min(directed_far), directed_near.max(directed_far)); */ - // let directed_near = w_l_y / d * (z_0 + (z_0 * z_1).sqrt()); - // println!("θ = {:?} η = {:?} z_n = {:?} z_f = {:?} γ = {:?} d = {:?} z_0 = {:?} z_1 = {:?} w_l_y: {:?} α = {:?} √α = {:?} n'₀ = {:?} n' = {:?} f' = {:?}", scalar_fov.to_degrees(), factor, z_n, z_f, gamma.to_degrees(), d, z_0, z_1, w_l_y, alpha, alpha_sqrt, directed_near_normal, directed_near, directed_far); - - // let directed_near = /*camera::NEAR_PLANE / sin_gamma*/camera::NEAR_PLANE; - //let near_dist = directed_near as f32; - // let directed_far = directed_near + (camera::FAR_PLANE - camera::NEAR_PLANE); - /* // let directed_near = 1.0; - let directed_near = ((z_n + (z_f * z_n).sqrt()) / /*sin_gamma*/factor) as f32; //1.0; */ - // let directed_far = directed_near + d as f32; - // println!("view_dir: {:?}, new_dir: {:?}, directed_light_dir: {:?}, cos_gamma: {:?}, sin_gamma: {:?}, near_dist: {:?}, d: {:?}, z_n: {:?}, z_f: {:?}, directed_near: {:?}, directed_far: {:?}", view_dir, new_dir, directed_light_dir, cos_gamma, sin_gamma, near_dist, d, z_n, z_f, directed_near, directed_far); - /* let size1 = bounds1.half_size(); - let center1 = bounds1.center(); */ - /* let look_at = cam_pos - (directed_near - near_dist) * up; - let light_all_mat: Mat4 = Mat4::look_at_rh(look_at, look_at + directed_light_dir, /*Vec3::up()*//*Vec3::from(view_dir)*//*up*//*Vec3::down()*/up); */ - // let look_at = look_at - (directed_near - near_dist) * up; - // let light_view_mat = l_r * Mat4::look_at_rh(look_at - sun_dir * light_scale, look_at, /*Vec3::up()*//*Vec3::from(view_dir)*/up); - // let w_v: Mat4 = Mat4::identity(); - // let w_v: Mat4 = Mat4::translation_3d(/*-bounds1.center()*/-center1); - //new observer point n-1 behind eye position - //pos = eyePos-up*(n-nearDist) - // let directed_near = if /*sin_gamma > EPISLON_GAMMA*/factor > EPSILON_UPSILON { directed_near } else { near_dist/*0.0*//*-(near_dist *//*- light_focus_pos.y)*/ }; - light_focus_pos.y = if factor > EPSILON_UPSILON { - light_focus_pos.y/* - directed_near*/+ (/*near_dist*//*z_0 as f32*/ - directed_near) - } else { - light_focus_pos.y - }; - let w_v: math::Mat4 = math::Mat4::translation_3d(/*-bounds1.center()*/-math::Vec3::new(light_focus_pos.x, light_focus_pos.y/* + (directed_near - near_dist)*/,/* - /*(directed_near - near_dist)*/directed_near*//*bounds1.center().z*//*directed_near*//*bounds1.min.z - *//*(directed_near - near_dist)*//*focus_pos.z*//*light_focus_pos.z*//*light_focus_pos.z*//*center1.z*//*center1.z.max(0.0)*/light_focus_pos.z)); - // let w_v: Mat4 = Mat4::translation_3d(/*-bounds1.center()*/-Vec3::new(light_focus_pos.x, light_focus_pos.y,/* - /*(directed_near - near_dist)*/directed_near*//*bounds1.center().z*//*directed_near*//*bounds1.min.z - *//*(directed_near - near_dist)*//*focus_pos.z*//*light_focus_pos.z*//*light_focus_pos.z*/center1.z + directed_near - near_dist)); - // let w_v: Mat4 = Mat4::translation_3d(/*-bounds1.center()*/-Vec3::new(0.0, 0.0,/* - /*(directed_near - near_dist)*/directed_near*//*bounds1.center().z*//*directed_near*//*bounds1.min.z - *//*(directed_near - near_dist)*//*focus_pos.z*//*light_focus_pos.z*/directed_near - near_dist)); - /* let w_p: Mat4 = Mat4::orthographic_rh_no/*frustum_rh_no*/(FrustumPlanes { - // TODO: Consider adjusting resolution based on view distance. - left: -1.0// + (center1.x - focus_pos.x) / size1.w, - // left: -(directed_shadow_resx as f32) / 2.0, - right: 1.0// + (center1.x - focus_pos.x) / size1.w, - // right: directed_shadow_res.x as f32 / 2.0, - bottom: -1.0// + (center1.y - focus_pos.y) / size1.h, - // bottom: -(directed_shadow_res.y as f32) / 2.0, - top: 1.0// + (center1.y - focus_pos.y) / size1.h, - // top: directed_shadow_res.y as f32 / 2.0, - // TODO: Swap fixed near and far planes for something dependent on the height of the - // current scene. - near: directed_near, - far: directed_far,// directed_near + /*zmax - zmin*/bounds1.max.z - bounds1.min.z,//directed_far, - }); */ - let shadow_view_mat: math::Mat4 = w_v * light_all_mat; - let _bounds0 = math::fit_psr(/*l_r*/shadow_view_mat/* * inverse_visible*/, visible_light_volume.iter().copied(), /*|p| math::Vec3::from(p) / p.w*/math::Vec4::homogenized); - // let factor = -1.0; - let w_p: math::Mat4 = { - if /*sin_gamma > EPISLON_GAMMA*/factor > EPSILON_UPSILON { - // Projection for y - let near = directed_near;// - near_dist; - let far = directed_far; - let left = -1.0;// bounds0.min.x;//-1.0;// bounds0.min.x - light_focus_pos.x; - let right = 1.0;// bounds0.max.x;//1.0;// bounds0.max.x - light_focus_pos.x; - let bottom = -1.0;// bounds0.max.z;// bounds0.max.z - light_focus_pos.z; - let top = 1.0;// bounds0.min.z;// bounds0.min.z - light_focus_pos.z; - let s_x = 2.0 * near / (right - left); - let o_x = (right + left) / (right - left); - let s_z = 2.0 * near / (top - bottom); - let o_z = (top + bottom) / (top - bottom); - - let s_y = (far + near) / (far - near); - let o_y = -2.0 * far * near / (far - near); - // y(y₀) = s_y y₀ + o_y - // = ((f + n)y₀ - 2fn) / (f - n) - // y(f) = s_y f + o_y - // = ((f + n)f - 2fn) / (f - n) - // = (f² + fn - 2fn) / (f - n) - // = (f² - fn) / (f - n) - // = f(f - n) / (f - n) - // = f - // - // y(n) = s_y n + o_y - // = ((f + n)n - 2fn) / (f - n) - // = (fn + n² - 2fn) / (f - n) - // = (n² - fn) / (f - n) - // = n(n - f) / (f - n) - // = -n - // - // x(y₀) = s_x x₀ + o_x y₀ - // = (2n x₀ + (r + l) y₀) / (r - l) - // = (2n x₀ + 2ly₀ + (r - l) y₀) / (r - l) - // = 2(n x₀ + l y₀) / (r - l) + y₀ - // = (2(n l + l n) + 2(n (x₀ - n) + l (y₀ - l))) / (r - l) + y₀ - // = (2(n l + l n) + 2(n (x₀ - n) + l (y₀ - l))) / (r - l) + y₀ - // - // = 2n(x₀ - l) / (r - l) + 2n l / (r - l) + (r + l) / (r - l)y₀ - // - // = 2 - // - // = (2 (x₀ n + l x₀) / (r - l) + y₀ - // - // = (2n x₀ - (r + l) y₀) / (r - l) - // = (2 (x₀ n - l y₀) - (r - l) y₀) / (r - l) - // = 2 (x₀ n - l y₀) / (r - l) - y₀ - // - // ~ 2(x₀ n / y₀ - l) / (r - l) - 1 - // - // = 2 (x₀ (y₀ + n - y₀) - l y₀) / (r - l) - y₀ - // = 2 (x₀ - l) y₀ / (r - l) - x₀(y₀ - n) / (r - l) - y₀ - // - // x(n) = 2 (x₀ n - l n) / (r - l) - n - // = n (2(x₀ - l) / (r - l) - 1) - // - // x(f) = 2 (x₀ n - l f) / (r - l) - f - // = f (2(x₀ (n / f) - l) / (r - l) - 1) - // - // x(f) = 2 (x₀ f + l y₀) / (r - l) - f - math::Mat4::new( - s_x, o_x, 0.0, 0.0, - 0.0, s_y, 0.0, o_y, - 0.0, o_z, s_z, 0.0, - 0.0, 1.0, 0.0, 0.0, - )/* - Mat4::new( - n/*1.0*/, 0.0, 0.0, 0.0, - 0.0, s_y, 0.0, o_y, - 0.0, 0.0, n, 0.0, - 0.0, 1.0, 0.0, 0.0, - )*/ + v_p.z = 0.0; + v_p.normalize(); + let l_r: math::Mat4 = if factor > EPSILON_UPSILON { + math::Mat4::look_at_rh(math::Vec3::zero(), math::Vec3::forward_rh(), v_p) } else { - /* Mat4::new( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, s_y, o_y, - 0.0, 0.0, 1.0, 0.0, - ) */ math::Mat4::identity() - } - // Mat4::identity() - /* let a = (n + f) / (n - f); - let b = 2.0 * n * f / (n - f); - Mat4::new( - n, 0.0, 0.0, 0.0, - 0.0, n, 0.0, 0.0, - 0.0, 0.0, a, b, - 0.0, 0.0, -1.0, 0.0, - ) */ - }; - /* let a = (directed_far + directed_near) / (directed_far - directed_near); - let b = -2.0 * directed_far * directed_near / (directed_far - directed_near); - let w_p: Mat4 = Mat4::new( - 1.0, 0.0, 0.0, 0.0, - 0.0, a, 0.0, b, - 0.0, 0.0, 1.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - ); */ - // let _w_p_arr = w_p.cols.iter().map(|e| (e.x, e.y, e.z, e.w)).collect::>(); - // println!("mat4 w_p = mat4(vec4{:?}, vec4{:?}, vec4{:?}, vec4{:?});", w_p_arr[0], w_p_arr[1], w_p_arr[2], w_p_arr[3]); - // let w_p: Mat4 = Mat4::identity(); - // let zmin = p1.z.min(p4.z); - // let zmax = p1.z.max(p4.z); - // println!("zmin: {:?}, zmax: {:?}", zmin, zmax); + }; + let directed_proj_mat = math::Mat4::new( + 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, + 1.0, + ); - // let directed_near = 1.0; - // let directed_far = /*loaded_distance * 2.0*/(zmax - zmin) * 2.0 + directed_near; + let light_all_mat = l_r * directed_proj_mat * light_view_mat; + let bounds0 = math::fit_psr( + light_all_mat, + visible_light_volume.iter().copied(), + math::Vec4::homogenized, + ); + // Vague idea: project z_n from the camera view to the light view (where it's + // tilted by γ). + let (z_0, z_1) = { + let p_z = bounds1.max.z; + let p_y = bounds0.min.y; + let p_x = bounds0.center().x; + let view_inv = view_mat.inverted(); + let light_all_inv = light_all_mat.inverted(); - /* let directed_proj_mat = Mat4::orthographic_rh_no(FrustumPlanes { - // TODO: Consider adjusting resolution based on view distance. - left: xmin, - // left: -(directed_shadow_res.x as f32) / 2.0, - right: xmax, - // right: directed_shadow_res.x as f32 / 2.0, - bottom: ymin, - // bottom: -(directed_shadow_res.y as f32) / 2.0, - top: ymax, - // top: directed_shadow_res.y as f32 / 2.0, - // TODO: Swap fixed near and far planes for something dependent on the height of the - // current scene. - near: zmin,//directed_near, - far: zmax,//directed_far, - }); */ - let shadow_all_mat: math::Mat4 = /*(w_v * l_r).inverted() * */w_p * shadow_view_mat/*w_v * light_all_mat*/; - // let _w_p_arr = shadow_all_mat.cols.iter().map(|e| (e.x, e.y, e.z, e.w)).collect::>(); - // println!("mat4 shadow_all_mat = mat4(vec4{:?}, vec4{:?}, vec4{:?}, vec4{:?});", w_p_arr[0], w_p_arr[1], w_p_arr[2], w_p_arr[3]); - let math::Aabb:: { min: math::Vec3 { x: xmin, y: ymin, z: zmin }, max: math::Vec3 { x: xmax, y: ymax, z: zmax } } = - math::fit_psr(/*light_all_mat*/shadow_all_mat/*shadow_view_mat*//* * inverse_visible*/, visible_light_volume.iter().copied(), /*|p| math::Vec3::from(p) / p.w*/math::Vec4::homogenized); - // fit_psr(light_all_mat/* * inverse_visible*/, aabb_to_points(visible_bounds).iter().copied(), |p| Vec3::from(p) / p.w); - /* let Aabb { min: Vec3 { z: zmin, .. }, max: Vec3 { z: zmax, .. } } = - fit_psr(/*light_all_mat*/shadow_all_mat/* * inverse_visible*/, light_volume.iter().copied(), |p| Vec3::from(p) / p.w); - // fit_psr(light_all_mat/* * inverse_visible*/, light_volume.iter().copied(), |p| Vec3::from(p) / p.w); - // fit_psr(light_all_mat/* * inverse_visible*/, aabb_to_points(visible_bounds).iter().copied(), |p| Vec3::from(p) / p.w); */ - // println!("xmin: {:?} ymin: {:?} zmin: {:?}, xmax: {:?}, ymax: {:?}, zmax: {:?}", xmin, ymin, zmin, xmax, ymax, zmax); - let s_x = 2.0 / (xmax - xmin); - let s_y = 2.0 / (ymax - ymin); - let s_z = 2.0 / (zmax - zmin); - /* let o_x = -(s_x * (xmax + xmin)) / 2.0; - let o_y = -(s_y * (ymax + ymin)) / 2.0; - let o_z = -(s_z * (zmax + zmin)) / 2.0; */ - let o_x = -(xmax + xmin) / (xmax - xmin); - let o_y = -(ymax + ymin) / (ymax - ymin); - let o_z = -(zmax + zmin) / (zmax - zmin); - let directed_proj_mat = Mat4::new( - s_x, 0.0, 0.0, o_x, - 0.0, s_y, 0.0, o_y, - 0.0, 0.0, s_z, o_z, - 0.0, 0.0, 0.0, 1.0, - )/*.scaled_3d(Vec3::new(1.0, 1.0, -1.0))*//* * w_p * w_v*//* * l_r*/;//Mat4::identity(); - // println!("proj_mat: {:?}", directed_proj_mat); - // println!("all_mat: {:?}", directed_proj_mat * view_mat); - // let _w_p_arr = directed_proj_mat.cols.iter().map(|e| (e.x, e.y, e.z, e.w)).collect::>(); - // println!("mat4 directed_proj_mat = mat4(vec4{:?}, vec4{:?}, vec4{:?}, vec4{:?});", w_p_arr[0], w_p_arr[1], w_p_arr[2], w_p_arr[3]); + let view_point = view_inv * math::Vec4::new(0.0, 0.0, p_z, 1.0); + let view_plane = + view_inv * math::Vec4::from_direction(math::Vec3::unit_z()); - let shadow_all_mat: Mat4 = Mat4::from_col_arrays(shadow_all_mat.into_col_arrays()); - // let _w_p_arr = (directed_proj_mat * shadow_all_mat).cols.iter().map(|e| (e.x, e.y, e.z, e.w)).collect::>(); - // println!("mat4 final_mat = mat4(vec4{:?}, vec4{:?}, vec4{:?}, vec4{:?});", w_p_arr[0], w_p_arr[1], w_p_arr[2], w_p_arr[3]); + let light_point = light_all_inv * math::Vec4::new(0.0, p_y, 0.0, 1.0); + let light_plane = + light_all_inv * math::Vec4::from_direction(math::Vec3::unit_y()); - let directed_texture_proj_mat = texture_mat * directed_proj_mat; - ShadowLocals::new(directed_proj_mat * shadow_all_mat, directed_texture_proj_mat * shadow_all_mat) - })); + let shadow_point = light_all_inv * math::Vec4::new(p_x, 0.0, 0.0, 1.0); + let shadow_plane = + light_all_inv * math::Vec4::from_direction(math::Vec3::unit_x()); + + let solve_p0 = math::Mat4::new( + view_plane.x, + view_plane.y, + view_plane.z, + -view_plane.dot(view_point), + light_plane.x, + light_plane.y, + light_plane.z, + -light_plane.dot(light_point), + shadow_plane.x, + shadow_plane.y, + shadow_plane.z, + -shadow_plane.dot(shadow_point), + 0.0, + 0.0, + 0.0, + 1.0, + ); + + let p0_world = solve_p0.inverted() * math::Vec4::unit_w(); + let p0 = light_all_mat * p0_world; + let mut p1 = p0; + p1.y = bounds0.max.y; + + let view_from_light_mat = view_mat * light_all_inv; + let z0 = view_from_light_mat * p0; + let z1 = view_from_light_mat * p1; + + (f64::from(z0.z), f64::from(z1.z)) + }; + + let mut light_focus_pos: math::Vec3 = math::Vec3::zero(); + light_focus_pos.x = bounds0.center().x; + light_focus_pos.y = bounds0.min.y; + light_focus_pos.z = bounds0.center().z; + + let d = f64::from(bounds0.max.y - bounds0.min.y).abs(); + + let w_l_y = d; + + // NOTE: See section 5.1.2.2 of Lloyd's thesis. + let alpha = z_1 / z_0; + let alpha_sqrt = alpha.sqrt(); + let directed_near_normal = if factor < 0.0 { + // Standard shadow map to LiSPSM + (1.0 + alpha_sqrt - factor * (alpha - 1.0)) + / ((alpha - 1.0) * (factor + 1.0)) + } else { + // LiSPSM to PSM + ((alpha_sqrt - 1.0) * (factor * alpha_sqrt + 1.0)).recip() + }; + + // Equation 5.14 - 5.16 + let y_ = |v: f64| w_l_y * (v + directed_near_normal).abs(); + let directed_near = y_(0.0) as f32; + let directed_far = y_(1.0) as f32; + light_focus_pos.y = if factor > EPSILON_UPSILON { + light_focus_pos.y - directed_near + } else { + light_focus_pos.y + }; + let w_v: math::Mat4 = math::Mat4::translation_3d(-math::Vec3::new( + light_focus_pos.x, + light_focus_pos.y, + light_focus_pos.z, + )); + let shadow_view_mat: math::Mat4 = w_v * light_all_mat; + let _bounds0 = math::fit_psr( + shadow_view_mat, + visible_light_volume.iter().copied(), + math::Vec4::homogenized, + ); + let w_p: math::Mat4 = { + if factor > EPSILON_UPSILON { + // Projection for y + let near = directed_near; + let far = directed_far; + let left = -1.0; + let right = 1.0; + let bottom = -1.0; + let top = 1.0; + let s_x = 2.0 * near / (right - left); + let o_x = (right + left) / (right - left); + let s_z = 2.0 * near / (top - bottom); + let o_z = (top + bottom) / (top - bottom); + + let s_y = (far + near) / (far - near); + let o_y = -2.0 * far * near / (far - near); + + math::Mat4::new( + s_x, o_x, 0.0, 0.0, 0.0, s_y, 0.0, o_y, 0.0, o_z, s_z, 0.0, 0.0, + 1.0, 0.0, 0.0, + ) + } else { + math::Mat4::identity() + } + }; + + let shadow_all_mat: math::Mat4 = w_p * shadow_view_mat; + let math::Aabb:: { + min: + math::Vec3 { + x: xmin, + y: ymin, + z: zmin, + }, + max: + math::Vec3 { + x: xmax, + y: ymax, + z: zmax, + }, + } = math::fit_psr( + shadow_all_mat, + visible_light_volume.iter().copied(), + math::Vec4::homogenized, + ); + let s_x = 2.0 / (xmax - xmin); + let s_y = 2.0 / (ymax - ymin); + let s_z = 2.0 / (zmax - zmin); + let o_x = -(xmax + xmin) / (xmax - xmin); + let o_y = -(ymax + ymin) / (ymax - ymin); + let o_z = -(zmax + zmin) / (zmax - zmin); + let directed_proj_mat = Mat4::new( + s_x, 0.0, 0.0, o_x, 0.0, s_y, 0.0, o_y, 0.0, 0.0, s_z, o_z, 0.0, 0.0, 0.0, + 1.0, + ); + + let shadow_all_mat: Mat4 = + Mat4::from_col_arrays(shadow_all_mat.into_col_arrays()); + + let directed_texture_proj_mat = texture_mat * directed_proj_mat; + ShadowLocals::new( + directed_proj_mat * shadow_all_mat, + directed_texture_proj_mat * shadow_all_mat, + ) + }, + )); // Now, we tackle point lights. // First, create a perspective projection matrix at 90 degrees (to cover a whole // face of the cube map we're using). @@ -1394,18 +885,9 @@ impl Scene { }) })); - /* shadow_mats.push( - Mat4::orthographic_rh_no - float near_plane = 1.0f, far_plane = 7.5f; - glm::mat4 lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane); - - ); */ renderer - .update_consts(&mut self.shadow_mats, &shadow_mats) + .update_consts(&mut self.data.shadow_mats, &shadow_mats) .expect("Failed to update light constants"); - // renderer - // .update_shadow_consts(&mut self.shadow_mats, &shadow_mats, 0, - // 6) .expect("Failed to update light constants"); } // Remove unused figures. @@ -1427,40 +909,28 @@ impl Scene { scene_data: &SceneData, ) { let sun_dir = scene_data.get_sun_dir(); - let is_daylight = sun_dir.z < 0.0/*0.6*/; + let is_daylight = sun_dir.z < 0.0; let focus_pos = self.camera.get_focus_pos(); let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc()); + let global = &self.data; + let light_data = (is_daylight, &*self.light_data); + let camera_data = (&self.camera, scene_data.figure_lod_render_distance); + // would instead have this as an extension. - if renderer.render_mode().shadow.is_map() && (is_daylight || self.light_data.len() > 0) { + if renderer.render_mode().shadow.is_map() && (is_daylight || light_data.1.len() > 0) { if is_daylight { // Set up shadow mapping. renderer.start_shadows(); } // Render terrain shadows. - self.terrain.render_shadows( - renderer, - &self.globals, - // &self.lights, - &self.shadow_mats, - &self.light_data, - is_daylight, - focus_pos, - ); + self.terrain + .render_shadows(renderer, &global, light_data, focus_pos); // Render figure shadows. - self.figure_mgr.render_shadows( - renderer, - state, - tick, - &self.globals, - &self.shadow_mats, - is_daylight, - &self.light_data, - &self.camera, - scene_data.figure_lod_render_distance, - ); + self.figure_mgr + .render_shadows(renderer, state, tick, &global, light_data, camera_data); if is_daylight { // Flush shadows. @@ -1474,56 +944,31 @@ impl Scene { state, player_entity, tick, - &self.globals, - &self.lights, - &self.shadows, - &self.shadow_mats, + &global, lod, - &self.camera, - scene_data.figure_lod_render_distance, + camera_data, ); // Render terrain and figures. - self.terrain.render( - renderer, - &self.globals, - &self.lights, - &self.shadows, - &self.shadow_mats, - lod, - focus_pos, - ); + self.terrain.render(renderer, &global, lod, focus_pos); self.figure_mgr.render( renderer, state, player_entity, tick, - &self.globals, - &self.lights, - &self.shadows, - &self.shadow_mats, + &global, lod, - &self.camera, - scene_data.figure_lod_render_distance, + camera_data, ); - self.lod.render(renderer, &self.globals); + self.lod.render(renderer, &global); // Render the skybox. - renderer.render_skybox( - &self.skybox.model, - &self.globals, - &self.skybox.locals, - &lod.alt, - &lod.horizon, - ); + renderer.render_skybox(&self.skybox.model, &global, &self.skybox.locals, lod); self.terrain.render_translucent( renderer, - &self.globals, - &self.lights, - &self.shadows, - &self.shadow_mats, + &global, lod, focus_pos, cam_pos, @@ -1532,7 +977,7 @@ impl Scene { renderer.render_post_process( &self.postprocess.model, - &self.globals, + &global.globals, &self.postprocess.locals, ); } diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 3f6d34b1f3..b5c1abf641 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -2,8 +2,8 @@ use crate::{ mesh::{greedy::GreedyMesh, Meshable}, render::{ create_pp_mesh, create_skybox_mesh, BoneMeshes, Consts, FigureModel, FigurePipeline, - Globals, Light, Model, PostProcessLocals, PostProcessPipeline, Renderer, Shadow, - ShadowLocals, SkyboxLocals, SkyboxPipeline, + GlobalModel, Globals, Light, Model, PostProcessLocals, PostProcessPipeline, Renderer, + Shadow, ShadowLocals, SkyboxLocals, SkyboxPipeline, }, scene::{ camera::{self, Camera, CameraMode}, @@ -68,10 +68,7 @@ struct PostProcess { } pub struct Scene { - globals: Consts, - lights: Consts, - shadows: Consts, - shadow_mats: Consts, + data: GlobalModel, camera: Camera, skybox: Skybox, @@ -105,18 +102,8 @@ impl Scene { let map_bounds = Vec2::new(-65536.0, 131071.0); let map_border = [0.0, 0.0, 0.0, 0.0]; - /* let map_image = image::DynamicImage::ImageRgba8(image::RgbaImage::from_pixel( - 1, - 1, - image::Rgba([0, 0, 0, 0]), - )); */ let map_image = [0]; let alt_image = [0]; - /* let horizon_image = image::DynamicImage::ImageRgba8(image::RgbaImage::from_pixel( - 1, - 1, - image::Rgba([0, 1, 0, 1]), - )); */ let horizon_image = [0x_00_01_00_01]; let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson); @@ -127,10 +114,14 @@ impl Scene { let mut col_lights = FigureColLights::new(renderer); Self { - globals: renderer.create_consts(&[Globals::default()]).unwrap(), - lights: renderer.create_consts(&[Light::default(); 32]).unwrap(), - shadows: renderer.create_consts(&[Shadow::default(); 32]).unwrap(), - shadow_mats: renderer.create_consts(&[ShadowLocals::default(); 6]).unwrap(), + data: GlobalModel { + globals: renderer.create_consts(&[Globals::default()]).unwrap(), + lights: renderer.create_consts(&[Light::default(); 32]).unwrap(), + shadows: renderer.create_consts(&[Shadow::default(); 32]).unwrap(), + shadow_mats: renderer + .create_consts(&[ShadowLocals::default(); 6]) + .unwrap(), + }, skybox: Skybox { model: renderer.create_model(&create_skybox_mesh()).unwrap(), @@ -142,8 +133,16 @@ impl Scene { .create_consts(&[PostProcessLocals::default()]) .unwrap(), }, - lod: LodData::new(renderer, Vec2::new(1, 1), &map_image, &alt_image, &horizon_image, 1, map_border.into()),// Lod::new(renderer, client, settings), - map_bounds,//: client.world_map.2, + lod: LodData::new( + renderer, + Vec2::new(1, 1), + &map_image, + &alt_image, + &horizon_image, + 1, + map_border.into(), + ), + map_bounds, figure_model_cache: FigureModelCache::new(), figure_state: FigureState::new(renderer, CharacterSkeleton::default()), @@ -173,21 +172,18 @@ impl Scene { &camera, &mut buf, ); - ( - model, - state, - ) + (model, state) }), col_lights, camera, turning: false, - char_ori: /*0.0*/-start_angle, + char_ori: -start_angle, } } - pub fn globals(&self) -> &Consts { &self.globals } + pub fn globals(&self) -> &Consts { &self.data.globals } pub fn camera_mut(&mut self) -> &mut Camera { &mut self.camera } @@ -234,19 +230,18 @@ impl Scene { cam_pos, } = self.camera.dependents(); const VD: f32 = 115.0; // View Distance - // const MAP_BOUNDS: Vec2 = Vec2::new(140.0, 2048.0); - const TIME: f64 = 10.0 * 60.0 * 60.0; //43200.0; // 12 hours*3600 seconds + const TIME: f64 = 10.0 * 60.0 * 60.0; const SHADOW_NEAR: f32 = 1.0; const SHADOW_FAR: f32 = 25.0; - if let Err(e) = renderer.update_consts(&mut self.globals, &[Globals::new( + if let Err(e) = renderer.update_consts(&mut self.data.globals, &[Globals::new( view_mat, proj_mat, cam_pos, self.camera.get_focus_pos(), VD, self.lod.tgt_detail as f32, - self.map_bounds, //MAP_BOUNDS, + self.map_bounds, TIME, scene_data.time, renderer.get_resolution(), @@ -338,10 +333,9 @@ impl Scene { ) { renderer.render_skybox( &self.skybox.model, - &self.globals, + &self.data, &self.skybox.locals, - &self.lod.alt, - &self.lod.horizon, + &self.lod, ); if let Some(body) = body { @@ -361,14 +355,10 @@ impl Scene { renderer.render_figure( &model[0], &self.col_lights.texture(), - &self.globals, + &self.data, self.figure_state.locals(), self.figure_state.bone_consts(), - &self.lights, - &self.shadows, - &self.shadow_mats, - &self.lod.alt, - &self.lod.horizon, + &self.lod, ); } @@ -376,20 +366,16 @@ impl Scene { renderer.render_figure( model, &self.col_lights.texture(), - &self.globals, + &self.data, state.locals(), state.bone_consts(), - &self.lights, - &self.shadows, - &self.shadow_mats, - &self.lod.alt, - &self.lod.horizon, + &self.lod, ); } renderer.render_post_process( &self.postprocess.model, - &self.globals, + &self.data.globals, &self.postprocess.locals, ); } diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 0fa8e1e016..580e5b8311 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -1,9 +1,9 @@ use crate::{ mesh::{greedy::GreedyMesh, Meshable}, render::{ - ColLightFmt, ColLightInfo, Consts, FluidPipeline, Globals, Instances, Light, Mesh, Model, - RenderError, Renderer, Shadow, ShadowLocals, ShadowPipeline, SpriteInstance, SpriteLocals, - SpritePipeline, TerrainLocals, TerrainPipeline, Texture, + ColLightFmt, ColLightInfo, Consts, FluidPipeline, GlobalModel, Instances, Mesh, Model, + RenderError, Renderer, ShadowPipeline, SpriteInstance, SpriteLocals, SpritePipeline, + TerrainLocals, TerrainPipeline, Texture, }, }; @@ -40,13 +40,8 @@ struct TerrainChunkData { load_time: f32, opaque_model: Model, fluid_model: Option>, - // shadow_model: Model, - // col_lights: Texture, col_lights: guillotiere::AllocId, - sprite_instances: HashMap< - (BlockKind, usize), - Instances, /* RawBuffer*//*(Consts, usize) */ - >, + sprite_instances: HashMap<(BlockKind, usize), Instances>, locals: Consts, visible: Visibility, @@ -386,12 +381,10 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug>( volume: as SampleVol>>::Sample, max_texture_size: u16, range: Aabb, - sprite_models: &HashMap<(BlockKind, usize), Vec */ SpriteData>>, + sprite_models: &HashMap<(BlockKind, usize), Vec>, ) -> MeshWorkerResponse { - let (opaque_mesh /* col_lights */, fluid_mesh, _shadow_mesh, (bounds, col_lights_info)) = + let (opaque_mesh, fluid_mesh, _shadow_mesh, (bounds, col_lights_info)) = volume.generate_mesh((range, Vec2::new(max_texture_size, max_texture_size))); - // println!("z_bounds{:?}, bounds: {:?}", z_bounds, (bounds.min.z, - // bounds.max.z)); MeshWorkerResponse { pos, z_bounds: (bounds.min.z, bounds.max.z), @@ -422,23 +415,12 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug>( let sprite_data = &sprite_models[&key][0]; let instance = SpriteInstance::new( Mat4::identity() - /*sprite_models[&key][0].mat - /* .scaled_3d( - lod_scale - ) */ - /* .translated_3d( - offset - ) */ - // * 1.0 / 11.0 - .rotated_z(f32::consts::PI * 0.25 * ori as f32) - */ .translated_3d(sprite_data.offset) - // .scaled_3d(SPRITE_SCALE) .rotated_z(f32::consts::PI * 0.25 * ori as f32) .translated_3d( - (rel_pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)) / SPRITE_SCALE, + (rel_pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)) + / SPRITE_SCALE, ), - // Rgb::broadcast(1.0), cfg.wind_sway, rel_pos, ori, @@ -490,8 +472,7 @@ pub struct Terrain { mesh_todo: HashMap, ChunkMeshState>, // GPU data - // sprite_model_data: Model, - sprite_models: Arc */ SpriteData>>>, + sprite_models: Arc>>, sprite_col_lights: Texture, col_lights: Texture, waves: Texture, @@ -518,9 +499,7 @@ impl Terrain { let max_texture_size = renderer.max_texture_size(); let max_size = guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size)); - // let max_sprite_size = guillotiere::Size::new(128, 64); let mut greedy = GreedyMesh::new(max_size); - // let mut mesh = Mesh::new(); let mut locals_buffer = [SpriteLocals::default(); 8]; let mut make_models = |(kind, variation), s, offset, lod_axes: Vec3| { let scaled = [1.0, 0.8, 0.6, 0.4, 0.2]; @@ -545,10 +524,6 @@ impl Terrain { scale } }); - /* println!( - "model_size: {:?} (model_scale = {:?})", - model_size, model_scale - ); */ let wind_sway = sprite_config_for(kind).map(|c| c.wind_sway).unwrap_or(0.0); let sprite_mat: Mat4 = Mat4::translation_3d(offset).scaled_3d(SPRITE_SCALE); ( @@ -556,45 +531,44 @@ impl Terrain { scaled .iter() .map(|&lod_scale_orig| { - let lod_scale = model_scale * if lod_scale_orig == 1.0 { - Vec3::broadcast(1.0) - } else { - lod_axes * lod_scale_orig + lod_axes.map(|e| if e == 0.0 { 1.0 } else { 0.0 }) - }; + let lod_scale = model_scale + * if lod_scale_orig == 1.0 { + Vec3::broadcast(1.0) + } else { + lod_axes * lod_scale_orig + + lod_axes.map(|e| if e == 0.0 { 1.0 } else { 0.0 }) + }; let opaque_model = - Meshable::::generate_mesh( - Segment::from(model.as_ref()).scaled_by(lod_scale), - (&mut greedy, wind_sway >= 0.4 && lod_scale_orig == 1.0/*>= 0.8*//*lod_axes.x == 0.0 && lod_axes.y == 0.0*//* && lod_scale.z >= 0.8*//*, offset * lod_scale, Vec3::one() / lod_scale*/), - ) - .0; + Meshable::::generate_mesh( + Segment::from(model.as_ref()).scaled_by(lod_scale), + (&mut greedy, wind_sway >= 0.4 && lod_scale_orig == 1.0), + ) + .0; let sprite_scale = Vec3::one() / lod_scale; let sprite_mat: Mat4 = sprite_mat * Mat4::scaling_3d(sprite_scale); - locals_buffer.iter_mut().enumerate().for_each(|(ori, locals)| { - let sprite_mat = sprite_mat.rotated_z(f32::consts::PI * 0.25 * ori as f32); - *locals = SpriteLocals::new(sprite_mat, sprite_scale, offset, wind_sway); - }); + locals_buffer + .iter_mut() + .enumerate() + .for_each(|(ori, locals)| { + let sprite_mat = + sprite_mat.rotated_z(f32::consts::PI * 0.25 * ori as f32); + *locals = + SpriteLocals::new(sprite_mat, sprite_scale, offset, wind_sway); + }); SpriteData { - /* scale: sprite_scale, */ offset, - /* mat: sprite_mat, */ - model: renderer.create_model(&opaque_model) - .unwrap(), - locals: renderer.create_consts(&locals_buffer) + model: renderer.create_model(&opaque_model).unwrap(), + locals: renderer + .create_consts(&locals_buffer) .expect("Failed to upload sprite locals to the GPU!"), } - /* // NOTE: Safe because atlas size is an upper bound on vertex count, and atlas - // width and height are at most u16::MAX. - let start = mesh.vertices().len() as u32; - let vbuf = (start..start + opaque_model.vertices().len() as u32); - mesh.push_mesh(&opaque_model); - vbuf */ }) .collect::>(), ) }; - let sprite_models: HashMap<(BlockKind, usize), /* Vec> */ _> = vec![ + let sprite_models: HashMap<(BlockKind, usize), _> = vec![ // Windows make_models( (BlockKind::Window1, 0), @@ -2308,11 +2282,6 @@ impl Terrain { ] .into_iter() .collect(); - /* let sprite_model_data = renderer - .create_model(&mesh) - .expect("Failed to upload sprite vertex to the GPU!"); */ - // println!("{:?}, {:?}", sprite_model_data.vbuf, - // sprite_model_data.vertex_range); println!("{:?}", sprite_models); let sprite_col_lights = ShadowPipeline::create_col_lights(renderer, greedy.finalize()) .expect("Failed to upload sprite color and light data to the GPU!"); Self { @@ -2322,23 +2291,8 @@ impl Terrain { mesh_send_tmp: send, mesh_recv: recv, mesh_todo: HashMap::default(), - // sprite_model_data, sprite_models: Arc::new(sprite_models), - sprite_col_lights, /*renderer - .create_texture_immutable_raw( - gfx::texture::Kind::D2( - tex_size.x, - tex_size.y, - gfx::texture::AaMode::Single, - ), - gfx::texture::Mipmap::Provided, - &[&tex], - gfx::texture::SamplerInfo::new( - gfx::texture::FilterMethod::Bilinear, - gfx::texture::WrapMode::Clamp, - ), - ) - .expect("Failed to upload sprite color and light data to the GPU!"),*/ + sprite_col_lights, waves: renderer .create_texture( &assets::load_expect("voxygen.texture.waves"), @@ -2358,14 +2312,12 @@ impl Terrain { let max_texture_size = renderer.max_texture_size(); let atlas_size = guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size)); - // let atlas_size = guillotiere::Size::new(1, 1); let atlas = AtlasAllocator::with_options(atlas_size, &guillotiere::AllocatorOptions { // TODO: Verify some good empirical constants. small_size_threshold: 128, large_size_threshold: 1024, ..guillotiere::AllocatorOptions::default() }); - // renderer.flush(); let texture = renderer.create_texture_raw( gfx::texture::Kind::D2( max_texture_size, @@ -2373,8 +2325,7 @@ impl Terrain { gfx::texture::AaMode::Single, ), 1 as gfx::texture::Level, - // gfx::memory::Upload, - gfx::memory::Bind::SHADER_RESOURCE, /* | gfx::memory::Bind::TRANSFER_DST */ + gfx::memory::Bind::SHADER_RESOURCE, gfx::memory::Usage::Dynamic, (0, 0), gfx::format::Swizzle::new(), @@ -2383,33 +2334,10 @@ impl Terrain { gfx::texture::WrapMode::Clamp, ), )?; - /* renderer.flush(); - let ten_millis = core::time::Duration::from_millis(10); - std::thread::sleep(ten_millis); - - renderer.update_texture( - &texture, - [0, 0], - [max_texture_size, max_texture_size], - &vec![[0u8; 4]; (usize::from(max_texture_size) * usize::from(max_texture_size))], - //&[[255u8; 4]; 64 * 64], - // NOTE: Cast is safe since the origin was a u16. - )?; - renderer.flush(); */ - // texture.cleanup(); - // Not sure if this is necessary... - // renderer.flush(); - // texture.update(); - // // FIXME: Currently, there seems to be a bug where the very first texture - // update always // fails. Not sure why, but we currently work around - // it with a dummy allocation (which we // proceed to leak, in case the - // bug can return after it's freed). let _ = atlas.allocate(guillotiere: - // :Size::new(64, 64)); Ok((atlas, texture)) } fn remove_chunk_meta(&mut self, _pos: Vec2, chunk: &TerrainChunkData) { - /* println!("Terrain chunk already existed: {:?}", pos); */ self.atlas.deallocate(chunk.col_lights); /* let (zmin, zmax) = chunk.z_bounds; self.z_index_up.remove(Vec3::from(zmin, pos.x, pos.y)); @@ -2426,15 +2354,13 @@ impl Terrain { } fn remove_chunk(&mut self, pos: Vec2) { - // println!("Terrain chunk removed: {:?}", pos); if let Some(chunk) = self.chunks.remove(&pos) { self.remove_chunk_meta(pos, &chunk); // Temporarily remember dead chunks for shadowing purposes. self.shadow_chunks.push((pos, chunk)); } if let Some(_todo) = self.mesh_todo.remove(&pos) { - /* println!("Terrain chunk was being meshed: {:?}", - * (todo.pos, todo.started_tick)); */ + //Do nothing on todo mesh removal. } } @@ -2452,11 +2378,7 @@ impl Terrain { loaded_distance: f32, view_mat: Mat4, proj_mat: Mat4, - ) -> ( - Aabb, - /* Aabb, Aabb */ Vec>, - math::Aabr, - ) { + ) -> (Aabb, Vec>, math::Aabr) { let current_tick = scene_data.tick; let current_time = scene_data.state.get_time(); let mut visible_bounding_box: Option> = None; @@ -2478,7 +2400,6 @@ impl Terrain { .map(|c| (false, c)), ) { - // println!("Terrain chunk change: {:?}", (modified, pos)); // TODO: ANOTHER PROBLEM HERE! // What happens if the block on the edge of a chunk gets modified? We need to // spawn a mesh worker to remesh its neighbour(s) too since their @@ -2500,7 +2421,6 @@ impl Terrain { } if neighbours { - // println!("Insert mesh_todo:: {:?}", (pos, current_tick)); self.mesh_todo.insert(pos, ChunkMeshState { pos, started_tick: current_tick, @@ -2521,7 +2441,6 @@ impl Terrain { .iter() .map(|(p, _)| *p) { - // println!("Terrain block change: {:?}", pos); let chunk_pos = scene_data.state.terrain().pos_key(pos); // Only mesh if this chunk has all its neighbors let mut neighbours = true; @@ -2535,7 +2454,6 @@ impl Terrain { } } if neighbours { - // println!("Insert mesh_todo: {:?}", (chunk_pos, current_tick)); self.mesh_todo.insert(chunk_pos, ChunkMeshState { pos: chunk_pos, started_tick: current_tick, @@ -2566,8 +2484,6 @@ impl Terrain { } } if neighbours { - // println!("Insert mesh_todo:: {:?}", (neighbour_chunk_pos, - // current_tick)); self.mesh_todo.insert(neighbour_chunk_pos, ChunkMeshState { pos: neighbour_chunk_pos, started_tick: current_tick, @@ -2673,8 +2589,6 @@ impl Terrain { // data structure (convert the mesh to a model first of course). Some(todo) if response.started_tick <= todo.started_tick => { let started_tick = todo.started_tick; - // println!("Finished meshing worker: (pos={:?}, response={:?}, todo={:?})", - // response.pos, response.started_tick, todo.started_tick); let load_time = self .chunks .get(&response.pos) @@ -2682,30 +2596,6 @@ impl Terrain { .unwrap_or(current_time as f32); // TODO: Allocate new atlas on allocation faillure. let (tex, tex_size) = response.col_lights_info; - /* if self.chunks.len() == 0 { - println!("{:?}\n{:?}", tex, tex_size); - /*// HACK - let (atlas_, col_lights_) = Self::make_atlas(renderer) - .expect("Failed to create atlas texture"); - // renderer.flush(); - let ten_millis = core::time::Duration::from_millis(1000); - std::thread::sleep(ten_millis); - if let Err(err) = renderer.update_texture( - &self.col_lights, - // &col_lights, - // NOTE: Cast is safe since the origin was a u16. - [0, 0], - [1, 1], - &[[0u8; 4]], - ) { - panic!("Ahhh {:?}", err); - warn!("Failed to update texture: {:?}", err); - } - renderer.flush(); - std::thread::sleep(ten_millis); - self.atlas = atlas_; - self.col_lights = col_lights_; */ - } */ let atlas = &mut self.atlas; let allocation = atlas .allocate(guillotiere::Size::new( @@ -2713,57 +2603,13 @@ impl Terrain { i32::from(tex_size.y), )) .expect("Not yet implemented: allocate new atlas on allocation faillure."); - // println!("Allocation {:?} for {:?} (original size = {:?}... ugh)", - // allocation, response.pos, tex_size); NOTE: Cast is safe - // since the origin was a u16. + // NOTE: Cast is safe since the origin was a u16. let atlas_offs = Vec2::new( allocation.rectangle.min.x as u16, allocation.rectangle.min.y as u16, ); - if atlas_offs == Vec2::zero() { - // println!("Model: {:?}", - // &response.opaque_mesh.vertices()); - // println!("Texture: {:?}", tex); - } - // let atlas_offs : Vec2 = Vec2::zero(); - /* let col_lights = renderer - .create_texture_immutable_raw( - gfx::texture::Kind::D2( - tex_size.x, - tex_size.y, - gfx::texture::AaMode::Single, - ), - gfx::texture::Mipmap::Provided, - &[&tex], - gfx::texture::SamplerInfo::new( - gfx::texture::FilterMethod::Bilinear, - gfx::texture::WrapMode::Clamp, - ), - ) - .expect("Failed to upload terrain color and light data to the GPU!"); */ - /* let col_lights = renderer - .create_texture_raw( - gfx::texture::Kind::D2( - tex_size.x, - tex_size.y, - gfx::texture::AaMode::Single, - ), - 1 as gfx::texture::Level, - // gfx::memory::Upload, - gfx::memory::Bind::SHADER_RESOURCE, - gfx::memory::Usage::Dynamic, - (0, 0), - gfx::format::Swizzle::new(), - gfx::texture::SamplerInfo::new( - gfx::texture::FilterMethod::Bilinear, - gfx::texture::WrapMode::Clamp, - ), - ) - .expect("Failed to upload col lights data to the GPU!"); */ if let Err(err) = renderer.update_texture( &self.col_lights, - // &col_lights, - // NOTE: Cast is safe since the origin was a u16. atlas_offs.into_array(), tex_size.into_array(), &tex, @@ -2785,27 +2631,10 @@ impl Terrain { } else { None }, - /* shadow_model: renderer - .create_model(&response.shadow_mesh) - .expect("Failed to upload chunk mesh to the GPU!"), */ - col_lights: allocation.id,/*ShadowPipeline::create_col_lights(renderer, /*response.col_lights_info*/(tex, tex_size)) - .expect("Failed to upload chunk light-color texture to the GPU!"),*/ - /* sprite_instances: response - .sprite_instances - .into_iter() - .map(|(kind, instances)| { - ( - kind, - (renderer./*create_consts_immutable*/create_consts(&instances).expect( - "Failed to upload chunk sprite instances to the GPU!", - ), instances.len()), - ) - }) - .collect(), */ + col_lights: allocation.id, sprite_instances: response .sprite_instances .into_iter() - .map(|(kind, instances)| { ( kind, @@ -2823,7 +2652,13 @@ impl Terrain { }), ) .into_array(), - atlas_offs: Vec4::new(i32::from(atlas_offs.x), i32::from(atlas_offs.y), 0, 0).into_array(), + atlas_offs: Vec4::new( + i32::from(atlas_offs.x), + i32::from(atlas_offs.y), + 0, + 0, + ) + .into_array(), load_time, }]) .expect("Failed to upload chunk locals to the GPU!"), @@ -2835,25 +2670,17 @@ impl Terrain { }); if response.started_tick == started_tick { - // println!("Terrain chunk removed from meshing: {:?}", (response.pos, - // response.started_tick)); self.mesh_todo.remove(&response.pos); } }, // Chunk must have been removed, or it was spawned on an old tick. Drop the mesh // since it's either out of date or no longer needed. - Some(_todo) => { - /* println!("Finished meshing worker: (pos={:?}, response={:?}, todo={:?})", response.pos, response.started_tick, todo.started_tick); - println!("Terrain chunk removed from meshing due to being out of date: {:?}", (response.pos, response.started_tick)); - self.mesh_todo.remove(&response.pos); */ - }, + Some(_todo) => {}, None => {}, } } // Construct view frustum - let _all_mat = proj_mat * view_mat; - //.scaled_3d(Vec3::new(proj_mat[(0, 0)], proj_mat[(1, 1)], 1.0)); let focus_off = focus_pos.map(|e| e.trunc()); let frustum = Frustum::from_modelview_projection( (proj_mat * view_mat * Mat4::translation_3d(-focus_off)).into_col_arrays(), @@ -2861,13 +2688,6 @@ impl Terrain { // Update chunk visibility let chunk_sz = V::RECT_SIZE.x as f32; - let _scene_bounding_box: Aabb = Aabb { - min: focus_pos - 2.0, /* - * - /0.5f32 */ - max: focus_pos + 2.0, /* + 0.5f32 */ - }; - /* let mut shadow_queue = - * std::collections::VecDeque::with_capacity(self.chunks.len()); */ for (pos, chunk) in &mut self.chunks { let chunk_pos = pos.map(|e| e as f32 * chunk_sz); @@ -2905,22 +2725,12 @@ impl Terrain { min: Vec3::from(chunk_min), max: Vec3::from(chunk_max), }; - // scene_bounding_box.expand_to_contain(chunk_box); if in_frustum { - /* let visible_box = Aabb { - min: chunk_box.min - focus_off, - max: chunk_box.max - focus_off, - }; - let visible_box = super::fit_psr(all_mat, visible_box, |p| Vec3::from(p) / p.w/*.clamped(-p.w.abs(), p.w.abs())*/) - .map(|e| e.clamped(-1.0, 1.0)) - ; */ let visible_box = chunk_box; visible_bounding_box = visible_bounding_box .map(|e| e.union(visible_box)) .or(Some(visible_box)); - /* shadow_queue.push_back(chunk_box); - // shadow_queue.push(chunk_min + chunk_sz * 0.5); */ } // FIXME: Hack that only works when only the lantern casts point shadows // (and hardcodes the shadow distance). Should ideally exist per-light, too. @@ -2929,17 +2739,11 @@ impl Terrain { // PSRs: potential shadow receivers let visible_bounding_box = visible_bounding_box.unwrap_or(Aabb { - min: focus_pos - 2.0, /* - * - 0.5 */ - max: focus_pos + 2.0, /* + 0.5 */ + min: focus_pos - 2.0, + max: focus_pos + 2.0, }); // PSCs: Potential shadow casters - let _psc_bounding_box: Aabb = visible_bounding_box; - /*Aabb { - min: focus_pos - 0.5f32, - max: focus_pos + 0.5f32, - }; */ let ray_direction = scene_data.get_sun_dir(); let collides_with_aabr = |a: math::Aabr, b: math::Aabr| { a.min.partial_cmple(&b.max).reduce_and() && a.max.partial_cmpge(&b.min).reduce_and() @@ -2956,11 +2760,10 @@ impl Terrain { min: math::Vec3::from(visible_bounding_box.min.map(f64::from)), max: math::Vec3::from(visible_bounding_box.max.map(f64::from)), }; - let inv_proj_view = math::Mat4::from_col_arrays( - (proj_mat * view_mat/* * Mat4::translation_3d(-focus_off)*/).into_col_arrays(), - ) - .map(f64::from) - .inverted(); + let inv_proj_view = + math::Mat4::from_col_arrays((proj_mat * view_mat).into_col_arrays()) + .map(f64::from) + .inverted(); let ray_direction = math::Vec3::::from(ray_direction); let visible_light_volume = math::calc_focused_light_volume_points( inv_proj_view, @@ -2971,44 +2774,16 @@ impl Terrain { .map(|v| v.map(|e| e as f32)) .collect::>(); - let cam_pos = math::Vec4::from(view_mat.inverted() * Vec4::unit_w()).xyz()/* + focus_off*/; - /* let view_dir = (focus_pos.map(f32::fract)) - cam_pos; - // let new_dir: Vec3 = light_volume/*visible_light_volume*/.iter().map(|p| - // p - cam_pos).sum(); - let new_dir = view_dir; - let new_dir = new_dir.normalized(); - let dot_prod = f64::from(ray_direction.dot(new_dir)); - let sin_gamma = (1.0 - dot_prod * dot_prod).sqrt(); - // let sin_gamma = 0.0; - let _new_dir = if sin_gamma > super::EPSILON_GAMMA { - new_dir - } else { - Vec3::from(view_mat * Vec4::from_direction(Vec3::up())).normalized() - }; */ - let up: math::Vec3 = { - /* (ray_direction) - .cross(new_dir) - .cross(ray_direction) - .normalized() */ - math::Vec3::up() - }; + let cam_pos = math::Vec4::from(view_mat.inverted() * Vec4::unit_w()).xyz(); + let up: math::Vec3 = { math::Vec3::up() }; - let ray_mat = math::Mat4::look_at_rh( - cam_pos, - cam_pos + ray_direction, - up, - // Vec3::up(), - ); - // println!("old: {:?} new: {:?}", visible_bounding_box, visible_light_volume); + let ray_mat = math::Mat4::look_at_rh(cam_pos, cam_pos + ray_direction, up); let visible_bounds = math::Aabr::from(math::fit_psr( ray_mat, - /* super::aabb_to_points(visible_bounding_box).iter().copied() */ visible_light_volume.iter().copied(), - |p| p, //math::Vec3::from(p), /* / p.w */ + |p| p, )); let ray_mat = ray_mat * math::Mat4::translation_3d(-focus_off); - /* let visible_bounds_old = Aabr::from(super::fit_psr(ray_mat, super::aabb_to_points(visible_bounding_box).iter().copied(), |p| Vec3::from(p) / p.w)); - println!("old: {:?} new: {:?}", visible_bounds_old, visible_bounds); */ let can_shadow_sun = |pos: Vec2, chunk: &TerrainChunkData| { let chunk_pos = pos.map(|e| e as f32 * chunk_sz); @@ -3026,20 +2801,9 @@ impl Terrain { let chunk_from_light = math::Aabr::from(math::fit_psr( ray_mat, math::aabb_to_points(chunk_box).iter().copied(), - |p| p, /* math::Vec3::from(p)/* / p.w*/ */ + |p| p, )); - /* let chunk_from_light = Aabr { - min: (ray_mat * Vec4::from_point(chunk_box.min)).xy(), - max: (ray_mat * Vec4::from_point(chunk_box.max)).xy(), - }.made_valid(); */ - /* let can_shadow_sun = */ collides_with_aabr(chunk_from_light, visible_bounds) - /* let can_shadow_sun_old = collides_with_aabr(chunk_from_light, visible_bounds_old); - if can_shadow_sun != can_shadow_sun_old { - println!("Different results for chunk {:?} (from light = {:?}):\n\ - old = {:?} new = {:?}", - chunk_box, chunk_from_light, can_shadow_sun_old, can_shadow_sun); - } */ }; // Handle potential shadow casters (chunks that aren't visible, but are still in @@ -3059,7 +2823,7 @@ impl Terrain { // If the sun can currently cast shadows, we retain only those shadow chunks // that both: 1. have not been replaced by a real chunk instance, // and 2. are currently potential shadow casters (as witnessed by - // `can_shadow_sun` returning true). + // `can_shadow_sun` returning true). // // NOTE: Please make sure this runs *after* any code that could insert a chunk! // Otherwise we may end up with multiple instances of the chunk trying to cast @@ -3078,63 +2842,8 @@ impl Terrain { max: math::Vec2::zero(), }) }; - /* let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w()) + focus_off; let look_at = visible_box.center(); - let view_dir = (focus_pos - cam_pos).normalized(); - let up_vec = ray_direction.cross(view_dir).cross(light_dir).normalized(); - let sun_light_mat = Mat4::look_at_rh(look_at - ray_direction, look_at, view_dir); - let sun_bounding_box = super::fit_psr(all_mat, visible_box, |p| Vec3::from(p) / p.w/*.clamped(-p.w.abs(), p.w.abs())*/) - Aabb { - min: -0.5, - max: 0.5, - }; */ - /* if ray_direction.z < 0.0 && renderer.render_mode().shadow.is_map() { - let ray = if ray_direction.x.abs() * scene_bounding_box.size().d > ray_direction.z.abs() * chunk_sz { - -ray_direction / ray_direction.x * chunk_sz - } else { - /* -ray_direction / ray_direction.z * scene_bounding_box.size().d */ - Vec3::new(0.0, 0.0, scene_bounding_box.size().d) - }; - while let Some(shadow_chunk) = shadow_queue.pop_front() { - let collides_with_aabb = |a: Aabb, b: Aabb| - a.min.partial_cmple(&b.max).reduce_and() && - a.max.partial_cmpge(&b.min).reduce_and(); - if !collides_with_aabb(scene_bounding_box, shadow_chunk) { - continue; - } - let min_chunk_pos = Vec2::from(shadow_chunk.min.map(|e| (e / chunk_sz).floor())) - .map(|e: f32| e as i32); - let max_chunk_pos = Vec2::from(shadow_chunk.max.map(|e| (e / chunk_sz).ceil())) - .map(|e: f32| e as i32); - let mut check_chunk = |x, y| { - if let Some(mut chunk) = self.chunks.get_mut(&Vec2::new(x, y)) { - let (minz, maxz) = chunk.z_bounds; - if minz <= shadow_chunk.max.z && maxz >= shadow_chunk.min.z { - chunk.can_shadow_sun = true; - // NOTE: These casts are safe because the maximum chunk index we are - // currently considering is 16384. - let x = x as f32; - let y = y as f32; - psc_bounding_box.expand_to_contain(shadow_chunk.intersection(Aabb { - min: Vec3::new(x * chunk_sz, y * chunk_sz, minz), - max: Vec3::new((x + 1.0) * chunk_sz, (y + 1.0) * chunk_sz, maxz), - })); - } - } - }; - (min_chunk_pos.y..max_chunk_pos.y).for_each(|y| { - (min_chunk_pos.x..max_chunk_pos.x).for_each(|x| { - check_chunk(x, y); - }) - }); - shadow_queue.push_back(Aabb { - min: shadow_chunk.min + ray, - max: shadow_chunk.max + ray, - }); - } - } */ ( - /* scene_bounding_box, visible_bounding_box, psc_bounding_box */ visible_bounding_box, visible_light_volume, visible_psr_bounds, @@ -3155,11 +2864,8 @@ impl Terrain { pub fn render_shadows( &self, renderer: &mut Renderer, - globals: &Consts, - // lights: &Consts, - shadow_mats: &Consts, - light_data: &[Light], - is_daylight: bool, + global: &GlobalModel, + (is_daylight, light_data): super::LightData, focus_pos: Vec3, ) { if !renderer.render_mode().shadow.is_map() { @@ -3177,8 +2883,6 @@ impl Terrain { }) .take(self.chunks.len()); - // let is_daylight = sun_dir.z < 0.0/*0.6*/; - // Directed shadows // // NOTE: We also render shadows for dead chunks that were found to still be @@ -3192,15 +2896,10 @@ impl Terrain { .for_each(|chunk| { // Directed light shadows. renderer.render_terrain_shadow_directed( - // &chunk.shadow_model, &chunk.opaque_model, - globals, + global, &chunk.locals, - shadow_mats, - /* lights, */ - /* shadows, - * &lod.alt, - * &lod.horizon, */ + &global.shadow_mats, ); }); } @@ -3212,17 +2911,11 @@ impl Terrain { light_data.iter().take(1).for_each(|_light| { chunk_iter.clone().for_each(|chunk| { if chunk.can_shadow_point { - // shadow_vertex_count += chunk.shadow_model.vertex_range.len(); renderer.render_shadow_point( &chunk.opaque_model, - // &chunk.shadow_model, - globals, + global, &chunk.locals, - shadow_mats, - /* lights, */ - /* shadows, - * &lod.alt, - * &lod.horizon, */ + &global.shadow_mats, ); } }); @@ -3232,14 +2925,9 @@ impl Terrain { pub fn render( &self, renderer: &mut Renderer, - globals: &Consts, - lights: &Consts, - shadows: &Consts, - shadow_mats: &Consts, + global: &GlobalModel, lod: &LodData, focus_pos: Vec3, - /* sun_dir: Vec3, - * light_data: &[Light], */ ) { let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| { (e as i32).div_euclid(sz as i32) @@ -3252,105 +2940,23 @@ impl Terrain { }) .take(self.chunks.len()); - // // Flush renderer to synchronize commands sent on the main encoder with the - // // start of the shadow encoder. - // renderer.flush(); - - // Shadows - - /*scene_data.thread_pool.execute(move || { - let _ = send.send(mesh_worker( - pos, - (min_z as f32, max_z as f32), - started_tick, - volume, - max_texture_size, - aabb, - )); - });*/ - // let mut shadow_vertex_count = 0; - /* let is_daylight = sun_dir.z < 0.0/*0.6*/; - - // Directed shadows - for (_, chunk) in chunk_iter.clone() { - if is_daylight { - // Directed light shadows. - renderer.render_shadow_directed( - // &chunk.shadow_model, - &chunk.opaque_model, - globals, - &chunk.locals, - shadow_mats, - // lights, - // shadows, - // &lod.alt, - // &lod.horizon, - ); - } - } - - // Point shadows - for _light in light_data.iter().take(1) { - for (_, chunk) in chunk_iter.clone() { - if chunk.can_shadow_point { - // shadow_vertex_count += chunk.shadow_model.vertex_range.len(); - renderer.render_shadow_point( - &chunk.opaque_model, - // &chunk.shadow_model, - globals, - &chunk.locals, - shadow_mats, - // lights, - // shadows, - // &lod.alt, - // &lod.horizon, - ); - } - } - } - - // Flush shadows. - if is_daylight || light_data.len() > 0 { - renderer.flush_shadows(); - } */ - - // Terrain - // let mut terrain_vertex_count = 0; for (_, chunk) in chunk_iter { - // terrain_vertex_count += chunk.opaque_model.vertex_range.len(); - if chunk.visible == Visibility::Visible - /* || chunk.can_shadow_sun() */ - { + if chunk.visible == Visibility::Visible { renderer.render_terrain_chunk( &chunk.opaque_model, - // &chunk.shadow_model, - // &chunk.col_lights, &self.col_lights, - globals, + global, &chunk.locals, - lights, - shadows, - shadow_mats, - &lod.alt, - &lod.horizon, + lod, ); } } - /* println!( - "Vertex count (shadow / terrain / ratio): {:?} / {:?} / {:?}", - shadow_vertex_count, - terrain_vertex_count, - shadow_vertex_count as f64 / terrain_vertex_count as f64 - ); */ } pub fn render_translucent( &self, renderer: &mut Renderer, - globals: &Consts, - lights: &Consts, - shadows: &Consts, - shadow_mats: &Consts, + global: &GlobalModel, lod: &LodData, focus_pos: Vec3, cam_pos: Vec3, @@ -3394,49 +3000,31 @@ impl Terrain { chunk_center + chunk_size.x * 0.5 - chunk_size.y * 0.5, )); if focus_dist_sqrd < sprite_render_distance.powf(2.0) { - for (kind, /*(instances, instance_count)*/instances) in (&chunk.sprite_instances).into_iter()/*.take(1)*/ { - let SpriteData { model, locals, .. } = - if sprite_config_for(kind.0).map(|config| config.wind_sway >= 0.4).unwrap_or(false) && dist_sqrd <= chunk_mag - || dist_sqrd < sprite_high_detail_distance.powf(2.0) { - &self.sprite_models[&kind][0] - } else if dist_sqrd < sprite_hid_detail_distance.powf(2.0) { - &self.sprite_models[&kind][1] - } else if dist_sqrd < sprite_mid_detail_distance.powf(2.0) { - &self.sprite_models[&kind][2] - } else if dist_sqrd < sprite_low_detail_distance.powf(2.0) { - &self.sprite_models[&kind][3] - } else { - &self.sprite_models[&kind][4] - }; + for (kind, instances) in (&chunk.sprite_instances).into_iter() { + let SpriteData { model, locals, .. } = if sprite_config_for(kind.0) + .map(|config| config.wind_sway >= 0.4) + .unwrap_or(false) + && dist_sqrd <= chunk_mag + || dist_sqrd < sprite_high_detail_distance.powf(2.0) + { + &self.sprite_models[&kind][0] + } else if dist_sqrd < sprite_hid_detail_distance.powf(2.0) { + &self.sprite_models[&kind][1] + } else if dist_sqrd < sprite_mid_detail_distance.powf(2.0) { + &self.sprite_models[&kind][2] + } else if dist_sqrd < sprite_low_detail_distance.powf(2.0) { + &self.sprite_models[&kind][3] + } else { + &self.sprite_models[&kind][4] + }; renderer.render_sprites( - /*Model { - vbuf: self.sprite_model_data.vbuf.clone(), - vertex_range: /*self.sprite_model_data.vertex_range()*/*/ - /* if sprite_config_for(kind.0).map(|config| config.wind_sway >= 0.4).unwrap_or(false) && dist_sqrd <= chunk_mag - || dist_sqrd < sprite_high_detail_distance.powf(2.0) { - &self.sprite_models[&kind][0].model - } else if dist_sqrd < sprite_hid_detail_distance.powf(2.0) { - &self.sprite_models[&kind][1].model - } else if dist_sqrd < sprite_mid_detail_distance.powf(2.0) { - &self.sprite_models[&kind][2].model - } else if dist_sqrd < sprite_low_detail_distance.powf(2.0) { - &self.sprite_models[&kind][3].model - } else { - &self.sprite_models[&kind][4].model - }/*.clone(), - }*/,*/ model, &self.sprite_col_lights, - globals, + global, &chunk.locals, locals, - // *instance_count, &instances, - lights, - shadows, - shadow_mats, - &lod.alt, - &lod.horizon, + lod, ); } } @@ -3459,13 +3047,9 @@ impl Terrain { .for_each(|(model, locals)| { renderer.render_fluid_chunk( model, - globals, + global, locals, - lights, - shadows, - shadow_mats, - &lod.alt, - &lod.horizon, + lod, &self.waves, ) });