diff --git a/assets/voxygen/shaders/include/lod.glsl b/assets/voxygen/shaders/include/lod.glsl index 92984fccd0..6d20f4de81 100644 --- a/assets/voxygen/shaders/include/lod.glsl +++ b/assets/voxygen/shaders/include/lod.glsl @@ -38,14 +38,14 @@ vec3 lod_pos(vec2 v_pos) { vec3 lod_norm(vec2 pos) { float alt00 = alt_at(pos); - float alt10 = alt_at(pos + vec2(100, 0)); - float alt01 = alt_at(pos + vec2(0, 100)); + float alt10 = alt_at(pos + vec2(32, 0)); + float alt01 = alt_at(pos + vec2(0, 32)); float slope = abs(alt00 - alt10) + abs(alt00 - alt01); return normalize(vec3( - (alt00 - alt10) / 100, - (alt00 - alt01) / 100, - 100 / (slope + 0.00001) // Avoid NaN + (alt00 - alt10) / 32, + (alt00 - alt01) / 32, + 32 / (slope + 0.00001) // Avoid NaN )); } diff --git a/assets/voxygen/shaders/lod-terrain-vert.glsl b/assets/voxygen/shaders/lod-terrain-vert.glsl index 84456c45aa..a062187383 100644 --- a/assets/voxygen/shaders/lod-terrain-vert.glsl +++ b/assets/voxygen/shaders/lod-terrain-vert.glsl @@ -15,7 +15,7 @@ out vec3 f_pos; out float f_light; void main() { - f_pos = lod_pos(v_pos + vec2(0, -v_pos.x * 0.5)); + f_pos = lod_pos(v_pos); f_pos.z -= 1.0 / pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.95), 20.0); diff --git a/common/src/lib.rs b/common/src/lib.rs index 45e2ce2404..9ff6a7a9c5 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -24,6 +24,7 @@ pub mod npc; pub mod path; pub mod ray; pub mod region; +pub mod spiral; pub mod state; pub mod sync; pub mod sys; diff --git a/common/src/spiral.rs b/common/src/spiral.rs new file mode 100644 index 0000000000..c08dee7f18 --- /dev/null +++ b/common/src/spiral.rs @@ -0,0 +1,35 @@ +use vek::*; + +#[derive(Clone)] +pub struct Spiral2d { + layer: i32, + i: i32, +} + +impl Spiral2d { + pub fn new() -> Self { Self { layer: 0, i: 0 } } +} + +impl Iterator for Spiral2d { + type Item = Vec2; + + fn next(&mut self) -> Option { + let layer_size = (self.layer * 8 + 4 * self.layer.min(1) - 4).max(1); + if self.i >= layer_size { + self.layer += 1; + self.i = 0; + } + let layer_size = (self.layer * 8 + 4 * self.layer.min(1) - 4).max(1); + + let pos = Vec2::new( + -self.layer + (self.i - (layer_size / 4) * 0).max(0).min(self.layer * 2) + - (self.i - (layer_size / 4) * 2).max(0).min(self.layer * 2), + -self.layer + (self.i - (layer_size / 4) * 1).max(0).min(self.layer * 2) + - (self.i - (layer_size / 4) * 3).max(0).min(self.layer * 2), + ); + + self.i += 1; + + Some(pos) + } +} diff --git a/voxygen/src/render/mesh.rs b/voxygen/src/render/mesh.rs index 1d3a45431b..00b48ead59 100644 --- a/voxygen/src/render/mesh.rs +++ b/voxygen/src/render/mesh.rs @@ -1,4 +1,5 @@ use super::Pipeline; +use std::iter::FromIterator; /// A `Vec`-based mesh structure used to store mesh data on the CPU. #[derive(Clone)] @@ -57,6 +58,24 @@ impl Mesh

{ } } +impl FromIterator> for Mesh

{ + fn from_iter>>(tris: I) -> Self { + tris.into_iter().fold(Self::new(), |mut this, tri| { + this.push_tri(tri); + this + }) + } +} + +impl FromIterator> for Mesh

{ + fn from_iter>>(quads: I) -> Self { + quads.into_iter().fold(Self::new(), |mut this, quad| { + this.push_quad(quad); + this + }) + } +} + /// Represents a triangle stored on the CPU. pub struct Tri { a: P::Vertex, @@ -80,4 +99,18 @@ impl Quad

{ pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex, d: P::Vertex) -> Self { Self { a, b, c, d } } + + pub fn rotated_by(self, n: usize) -> Self + where + P::Vertex: Clone, + { + let verts = [self.a, self.b, self.c, self.d]; + + Self { + a: verts[(0 + n) % 4].clone(), + b: verts[(1 + n) % 4].clone(), + c: verts[(2 + n) % 4].clone(), + d: verts[(3 + n) % 4].clone(), + } + } } diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index 10b7b3eae1..ca245ce979 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -3,6 +3,7 @@ use crate::render::{ Consts, FilterMethod, Globals, LodTerrainPipeline, Mesh, Model, Quad, Renderer, Texture, }; use client::Client; +use common::spiral::Spiral2d; use vek::*; pub struct Lod { @@ -30,22 +31,25 @@ impl Lod { } fn create_lod_terrain_mesh(detail: usize) -> Mesh { - let transform = |x| (2.0 * x as f32) / detail as f32 - 1.0; + Spiral2d::new() + .take(detail * detail) + .map(|pos| { + let x = pos.x + detail as i32 / 2; + let y = pos.y + detail as i32 / 2; - let mut mesh = Mesh::new(); + let transform = |x| (2.0 * x as f32) / detail as f32 - 1.0; - for x in 0..detail { - for y in 0..detail { - if Vec2::new(x, y).map(transform).magnitude() <= 1.0 { - mesh.push_quad(Quad::new( - Vertex::new(Vec2::new(x + 0, y + 0).map(transform)), - Vertex::new(Vec2::new(x + 1, y + 0).map(transform)), - Vertex::new(Vec2::new(x + 1, y + 1).map(transform)), - Vertex::new(Vec2::new(x + 0, y + 1).map(transform)), - )); - } - } - } - - mesh + Quad::new( + Vertex::new(Vec2::new(x + 0, y + 0).map(transform)), + Vertex::new(Vec2::new(x + 1, y + 0).map(transform)), + Vertex::new(Vec2::new(x + 1, y + 1).map(transform)), + Vertex::new(Vec2::new(x + 0, y + 1).map(transform)), + ) + .rotated_by(if (x > detail as i32 / 2) ^ (y > detail as i32 / 2) { + 0 + } else { + 1 + }) + }) + .collect() } diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 3038236c4b..23943e8752 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -329,6 +329,13 @@ impl Scene { /// Render the scene using the provided `Renderer`. pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client) { // Render terrain and figures. + self.terrain.render( + renderer, + &self.globals, + &self.lights, + &self.shadows, + self.camera.get_focus_pos(), + ); self.figure_mgr.render( renderer, client, @@ -337,13 +344,6 @@ impl Scene { &self.shadows, &self.camera, ); - self.terrain.render( - renderer, - &self.globals, - &self.lights, - &self.shadows, - self.camera.get_focus_pos(), - ); self.lod.render(renderer, &self.globals); // Render the skybox. diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 80e98e3a37..e6c34934f6 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -10,6 +10,7 @@ use client::Client; use common::{ assets, figure::Segment, + spiral::Spiral2d, terrain::{Block, BlockKind, TerrainChunk}, vol::{BaseVol, ReadVol, RectRasterableVol, SampleVol, Vox}, volumes::vol_grid_2d::{VolGrid2d, VolGrid2dError}, @@ -1404,9 +1405,11 @@ impl Terrain { if *n >= chunks.len() { None } else { - *n += 1; let pos = focus_chunk + rpos; - Some(chunks.get(&pos).map(|c| (pos, c))) + Some(chunks.get(&pos).map(|c| { + *n += 1; + (pos, c) + })) } }) .filter_map(|x| x); @@ -1443,9 +1446,11 @@ impl Terrain { if *n >= chunks.len() { None } else { - *n += 1; let pos = focus_chunk + rpos; - Some(chunks.get(&pos).map(|c| (pos, c))) + Some(chunks.get(&pos).map(|c| { + *n += 1; + (pos, c) + })) } }) .filter_map(|x| x); @@ -1488,37 +1493,3 @@ impl Terrain { }); } } - -#[derive(Clone)] -struct Spiral2d { - layer: i32, - i: i32, -} - -impl Spiral2d { - pub fn new() -> Self { Self { layer: 0, i: 0 } } -} - -impl Iterator for Spiral2d { - type Item = Vec2; - - fn next(&mut self) -> Option { - let layer_size = (self.layer * 8 + 4 * self.layer.min(1) - 4).max(1); - if self.i >= layer_size { - self.layer += 1; - self.i = 0; - } - let layer_size = (self.layer * 8 + 4 * self.layer.min(1) - 4).max(1); - - let pos = Vec2::new( - -self.layer + (self.i - (layer_size / 4) * 0).max(0).min(self.layer * 2) - - (self.i - (layer_size / 4) * 2).max(0).min(self.layer * 2), - -self.layer + (self.i - (layer_size / 4) * 1).max(0).min(self.layer * 2) - - (self.i - (layer_size / 4) * 3).max(0).min(self.layer * 2), - ); - - self.i += 1; - - Some(pos) - } -} diff --git a/world/src/sim/map.rs b/world/src/sim/map.rs index aa812ab478..566a377ed2 100644 --- a/world/src/sim/map.rs +++ b/world/src/sim/map.rs @@ -291,7 +291,7 @@ impl MapConfig { ), }; - let rgba = (rgb.0, rgb.1, rgb.2, (255.0 * alt) as u8); + let rgba = (rgb.0, rgb.1, rgb.2, (255.0 * alt.max(water_alt)) as u8); write_pixel(Vec2::new(i, j), rgba); });