From f3464b36b9cdadebdf4a86a0b4dd7dc6f7891396 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 4 Jun 2019 13:45:41 +0100 Subject: [PATCH 01/21] Optimised sub-terrain chonk storage, fixed hash chunk bug, altered terrain base --- Cargo.lock | 1 + client/Cargo.toml | 1 + client/src/lib.rs | 14 ++- common/src/terrain/chonk.rs | 163 +++++++++++++++++++++++------------ voxygen/src/scene/terrain.rs | 4 +- world/src/lib.rs | 12 ++- world/src/sim.rs | 6 +- 7 files changed, 141 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 79e7642dc8..8bc98412fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2569,6 +2569,7 @@ dependencies = [ name = "veloren-client" version = "0.2.0" dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "specs 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)", "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "vek 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/client/Cargo.toml b/client/Cargo.toml index 847431764b..fecbfcdd11 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] common = { package = "veloren-common", path = "../common" } +log = "0.4" specs = "0.14" vek = "0.9" threadpool = "1.7" diff --git a/client/src/lib.rs b/client/src/lib.rs index 61f16c482b..ac6dca0ab3 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -12,18 +12,21 @@ use common::{ msg::{ClientMsg, ClientState, ServerInfo, ServerMsg}, net::PostBox, state::State, + terrain::chonk::ChonkMetrics, }; use std::{ collections::HashMap, net::SocketAddr, time::{Duration, Instant}, }; - use threadpool::ThreadPool; +use log::info; use vek::*; const SERVER_TIMEOUT: Duration = Duration::from_secs(20); +const DEBUG_METRICS: bool = true; + pub enum Event { Chat(String), Disconnect, @@ -308,6 +311,15 @@ impl Client { } } + // Output debug metrics + if DEBUG_METRICS && self.tick % 600 == 0 { + let metrics = self.state + .terrain() + .iter() + .fold(ChonkMetrics::default(), |a, (_, c)| a + c.get_metrics()); + info!("{:?}", metrics); + } + // 7) Finish the tick, pass control back to the frontend. self.tick += 1; diff --git a/common/src/terrain/chonk.rs b/common/src/terrain/chonk.rs index e5c4de955b..8e546b2fd2 100644 --- a/common/src/terrain/chonk.rs +++ b/common/src/terrain/chonk.rs @@ -4,7 +4,10 @@ use crate::{ volumes::chunk::{Chunk, ChunkErr}, }; use serde_derive::{Deserialize, Serialize}; -use std::collections::HashMap; +use std::{ + ops::Add, + collections::HashMap, +}; use vek::*; #[derive(Debug)] @@ -43,6 +46,24 @@ impl Chonk { self.z_offset + (self.sub_chunks.len() as u32 * SUB_CHUNK_HEIGHT) as i32 } + pub fn get_metrics(&self) -> ChonkMetrics { + ChonkMetrics { + chonks: 1, + homogeneous: self.sub_chunks + .iter() + .filter(|s| match s { SubChunk::Homogeneous(_) => true, _ => false }) + .count(), + hash: self.sub_chunks + .iter() + .filter(|s| match s { SubChunk::Hash(_, _) => true, _ => false }) + .count(), + heterogeneous: self.sub_chunks + .iter() + .filter(|s| match s { SubChunk::Heterogeneous(_) => true, _ => false }) + .count(), + } + } + fn sub_chunk_idx(&self, z: i32) -> usize { ((z - self.z_offset) as u32 / SUB_CHUNK_HEIGHT as u32) as usize } @@ -75,7 +96,7 @@ impl ReadVol for Chonk { - Vec3::unit_z() * (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32); - Ok(map.get(&rpos).unwrap_or(cblock)) + Ok(map.get(&rpos.map(|e| e as u8)).unwrap_or(cblock)) } SubChunk::Heterogeneous(chunk) => { let rpos = pos @@ -92,59 +113,61 @@ impl ReadVol for Chonk { impl WriteVol for Chonk { #[inline(always)] fn set(&mut self, pos: Vec3, block: Block) -> Result<(), ChonkError> { - if pos.z < self.z_offset { - Err(ChonkError::OutOfBounds) - } else { - let sub_chunk_idx = self.sub_chunk_idx(pos.z); + while pos.z < self.z_offset { + self.sub_chunks.insert(0, SubChunk::Homogeneous(self.below)); + self.z_offset -= SUB_CHUNK_HEIGHT as i32; + } - while self.sub_chunks.get(sub_chunk_idx).is_none() { - self.sub_chunks.push(SubChunk::Homogeneous(self.above)); - } - - let rpos = pos - - Vec3::unit_z() * (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32); - - match &mut self.sub_chunks[sub_chunk_idx] { - // Can't fail - SubChunk::Homogeneous(cblock) if *cblock == block => Ok(()), - SubChunk::Homogeneous(cblock) => { - let mut map = HashMap::new(); - map.insert(rpos, block); - - self.sub_chunks[sub_chunk_idx] = SubChunk::Hash(*cblock, map); - Ok(()) - } - SubChunk::Hash(cblock, map) if map.len() < 1024 => { - map.insert(rpos, block); - Ok(()) - } - SubChunk::Hash(cblock, map) => { - let mut new_chunk = Chunk::filled(*cblock, ()); - new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope) - - for (map_pos, map_block) in map { - new_chunk.set(*map_pos, *map_block).unwrap(); // Can't fail (I hope!) - } - - self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk); - Ok(()) - } - - /* - SubChunk::Homogeneous(cblock) => { - let mut new_chunk = Chunk::filled(*cblock, ()); - - new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope!) - - self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk); - Ok(()) - } - */ - SubChunk::Heterogeneous(chunk) => chunk - .set(rpos, block) - .map_err(|err| ChonkError::ChunkError(err)), - //_ => unimplemented!(), + let sub_chunk_idx = self.sub_chunk_idx(pos.z); + + while self.sub_chunks.get(sub_chunk_idx).is_none() { + self.sub_chunks.push(SubChunk::Homogeneous(self.above)); + } + + let rpos = pos + - Vec3::unit_z() * (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32); + + match &mut self.sub_chunks[sub_chunk_idx] { + // Can't fail + SubChunk::Homogeneous(cblock) if block == *cblock => Ok(()), + SubChunk::Homogeneous(cblock) => { + let mut map = HashMap::new(); + map.insert(rpos.map(|e| e as u8), block); + + self.sub_chunks[sub_chunk_idx] = SubChunk::Hash(*cblock, map); + Ok(()) + }, + SubChunk::Hash(cblock, map) if block == *cblock => Ok(()), + SubChunk::Hash(cblock, map) if map.len() < 4096 => { + map.insert(rpos.map(|e| e as u8), block); + Ok(()) + }, + SubChunk::Hash(cblock, map) => { + let mut new_chunk = Chunk::filled(*cblock, ()); + new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope) + + for (map_pos, map_block) in map { + new_chunk.set(map_pos.map(|e| e as i32), *map_block).unwrap(); // Can't fail (I hope!) + } + + self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk); + Ok(()) + }, + + /* + SubChunk::Homogeneous(cblock) => { + let mut new_chunk = Chunk::filled(*cblock, ()); + + new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope!) + + self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk); + Ok(()) } + */ + SubChunk::Heterogeneous(chunk) => chunk + .set(rpos, block) + .map_err(|err| ChonkError::ChunkError(err)), + //_ => unimplemented!(), } } } @@ -152,7 +175,7 @@ impl WriteVol for Chonk { #[derive(Debug, Clone, Serialize, Deserialize)] pub enum SubChunk { Homogeneous(Block), - Hash(Block, HashMap, Block>), + Hash(Block, HashMap, Block>), Heterogeneous(Chunk), } @@ -161,3 +184,35 @@ impl SubChunk { SubChunk::Homogeneous(block) } } + +#[derive(Debug)] +pub struct ChonkMetrics { + chonks: usize, + homogeneous: usize, + hash: usize, + heterogeneous: usize, +} + +impl Default for ChonkMetrics { + fn default() -> Self { + ChonkMetrics { + chonks: 0, + homogeneous: 0, + hash: 0, + heterogeneous: 0, + } + } +} + +impl Add for ChonkMetrics { + type Output = Self; + + fn add(self, other: Self::Output) -> Self { + Self::Output { + chonks: self.chonks + other.chonks, + homogeneous: self.homogeneous + other.homogeneous, + hash: self.hash + other.hash, + heterogeneous: self.heterogeneous + other.heterogeneous, + } + } +} diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index da8bd9ec82..9b072e9564 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -151,8 +151,8 @@ impl Terrain { .fold(i32::MIN, |max, (_, chunk)| chunk.get_z_max().max(max)); let aabb = Aabb { - min: Vec3::from(aabr.min) + Vec3::unit_z() * z_min, - max: Vec3::from(aabr.max) + Vec3::unit_z() * z_max, + min: Vec3::from(aabr.min) + Vec3::unit_z() * (z_min - 1), + max: Vec3::from(aabr.max) + Vec3::unit_z() * (z_max + 1), }; // Clone various things so that they can be moved into the thread. diff --git a/world/src/lib.rs b/world/src/lib.rs index 16a3acb68b..86b9ff877a 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -49,7 +49,10 @@ impl World { let warp_nz = BasicMulti::new().set_octaves(3).set_seed(self.sim.seed + 0); - let base_z = match self.sim.get_base_z(chunk_pos.map(|e| e as u32)) { + let base_z = match self.sim + .get(chunk_pos.map(|e| e as u32)) + .map(|chunk| chunk.get_base_z()) + { Some(base_z) => base_z as i32, None => return TerrainChunk::new(0, water, air, TerrainChunkMeta::void()), }; @@ -64,12 +67,17 @@ impl World { + Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32); let wposf2d = wpos2d.map(|e| e as f64); + let min_z = self + .sim + .get_interpolated(wpos2d, |chunk| chunk.get_min_z()) + .unwrap_or(0.0) as i32; + let max_z = self .sim .get_interpolated(wpos2d, |chunk| chunk.get_max_z()) .unwrap_or(0.0) as i32; - for z in base_z..max_z.max(sim::SEA_LEVEL as i32) { + for z in min_z..max_z { let lpos = Vec3::new(x, y, z); let wpos = lpos + Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32); diff --git a/world/src/sim.rs b/world/src/sim.rs index 411a18e02f..d38ed87a93 100644 --- a/world/src/sim.rs +++ b/world/src/sim.rs @@ -746,10 +746,14 @@ impl SimChunk { } pub fn get_base_z(&self) -> f32 { + self.alt - 8.0 + } + + pub fn get_min_z(&self) -> f32 { self.alt - Z_TOLERANCE.0 * (self.chaos + 0.3) } pub fn get_max_z(&self) -> f32 { - self.alt + Z_TOLERANCE.1 + (self.alt + Z_TOLERANCE.1).max(SEA_LEVEL) } } From 130cbca49abbdb95e4b0117c55277d0ef70fbc5f Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 4 Jun 2019 13:49:57 +0100 Subject: [PATCH 02/21] fmt --- client/src/lib.rs | 5 +++-- common/src/terrain/chonk.rs | 43 +++++++++++++++++++++++-------------- world/src/lib.rs | 3 ++- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index ac6dca0ab3..11d93cdc3c 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -14,13 +14,13 @@ use common::{ state::State, terrain::chonk::ChonkMetrics, }; +use log::info; use std::{ collections::HashMap, net::SocketAddr, time::{Duration, Instant}, }; use threadpool::ThreadPool; -use log::info; use vek::*; const SERVER_TIMEOUT: Duration = Duration::from_secs(20); @@ -313,7 +313,8 @@ impl Client { // Output debug metrics if DEBUG_METRICS && self.tick % 600 == 0 { - let metrics = self.state + let metrics = self + .state .terrain() .iter() .fold(ChonkMetrics::default(), |a, (_, c)| a + c.get_metrics()); diff --git a/common/src/terrain/chonk.rs b/common/src/terrain/chonk.rs index 8e546b2fd2..eed0b24e8f 100644 --- a/common/src/terrain/chonk.rs +++ b/common/src/terrain/chonk.rs @@ -4,10 +4,7 @@ use crate::{ volumes::chunk::{Chunk, ChunkErr}, }; use serde_derive::{Deserialize, Serialize}; -use std::{ - ops::Add, - collections::HashMap, -}; +use std::{collections::HashMap, ops::Add}; use vek::*; #[derive(Debug)] @@ -49,17 +46,29 @@ impl Chonk { pub fn get_metrics(&self) -> ChonkMetrics { ChonkMetrics { chonks: 1, - homogeneous: self.sub_chunks + homogeneous: self + .sub_chunks .iter() - .filter(|s| match s { SubChunk::Homogeneous(_) => true, _ => false }) + .filter(|s| match s { + SubChunk::Homogeneous(_) => true, + _ => false, + }) .count(), - hash: self.sub_chunks + hash: self + .sub_chunks .iter() - .filter(|s| match s { SubChunk::Hash(_, _) => true, _ => false }) + .filter(|s| match s { + SubChunk::Hash(_, _) => true, + _ => false, + }) .count(), - heterogeneous: self.sub_chunks + heterogeneous: self + .sub_chunks .iter() - .filter(|s| match s { SubChunk::Heterogeneous(_) => true, _ => false }) + .filter(|s| match s { + SubChunk::Heterogeneous(_) => true, + _ => false, + }) .count(), } } @@ -124,8 +133,8 @@ impl WriteVol for Chonk { self.sub_chunks.push(SubChunk::Homogeneous(self.above)); } - let rpos = pos - - Vec3::unit_z() * (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32); + let rpos = + pos - Vec3::unit_z() * (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32); match &mut self.sub_chunks[sub_chunk_idx] { // Can't fail @@ -136,23 +145,25 @@ impl WriteVol for Chonk { self.sub_chunks[sub_chunk_idx] = SubChunk::Hash(*cblock, map); Ok(()) - }, + } SubChunk::Hash(cblock, map) if block == *cblock => Ok(()), SubChunk::Hash(cblock, map) if map.len() < 4096 => { map.insert(rpos.map(|e| e as u8), block); Ok(()) - }, + } SubChunk::Hash(cblock, map) => { let mut new_chunk = Chunk::filled(*cblock, ()); new_chunk.set(rpos, block).unwrap(); // Can't fail (I hope) for (map_pos, map_block) in map { - new_chunk.set(map_pos.map(|e| e as i32), *map_block).unwrap(); // Can't fail (I hope!) + new_chunk + .set(map_pos.map(|e| e as i32), *map_block) + .unwrap(); // Can't fail (I hope!) } self.sub_chunks[sub_chunk_idx] = SubChunk::Heterogeneous(new_chunk); Ok(()) - }, + } /* SubChunk::Homogeneous(cblock) => { diff --git a/world/src/lib.rs b/world/src/lib.rs index 86b9ff877a..a94a887a27 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -49,7 +49,8 @@ impl World { let warp_nz = BasicMulti::new().set_octaves(3).set_seed(self.sim.seed + 0); - let base_z = match self.sim + let base_z = match self + .sim .get(chunk_pos.map(|e| e as u32)) .map(|chunk| chunk.get_base_z()) { From db5524a21af22e3805fcb65ebf78f8dff5e42089 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 4 Jun 2019 14:27:19 +0100 Subject: [PATCH 03/21] Deferred normal unpacking to the terrain fragment shader --- voxygen/shaders/terrain.frag | 14 +++++++++++++- voxygen/shaders/terrain.vert | 14 +++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/voxygen/shaders/terrain.frag b/voxygen/shaders/terrain.frag index 2c9cdb6c44..4561529aa3 100644 --- a/voxygen/shaders/terrain.frag +++ b/voxygen/shaders/terrain.frag @@ -3,7 +3,7 @@ #include in vec3 f_pos; -in vec3 f_norm; +flat in uint f_pos_norm; in vec3 f_col; in float f_light; @@ -15,6 +15,18 @@ uniform u_locals { out vec4 tgt_color; void main() { + // Calculate normal from packed data + vec3 f_norm; + uint norm_axis = (f_pos_norm >> 30) & 0x3u; + float norm_dir = float((f_pos_norm >> 29) & 0x1u) * 2.0 - 1.0; + if (norm_axis == 0u) { + f_norm = vec3(1.0, 0.0, 0.0) * norm_dir; + } else if (norm_axis == 1u) { + f_norm = vec3(0.0, 1.0, 0.0) * norm_dir; + } else { + f_norm = vec3(0.0, 0.0, 1.0) * norm_dir; + } + float glob_ambience = 0.001; float sun_ambience = 0.9; diff --git a/voxygen/shaders/terrain.vert b/voxygen/shaders/terrain.vert index cbf11d2747..1a448dbba3 100644 --- a/voxygen/shaders/terrain.vert +++ b/voxygen/shaders/terrain.vert @@ -11,7 +11,7 @@ uniform u_locals { }; out vec3 f_pos; -out vec3 f_norm; +flat out uint f_pos_norm; out vec3 f_col; out float f_light; @@ -22,22 +22,14 @@ void main() { float((v_pos_norm >> 16) & 0x1FFFu) ) + model_offs; + f_pos_norm = v_pos_norm; + f_col = vec3( float((v_col_light >> 8) & 0xFFu), float((v_col_light >> 16) & 0xFFu), float((v_col_light >> 24) & 0xFFu) ) / 255.0; - uint norm_axis = (v_pos_norm >> 30) & 0x3u; - float norm_dir = float((v_pos_norm >> 29) & 0x1u) * 2.0 - 1.0; - if (norm_axis == 0u) { - f_norm = vec3(1.0, 0.0, 0.0) * norm_dir; - } else if (norm_axis == 1u) { - f_norm = vec3(0.0, 1.0, 0.0) * norm_dir; - } else { - f_norm = vec3(0.0, 0.0, 1.0) * norm_dir; - } - f_light = float(v_col_light & 0xFFu) / 255.0; gl_Position = From a49e061c7b6ae59c40b09857f6b58b8e69a9a11b Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 4 Jun 2019 18:19:40 +0100 Subject: [PATCH 04/21] Added rocks --- common/src/terrain/chonk.rs | 4 +- voxygen/src/scene/terrain.rs | 12 +- world/src/lib.rs | 12 +- world/src/sim.rs | 256 +++++++++++++++++++---------------- 4 files changed, 151 insertions(+), 133 deletions(-) diff --git a/common/src/terrain/chonk.rs b/common/src/terrain/chonk.rs index eed0b24e8f..4373d378c5 100644 --- a/common/src/terrain/chonk.rs +++ b/common/src/terrain/chonk.rs @@ -35,11 +35,11 @@ impl Chonk { } } - pub fn get_z_min(&self) -> i32 { + pub fn get_min_z(&self) -> i32 { self.z_offset } - pub fn get_z_max(&self) -> i32 { + pub fn get_max_z(&self) -> i32 { self.z_offset + (self.sub_chunks.len() as u32 * SUB_CHUNK_HEIGHT) as i32 } diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 9b072e9564..8e1a39d57c 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -143,16 +143,16 @@ impl Terrain { }; // The region to actually mesh - let z_min = volume + let min_z = volume .iter() - .fold(i32::MAX, |min, (_, chunk)| chunk.get_z_min().min(min)); - let z_max = volume + .fold(i32::MAX, |min, (_, chunk)| chunk.get_min_z().min(min)); + let max_z = volume .iter() - .fold(i32::MIN, |max, (_, chunk)| chunk.get_z_max().max(max)); + .fold(i32::MIN, |max, (_, chunk)| chunk.get_max_z().max(max)); let aabb = Aabb { - min: Vec3::from(aabr.min) + Vec3::unit_z() * (z_min - 1), - max: Vec3::from(aabr.max) + Vec3::unit_z() * (z_max + 1), + min: Vec3::from(aabr.min) + Vec3::unit_z() * (min_z - 1), + max: Vec3::from(aabr.max) + Vec3::unit_z() * (max_z + 1), }; // Clone various things so that they can be moved into the thread. diff --git a/world/src/lib.rs b/world/src/lib.rs index a94a887a27..7fa22f96de 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -49,16 +49,16 @@ impl World { let warp_nz = BasicMulti::new().set_octaves(3).set_seed(self.sim.seed + 0); - let base_z = match self - .sim - .get(chunk_pos.map(|e| e as u32)) - .map(|chunk| chunk.get_base_z()) - { + let chunk_size2d = Vec2::from(TerrainChunkSize::SIZE); + let base_z = match self.sim.get_interpolated( + chunk_pos.map2(chunk_size2d, |e, sz: u32| e * sz as i32 + sz as i32 / 2), + |chunk| chunk.get_base_z(), + ) { Some(base_z) => base_z as i32, None => return TerrainChunk::new(0, water, air, TerrainChunkMeta::void()), }; - let mut chunk = TerrainChunk::new(base_z, stone, air, TerrainChunkMeta::void()); + let mut chunk = TerrainChunk::new(base_z - 8, stone, air, TerrainChunkMeta::void()); let mut world_sampler = self.sim.sampler(); diff --git a/world/src/sim.rs b/world/src/sim.rs index d38ed87a93..e5329f35de 100644 --- a/world/src/sim.rs +++ b/world/src/sim.rs @@ -75,7 +75,7 @@ impl WorldSim { seed, chunks, gen_ctx, - tree_gen: StructureGen2d::new(seed, 32, 28), + tree_gen: StructureGen2d::new(seed, 24, 16), } } @@ -165,15 +165,14 @@ impl<'a> Sampler<'a> { let rock = (sim.gen_ctx.small_nz.get((wposf.div(100.0)).into_array()) as f32) .mul(rockiness) - .sub(0.2) + .sub(0.35) .max(0.0) - .mul(2.0); + .mul(6.0); let alt = sim.get_interpolated(wpos, |chunk| chunk.alt)? + sim.gen_ctx.small_nz.get((wposf.div(256.0)).into_array()) as f32 * chaos.max(0.2) - * 64.0 - + rock * 15.0; + * 64.0; let wposf3d = Vec3::new(wposf.x, wposf.y, alt as f64); @@ -191,7 +190,7 @@ impl<'a> Sampler<'a> { let snow = Rgb::broadcast(1.0); let grass = Rgb::lerp(cold_grass, warm_grass, marble); - let grassland = Rgb::lerp(grass, warm_stone, rock.mul(5.0).min(0.8)); + let grassland = grass; //Rgb::lerp(grass, warm_stone, rock.mul(5.0).min(0.8)); let cliff = Rgb::lerp(cold_stone, warm_stone, marble); let ground = Rgb::lerp( @@ -240,9 +239,14 @@ impl<'a> Sampler<'a> { Rgb::lerp( cliff, snow, - (alt - SEA_LEVEL - 350.0 - alt_base - temp * 48.0) / 12.0, + (alt - SEA_LEVEL + - 0.3 * MOUNTAIN_HEIGHT + - alt_base + - temp * 96.0 + - marble * 24.0) + / 12.0, ), - (alt - SEA_LEVEL - 150.0) / 180.0, + (alt - SEA_LEVEL - 0.15 * MOUNTAIN_HEIGHT) / 180.0, ), // Beach (alt - SEA_LEVEL - 2.0) / 5.0, @@ -251,6 +255,7 @@ impl<'a> Sampler<'a> { close_trees: sim.tree_gen.sample(wpos), cave_xy, cave_alt, + rock, }) } @@ -275,6 +280,7 @@ impl<'a> Sampler<'a> { close_trees, cave_xy, cave_alt, + rock, } = *self.sample_2d(wpos2d)?; // Apply warping @@ -289,7 +295,6 @@ impl<'a> Sampler<'a> { .mul(110.0); let height = alt + warp; - let temp = 0.0; // Sample blocks @@ -298,6 +303,7 @@ impl<'a> Sampler<'a> { let dirt = Block::new(1, Rgb::new(128, 90, 0)); let sand = Block::new(1, Rgb::new(180, 150, 50)); let water = Block::new(1, Rgb::new(100, 150, 255)); + let warm_stone = Block::new(1, Rgb::new(165, 165, 90)); let ground_block = if (wposf.z as f32) < height - 4.0 { // Underground @@ -312,7 +318,8 @@ impl<'a> Sampler<'a> { None }; - let ground_block = if let Some(block) = ground_block { + // Caves + let block = ground_block.or_else(|| { // Underground let cave = cave_xy.powf(2.0) * (wposf.z as f32 - cave_alt) @@ -325,13 +332,20 @@ impl<'a> Sampler<'a> { if cave { None } else { - Some(block) + ground_block } - } else { - None - }; + }); - let block = match ground_block { + // Rocks + let block = block.or_else(|| { + if (height + 2.5 - wposf.z as f32).div(7.5).abs().powf(2.0) < rock { + Some(warm_stone) + } else { + None + } + }); + + let block = match block { Some(block) => block, None => (&close_trees) .iter() @@ -357,6 +371,114 @@ impl<'a> Sampler<'a> { } } +#[derive(Copy, Clone)] +pub struct Sample2d { + pub alt: f32, + pub chaos: f32, + pub surface_color: Rgb, + pub tree_density: f32, + pub close_trees: [(Vec2, u32); 9], + pub cave_xy: f32, + pub cave_alt: f32, + pub rock: f32, +} + +#[derive(Copy, Clone)] +pub struct Sample3d { + pub block: Block, +} + +pub const SEA_LEVEL: f32 = 128.0; +pub const MOUNTAIN_HEIGHT: f32 = 900.0; + +const Z_TOLERANCE: (f32, f32) = (64.0, 64.0); + +pub struct SimChunk { + pub chaos: f32, + pub alt_base: f32, + pub alt: f32, + pub temp: f32, + pub rockiness: f32, + pub tree_density: f32, +} + +impl SimChunk { + fn generate(pos: Vec2, gen_ctx: &mut GenCtx) -> Self { + let wposf = (pos * Vec2::from(TerrainChunkSize::SIZE)).map(|e| e as f64); + + let hill = (0.0 + + gen_ctx + .hill_nz + .get((wposf.div(3_500.0)).into_array()) + .mul(1.0) as f32 + + gen_ctx + .hill_nz + .get((wposf.div(1_000.0)).into_array()) + .mul(0.3) as f32) + .add(0.3) + .max(0.0); + + let chaos = (gen_ctx.chaos_nz.get((wposf.div(2_000.0)).into_array()) as f32) + .add(1.0) + .mul(0.5) + .powf(1.5) + .add(0.1 * hill); + + let chaos = chaos + chaos.mul(16.0).sin().mul(0.02); + + let alt_base = gen_ctx.alt_nz.get((wposf.div(6_000.0)).into_array()) as f32; + let alt_base = alt_base + .mul(0.4) + .add(alt_base.mul(128.0).sin().mul(0.005)) + .mul(800.0); + + let alt_main = gen_ctx.alt_nz.get((wposf.div(2_500.0)).into_array()) as f32; + + let alt = SEA_LEVEL + + alt_base + + (0.0 + + alt_main + + gen_ctx.small_nz.get((wposf.div(300.0)).into_array()) as f32 + * alt_main.max(0.05) + * chaos + * 1.6) + .add(1.0) + .mul(0.5) + .mul(chaos) + .mul(MOUNTAIN_HEIGHT); + + Self { + chaos, + alt_base, + alt, + temp: (gen_ctx.temp_nz.get((wposf.div(8192.0)).into_array()) as f32), + rockiness: (gen_ctx.rock_nz.get((wposf.div(1024.0)).into_array()) as f32) + .sub(0.1) + .mul(1.2) + .max(0.0), + tree_density: (gen_ctx.tree_nz.get((wposf.div(1024.0)).into_array()) as f32) + .add(1.0) + .mul(0.5) + .mul(1.0 - chaos * 0.85) + .mul(1.25) + .add(0.1) + .mul(if alt > SEA_LEVEL + 2.0 { 1.0 } else { 0.0 }), + } + } + + pub fn get_base_z(&self) -> f32 { + self.alt + } + + pub fn get_min_z(&self) -> f32 { + self.alt - Z_TOLERANCE.0 * (self.chaos + 0.5) + } + + pub fn get_max_z(&self) -> f32 { + (self.alt + Z_TOLERANCE.1).max(SEA_LEVEL + 1.0) + } +} + lazy_static! { static ref TREES: [Arc; 61] = [ // green oaks @@ -653,107 +775,3 @@ lazy_static! { ]; } - -#[derive(Copy, Clone)] -pub struct Sample2d { - pub alt: f32, - pub chaos: f32, - pub surface_color: Rgb, - pub tree_density: f32, - pub close_trees: [(Vec2, u32); 9], - pub cave_xy: f32, - pub cave_alt: f32, -} - -#[derive(Copy, Clone)] -pub struct Sample3d { - pub block: Block, -} - -const Z_TOLERANCE: (f32, f32) = (126.0, 94.0); -pub const SEA_LEVEL: f32 = 128.0; - -pub struct SimChunk { - pub chaos: f32, - pub alt_base: f32, - pub alt: f32, - pub temp: f32, - pub rockiness: f32, - pub tree_density: f32, -} - -impl SimChunk { - fn generate(pos: Vec2, gen_ctx: &mut GenCtx) -> Self { - let wposf = (pos * Vec2::from(TerrainChunkSize::SIZE)).map(|e| e as f64); - - let hill = (0.0 - + gen_ctx - .hill_nz - .get((wposf.div(3_500.0)).into_array()) - .mul(1.0) as f32 - + gen_ctx - .hill_nz - .get((wposf.div(1_000.0)).into_array()) - .mul(0.3) as f32) - .add(0.3) - .max(0.0); - - let chaos = (gen_ctx.chaos_nz.get((wposf.div(4_000.0)).into_array()) as f32) - .add(1.0) - .mul(0.5) - .powf(1.5) - .add(0.1 * hill); - - let chaos = chaos + chaos.mul(16.0).sin().mul(0.02); - - let alt_base = gen_ctx.alt_nz.get((wposf.div(6_000.0)).into_array()) as f32; - let alt_base = alt_base - .mul(0.4) - .add(alt_base.mul(128.0).sin().mul(0.004)) - .mul(600.0); - - let alt_main = gen_ctx.alt_nz.get((wposf.div(1_500.0)).into_array()) as f32; - - let alt = SEA_LEVEL - + alt_base - + (0.0 - + alt_main - + gen_ctx.small_nz.get((wposf.div(300.0)).into_array()) as f32 - * alt_main.max(0.05) - * chaos - * 1.3) - .add(1.0) - .mul(0.5) - .mul(chaos) - .mul(1200.0); - - Self { - chaos, - alt_base, - alt, - temp: (gen_ctx.temp_nz.get((wposf.div(8192.0)).into_array()) as f32), - rockiness: (gen_ctx.rock_nz.get((wposf.div(1024.0)).into_array()) as f32) - .sub(0.1) - .mul(1.2) - .max(0.0), - tree_density: (gen_ctx.tree_nz.get((wposf.div(1024.0)).into_array()) as f32) - .add(1.0) - .mul(0.5) - .mul(1.0 - chaos * 0.85) - .add(0.1) - .mul(if alt > SEA_LEVEL + 3.0 { 1.0 } else { 0.0 }), - } - } - - pub fn get_base_z(&self) -> f32 { - self.alt - 8.0 - } - - pub fn get_min_z(&self) -> f32 { - self.alt - Z_TOLERANCE.0 * (self.chaos + 0.3) - } - - pub fn get_max_z(&self) -> f32 { - (self.alt + Z_TOLERANCE.1).max(SEA_LEVEL) - } -} From bdc9a3c731de62c48d65e0af6542bab0e639cc51 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 4 Jun 2019 18:27:58 +0100 Subject: [PATCH 05/21] Tweaked mountain base scale --- world/src/sim.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/world/src/sim.rs b/world/src/sim.rs index e5329f35de..d1bf63b25e 100644 --- a/world/src/sim.rs +++ b/world/src/sim.rs @@ -49,7 +49,7 @@ impl WorldSim { chaos_nz: RidgedMulti::new().set_octaves(7).set_seed(seed + 2), hill_nz: SuperSimplex::new().set_seed(seed + 3), alt_nz: HybridMulti::new() - .set_octaves(7) + .set_octaves(8) .set_persistence(0.1) .set_seed(seed + 4), temp_nz: SuperSimplex::new().set_seed(seed + 5), @@ -432,7 +432,7 @@ impl SimChunk { .add(alt_base.mul(128.0).sin().mul(0.005)) .mul(800.0); - let alt_main = gen_ctx.alt_nz.get((wposf.div(2_500.0)).into_array()) as f32; + let alt_main = gen_ctx.alt_nz.get((wposf.div(3_000.0)).into_array()) as f32; let alt = SEA_LEVEL + alt_base From 672275633c9d83c0e81199c512e8e31983cccea3 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 14:13:24 +0100 Subject: [PATCH 06/21] Reduced threadpool threads to keep render thread smooth --- client/src/lib.rs | 18 ++++++++++++++---- server/src/lib.rs | 6 ++++++ voxygen/shaders/postprocess.frag | 2 +- voxygen/shaders/terrain.frag | 11 ++++++++++- voxygen/src/anim/character/run.rs | 14 +++++++------- voxygen/src/menu/main/start_singleplayer.rs | 3 ++- voxygen/src/render/renderer.rs | 4 ++-- voxygen/src/scene/figure.rs | 3 ++- voxygen/src/scene/mod.rs | 2 +- voxygen/src/singleplayer.rs | 11 +++++++++-- world/src/sim.rs | 7 ++++--- 11 files changed, 58 insertions(+), 23 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 11d93cdc3c..f6e2fa5d29 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -76,11 +76,15 @@ impl Client { postbox.send_message(ClientMsg::Ping); + let mut thread_pool = threadpool::Builder::new() + .thread_name("veloren-worker".into()) + .build(); + // We reduce the thread count by 1 to keep rendering smooth + thread_pool.set_num_threads((thread_pool.max_count() - 1).max(1)); + Ok(Self { client_state, - thread_pool: threadpool::Builder::new() - .thread_name("veloren-worker".into()) - .build(), + thread_pool, server_info, postbox, @@ -97,6 +101,12 @@ impl Client { }) } + #[allow(dead_code)] + pub fn with_thread_pool(mut self, thread_pool: ThreadPool) -> Self { + self.thread_pool = thread_pool; + self + } + /// Request a state transition to `ClientState::Registered`. pub fn register(&mut self, player: comp::Player) { self.postbox.send_message(ClientMsg::Register { player }); @@ -434,7 +444,7 @@ impl Client { /// computationally expensive operations that run outside of the main thread (i.e., threads that /// block on I/O operations are exempt). #[allow(dead_code)] - pub fn thread_pool(&self) -> &threadpool::ThreadPool { + pub fn thread_pool(&self) -> &ThreadPool { &self.thread_pool } diff --git a/server/src/lib.rs b/server/src/lib.rs index 9c657c517b..d680fe79a4 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -122,6 +122,12 @@ impl Server { Ok(this) } + #[allow(dead_code)] + pub fn with_thread_pool(mut self, thread_pool: ThreadPool) -> Self { + self.thread_pool = thread_pool; + self + } + /// Get a reference to the server's game state. #[allow(dead_code)] pub fn state(&self) -> &State { diff --git a/voxygen/shaders/postprocess.frag b/voxygen/shaders/postprocess.frag index 304a0de91c..8eda152c57 100644 --- a/voxygen/shaders/postprocess.frag +++ b/voxygen/shaders/postprocess.frag @@ -171,5 +171,5 @@ void main() { //hsva_color.z = 1.0 - 1.0 / (1.0 * hsva_color.z + 1.0); vec4 final_color = vec4(hsv2rgb(hsva_color.rgb), hsva_color.a); - tgt_color = final_color; + tgt_color = vec4(final_color.rgb, 0.5); } diff --git a/voxygen/shaders/terrain.frag b/voxygen/shaders/terrain.frag index 4561529aa3..ac07bd0ef9 100644 --- a/voxygen/shaders/terrain.frag +++ b/voxygen/shaders/terrain.frag @@ -14,6 +14,11 @@ uniform u_locals { out vec4 tgt_color; +float fog() { + float half_vd = 0.95 * view_distance.x / 2.0; + return clamp(distance(f_pos, cam_pos.xyz) / half_vd - 1.0, 0.0, 1.0); +} + void main() { // Calculate normal from packed data vec3 f_norm; @@ -40,5 +45,9 @@ void main() { vec3 light = vec3(static_light); - tgt_color = vec4(f_col * light, 1.0); + vec3 frag_color = f_col * light; + + vec3 fog_color = vec3(0.0, 0.25, 0.55); + + tgt_color = vec4(mix(frag_color, fog_color, fog()), 1.0); } diff --git a/voxygen/src/anim/character/run.rs b/voxygen/src/anim/character/run.rs index 6e1937380a..53845caeec 100644 --- a/voxygen/src/anim/character/run.rs +++ b/voxygen/src/anim/character/run.rs @@ -38,7 +38,7 @@ impl Animation for RunAnimation { next.head.offset = Vec3::new(0.0, 3.0, 12.0 + wave_cos * 1.3); next.head.ori = - Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y + 0.35); + Quaternion::rotation_z(head_look.x + wave * 0.1) * Quaternion::rotation_x(head_look.y + 0.35); next.head.scale = Vec3::one(); next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_cos * 1.1); @@ -53,20 +53,20 @@ impl Animation for RunAnimation { next.shorts.ori = Quaternion::rotation_z(wave * 0.6); next.shorts.scale = Vec3::one(); - next.l_hand.offset = Vec3::new(-8.0, 3.0 + wave_cos * 5.0, 9.0 - wave * 2.0) / 11.0; + next.l_hand.offset = Vec3::new(-9.0, 3.0 + wave_cos * 8.0, 12.0 - wave * 1.0) / 11.0; next.l_hand.ori = Quaternion::rotation_x(wave_cos * 1.1); next.l_hand.scale = Vec3::one() / 11.0; - next.r_hand.offset = Vec3::new(8.0, 3.0 - wave_cos * 5.0, 9.0 + wave * 2.0) / 11.0; + next.r_hand.offset = Vec3::new(9.0, 3.0 - wave_cos * 8.0, 12.0 + wave * 1.0) / 11.0; next.r_hand.ori = Quaternion::rotation_x(wave_cos * -1.1); next.r_hand.scale = Vec3::one() / 11.0; - next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave * 1.0, 6.0); - next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave * 1.5); + next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave_cos * 1.0, 6.0); + next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave_cos * 1.5); next.l_foot.scale = Vec3::one(); - next.r_foot.offset = Vec3::new(3.4, 0.0 - wave * 1.0, 6.0); - next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave * 1.5); + next.r_foot.offset = Vec3::new(3.4, 0.0 - wave_cos * 1.0, 6.0); + next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave_cos * 1.5); next.r_foot.scale = Vec3::one(); next.weapon.offset = Vec3::new(-7.0, -5.0, 15.0); diff --git a/voxygen/src/menu/main/start_singleplayer.rs b/voxygen/src/menu/main/start_singleplayer.rs index a44efca663..9ab08b138a 100644 --- a/voxygen/src/menu/main/start_singleplayer.rs +++ b/voxygen/src/menu/main/start_singleplayer.rs @@ -4,6 +4,7 @@ use crate::{ PlayState, PlayStateResult, }; use common::comp; +use client::Client; use log::warn; use std::net::SocketAddr; @@ -15,7 +16,7 @@ pub struct StartSingleplayerState { impl StartSingleplayerState { /// Create a new `MainMenuState`. pub fn new() -> Self { - let (singleplayer, sock) = Singleplayer::new(); + let (singleplayer, sock) = Singleplayer::new(None); // TODO: Make client and server use the same thread pool Self { singleplayer, sock } } diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index fa7317ae89..794b59ca4b 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -230,9 +230,9 @@ impl Renderer { /// Queue the clearing of the color and depth targets ready for a new frame to be rendered. /// TODO: Make a version of this that doesn't clear the colour target for speed. pub fn clear(&mut self, col: Rgba) { - self.encoder.clear(&self.tgt_color_view, col.into_array()); + //self.encoder.clear(&self.tgt_color_view, col.into_array()); self.encoder.clear_depth(&self.tgt_depth_view, 1.0); - self.encoder.clear(&self.win_color_view, col.into_array()); + //self.encoder.clear(&self.win_color_view, col.into_array()); self.encoder.clear_depth(&self.win_depth_view, 1.0); } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 0c17815f6b..8be3ca11b4 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -742,7 +742,8 @@ impl FigureState { ) { let mat = Mat4::::identity() * Mat4::translation_3d(pos) - * Mat4::rotation_z(-ori.x.atan2(ori.y)); // + f32::consts::PI / 2.0); + * Mat4::rotation_z(-ori.x.atan2(ori.y)) // + f32::consts::PI / 2.0); + * Mat4::scaling_3d(Vec3::from(0.8)); let locals = FigureLocals::new(mat, col); renderer.update_consts(&mut self.locals, &[locals]).unwrap(); diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 0f8d33f4ce..f768afa6c6 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -136,7 +136,7 @@ impl Scene { proj_mat, cam_pos, self.camera.get_focus_pos(), - 10.0, + client.view_distance().unwrap_or(0) as f32 * 32.0, // TODO: No magic numbers client.state().get_time_of_day(), client.state().get_time(), renderer.get_resolution(), diff --git a/voxygen/src/singleplayer.rs b/voxygen/src/singleplayer.rs index 4c78a9f550..27bb198596 100644 --- a/voxygen/src/singleplayer.rs +++ b/voxygen/src/singleplayer.rs @@ -1,4 +1,5 @@ use common::clock::Clock; +use client::Client; use log::info; use portpicker::pick_unused_port; use server::{Event, Input, Server}; @@ -23,7 +24,7 @@ pub struct Singleplayer { } impl Singleplayer { - pub fn new() -> (Self, SocketAddr) { + pub fn new(client: Option<&Client>) -> (Self, SocketAddr) { let (sender, receiver) = channel(); let sock = SocketAddr::from(( @@ -32,7 +33,13 @@ impl Singleplayer { )); // Create server - let server = Server::bind(sock.clone()).expect("Failed to create server instance!"); + let server = Server::bind(sock.clone()) + .expect("Failed to create server instance!"); + + let server = match client { + Some(client) => server.with_thread_pool(client.thread_pool().clone()), + None => server, + }; let thread = thread::spawn(move || { run_server(server, receiver); diff --git a/world/src/sim.rs b/world/src/sim.rs index d1bf63b25e..2415bd2389 100644 --- a/world/src/sim.rs +++ b/world/src/sim.rs @@ -57,8 +57,8 @@ impl WorldSim { rock_nz: HybridMulti::new().set_persistence(0.3).set_seed(seed + 7), warp_nz: BasicMulti::new().set_octaves(3).set_seed(seed + 8), tree_nz: BasicMulti::new() - .set_octaves(8) - .set_persistence(0.75) + .set_octaves(12) + .set_persistence(0.9) .set_seed(seed + 9), cave_0_nz: SuperSimplex::new().set_seed(seed + 10), cave_1_nz: SuperSimplex::new().set_seed(seed + 11), @@ -357,8 +357,9 @@ impl<'a> Sampler<'a> { { let tree_pos3d = Vec3::new(tree_pos.x, tree_pos.y, tree_sample.alt as i32); + let rpos = wpos - tree_pos3d; block.or(TREES[*tree_seed as usize % TREES.len()] - .get(wpos - tree_pos3d) + .get((rpos * 160) / 128) // Scaling .map(|b| b.clone()) .unwrap_or(Block::empty())) } From ca4a0e7bc127febbb89bdba2302c0b8b0245e80e Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 16:22:06 +0100 Subject: [PATCH 07/21] Added proper VD fog --- Cargo.lock | 1 + common/Cargo.toml | 1 + common/src/terrain/chonk.rs | 39 +++++++++++++++++++-- common/src/vol.rs | 8 ++++- common/src/volumes/chunk.rs | 12 +++++++ common/src/volumes/dyna.rs | 13 +++++++ common/src/volumes/vol_map_2d.rs | 21 +++++++---- common/src/volumes/vol_map_3d.rs | 10 +++--- voxygen/shaders/figure.frag | 9 ++++- voxygen/shaders/figure.vert | 11 +++--- voxygen/shaders/include/sky.glsl | 27 ++++++++++++++ voxygen/shaders/postprocess.frag | 2 +- voxygen/shaders/skybox.frag | 22 +----------- voxygen/shaders/terrain.frag | 14 ++++---- voxygen/src/anim/character/run.rs | 4 +-- voxygen/src/menu/main/start_singleplayer.rs | 2 +- voxygen/src/mesh/terrain.rs | 20 +++++------ voxygen/src/render/renderer.rs | 2 +- voxygen/src/scene/camera.rs | 2 +- voxygen/src/singleplayer.rs | 5 ++- 20 files changed, 153 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8bc98412fb..6c16661e04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2582,6 +2582,7 @@ version = "0.2.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/common/Cargo.toml b/common/Cargo.toml index ddb7f68de2..92245e75b3 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -23,3 +23,4 @@ rand = "0.6.5" rayon = "1.0" lazy_static = "1.3" lz4-compress = "0.1" +fxhash = "0.2" diff --git a/common/src/terrain/chonk.rs b/common/src/terrain/chonk.rs index 4373d378c5..919a97c94d 100644 --- a/common/src/terrain/chonk.rs +++ b/common/src/terrain/chonk.rs @@ -3,6 +3,7 @@ use crate::{ vol::{BaseVol, ReadVol, VolSize, WriteVol}, volumes::chunk::{Chunk, ChunkErr}, }; +use fxhash::FxHashMap; use serde_derive::{Deserialize, Serialize}; use std::{collections::HashMap, ops::Add}; use vek::*; @@ -117,6 +118,40 @@ impl ReadVol for Chonk { } } } + + #[inline(always)] + unsafe fn get_unchecked(&self, pos: Vec3) -> &Block { + if pos.z < self.z_offset { + // Below the terrain + &self.below + } else if pos.z >= self.z_offset + SUB_CHUNK_HEIGHT as i32 * self.sub_chunks.len() as i32 { + // Above the terrain + &self.above + } else { + // Within the terrain + + let sub_chunk_idx = self.sub_chunk_idx(pos.z); + + match &self.sub_chunks[sub_chunk_idx] { + // Can't fail + SubChunk::Homogeneous(block) => block, + SubChunk::Hash(cblock, map) => { + let rpos = pos + - Vec3::unit_z() + * (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32); + + map.get(&rpos.map(|e| e as u8)).unwrap_or(cblock) + } + SubChunk::Heterogeneous(chunk) => { + let rpos = pos + - Vec3::unit_z() + * (self.z_offset + sub_chunk_idx as i32 * SUB_CHUNK_HEIGHT as i32); + + chunk.get_unchecked(rpos) + } + } + } + } } impl WriteVol for Chonk { @@ -140,7 +175,7 @@ impl WriteVol for Chonk { // Can't fail SubChunk::Homogeneous(cblock) if block == *cblock => Ok(()), SubChunk::Homogeneous(cblock) => { - let mut map = HashMap::new(); + let mut map = FxHashMap::default(); map.insert(rpos.map(|e| e as u8), block); self.sub_chunks[sub_chunk_idx] = SubChunk::Hash(*cblock, map); @@ -186,7 +221,7 @@ impl WriteVol for Chonk { #[derive(Debug, Clone, Serialize, Deserialize)] pub enum SubChunk { Homogeneous(Block), - Hash(Block, HashMap, Block>), + Hash(Block, FxHashMap, Block>), Heterogeneous(Chunk), } diff --git a/common/src/vol.rs b/common/src/vol.rs index 3a063a6de5..6b800d8793 100644 --- a/common/src/vol.rs +++ b/common/src/vol.rs @@ -1,4 +1,5 @@ use crate::ray::{Ray, RayUntil}; +use std::fmt::Debug; use vek::*; /// A voxel. @@ -18,7 +19,7 @@ pub trait Vox: Sized { /// A volume that contains voxel data. pub trait BaseVol { type Vox: Vox; - type Err; + type Err: Debug; } // Utility types @@ -73,6 +74,11 @@ pub trait ReadVol: BaseVol { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&Self::Vox, Self::Err>; + #[inline(always)] + unsafe fn get_unchecked(&self, pos: Vec3) -> &Self::Vox { + self.get(pos).unwrap() + } + fn ray(&self, from: Vec3, to: Vec3) -> Ray bool> where Self: Sized, diff --git a/common/src/volumes/chunk.rs b/common/src/volumes/chunk.rs index 4e61190b9c..e395a762ef 100644 --- a/common/src/volumes/chunk.rs +++ b/common/src/volumes/chunk.rs @@ -40,6 +40,13 @@ impl Chunk { None } } + + /// Used to transform a voxel position in the volume into its corresponding index + /// in the voxel array. + #[inline(always)] + fn idx_for_unchecked(pos: Vec3) -> usize { + (pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 + pos.y * S::SIZE.z as i32 + pos.z) as usize + } } impl BaseVol for Chunk { @@ -61,6 +68,11 @@ impl ReadVol for Chunk { .and_then(|idx| self.vox.get(idx)) .ok_or(ChunkErr::OutOfBounds) } + + #[inline(always)] + unsafe fn get_unchecked(&self, pos: Vec3) -> &V { + self.vox.get_unchecked(Self::idx_for_unchecked(pos)) + } } impl WriteVol for Chunk { diff --git a/common/src/volumes/dyna.rs b/common/src/volumes/dyna.rs index 9c0968dbc7..51d6d111d8 100644 --- a/common/src/volumes/dyna.rs +++ b/common/src/volumes/dyna.rs @@ -32,6 +32,13 @@ impl Dyna { None } } + + /// Used to transform a voxel position in the volume into its corresponding index + /// in the voxel array. + #[inline(always)] + fn idx_for_unchecked(sz: Vec3, pos: Vec3) -> usize { + (pos.x * sz.y as i32 * sz.z as i32 + pos.y * sz.z as i32 + pos.z) as usize + } } impl BaseVol for Dyna { @@ -53,6 +60,12 @@ impl ReadVol for Dyna { .and_then(|idx| self.vox.get(idx)) .ok_or(DynaErr::OutOfBounds) } + + #[inline(always)] + unsafe fn get_unchecked(&self, pos: Vec3) -> &V { + self.vox + .get_unchecked(Self::idx_for_unchecked(self.sz, pos)) + } } impl WriteVol for Dyna { diff --git a/common/src/volumes/vol_map_2d.rs b/common/src/volumes/vol_map_2d.rs index b552778a04..de35ceb3f3 100644 --- a/common/src/volumes/vol_map_2d.rs +++ b/common/src/volumes/vol_map_2d.rs @@ -6,8 +6,10 @@ use crate::{ dyna::{Dyna, DynaErr}, }, }; +use fxhash::FxHashMap; use std::{ collections::{hash_map, HashMap}, + fmt::Debug, marker::PhantomData, sync::Arc, }; @@ -26,7 +28,7 @@ pub enum VolMap2dErr { // M = Chunk metadata #[derive(Clone)] pub struct VolMap2d { - chunks: HashMap, Arc>, + chunks: FxHashMap, Arc>, phantom: PhantomData, } @@ -50,12 +52,12 @@ impl VolMap2d { } } -impl BaseVol for VolMap2d { +impl BaseVol for VolMap2d { type Vox = V::Vox; type Err = VolMap2dErr; } -impl ReadVol for VolMap2d { +impl ReadVol for VolMap2d { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&V::Vox, VolMap2dErr> { let ck = Self::chunk_key(pos); @@ -67,11 +69,18 @@ impl ReadVol for VolMap2d { chunk.get(co).map_err(|err| VolMap2dErr::ChunkErr(err)) }) } + + #[inline(always)] + unsafe fn get_unchecked(&self, pos: Vec3) -> &V::Vox { + let ck = Self::chunk_key(pos); + let co = Self::chunk_offs(pos); + self.chunks.get(&ck).unwrap().get_unchecked(co) + } } // TODO: This actually breaks the API: samples are supposed to have an offset of zero! // TODO: Should this be changed, perhaps? -impl>, V: BaseVol + ReadVol, S: VolSize> SampleVol for VolMap2d { +impl>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol for VolMap2d { type Sample = VolMap2d; /// Take a sample of the terrain by cloning the voxels within the provided range. @@ -99,7 +108,7 @@ impl>, V: BaseVol + ReadVol, S: VolSize> SampleVol for VolM } } -impl WriteVol for VolMap2d { +impl WriteVol for VolMap2d { #[inline(always)] fn set(&mut self, pos: Vec3, vox: V::Vox) -> Result<(), VolMap2dErr> { let ck = Self::chunk_key(pos); @@ -122,7 +131,7 @@ impl VolMap2d { .reduce_and() { Ok(Self { - chunks: HashMap::new(), + chunks: FxHashMap::default(), phantom: PhantomData, }) } else { diff --git a/common/src/volumes/vol_map_3d.rs b/common/src/volumes/vol_map_3d.rs index 3d8f2b0ba0..8d03b1f487 100644 --- a/common/src/volumes/vol_map_3d.rs +++ b/common/src/volumes/vol_map_3d.rs @@ -6,7 +6,7 @@ use crate::{ dyna::{Dyna, DynaErr}, }, }; -use std::{collections::HashMap, marker::PhantomData, sync::Arc}; +use std::{collections::HashMap, fmt::Debug, marker::PhantomData, sync::Arc}; use vek::*; #[derive(Debug)] @@ -45,12 +45,12 @@ impl VolMap3d { } } -impl BaseVol for VolMap3d { +impl BaseVol for VolMap3d { type Vox = V::Vox; type Err = VolMap3dErr; } -impl ReadVol for VolMap3d { +impl ReadVol for VolMap3d { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&V::Vox, VolMap3dErr> { let ck = Self::chunk_key(pos); @@ -66,7 +66,7 @@ impl ReadVol for VolMap3d { // TODO: This actually breaks the API: samples are supposed to have an offset of zero! // TODO: Should this be changed, perhaps? -impl>, V: BaseVol + ReadVol, S: VolSize> SampleVol for VolMap3d { +impl>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol for VolMap3d { type Sample = VolMap3d; /// Take a sample of the terrain by cloning the voxels within the provided range. @@ -95,7 +95,7 @@ impl>, V: BaseVol + ReadVol, S: VolSize> SampleVol for VolM } } -impl WriteVol for VolMap3d { +impl WriteVol for VolMap3d { #[inline(always)] fn set(&mut self, pos: Vec3, vox: V::Vox) -> Result<(), VolMap3dErr> { let ck = Self::chunk_key(pos); diff --git a/voxygen/shaders/figure.frag b/voxygen/shaders/figure.frag index 9f35b6b04a..e68dbb4e5d 100644 --- a/voxygen/shaders/figure.frag +++ b/voxygen/shaders/figure.frag @@ -1,6 +1,7 @@ #version 330 core #include +#include in vec3 f_pos; in vec3 f_norm; @@ -37,5 +38,11 @@ void main() { float sun_diffuse = dot(sun_dir, world_norm) * 0.5; - tgt_color = model_col * vec4(f_col * (ambient + sun_diffuse), 1.0); + vec3 surf_color = model_col.rgb * f_col * (ambient + sun_diffuse); + + float fog_level = fog(f_pos.xy, cam_pos.xy); + vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x); + vec3 color = mix(surf_color, fog_color, fog_level); + + tgt_color = vec4(color, 1.0); } diff --git a/voxygen/shaders/figure.vert b/voxygen/shaders/figure.vert index 4db80ee7c4..a33dc8004c 100644 --- a/voxygen/shaders/figure.vert +++ b/voxygen/shaders/figure.vert @@ -28,15 +28,12 @@ out vec3 f_col; flat out uint f_bone_idx; void main() { - f_pos = v_pos; + f_pos = (model_mat * + bones[v_bone_idx].bone_mat * + vec4(v_pos, 1)).xyz; f_norm = v_norm; f_col = v_col; f_bone_idx = v_bone_idx; - gl_Position = - proj_mat * - view_mat * - model_mat * - bones[v_bone_idx].bone_mat * - vec4(v_pos, 1); + gl_Position = proj_mat * view_mat * vec4(f_pos, 1); } diff --git a/voxygen/shaders/include/sky.glsl b/voxygen/shaders/include/sky.glsl index 8b13789179..e17e5288d3 100644 --- a/voxygen/shaders/include/sky.glsl +++ b/voxygen/shaders/include/sky.glsl @@ -1 +1,28 @@ +const float PI = 3.141592; +vec3 get_sky_color(vec3 dir, float time_of_day) { + const float TIME_FACTOR = (PI * 2.0) / (3600.0 * 24.0); + + const vec3 SKY_TOP = vec3(0.1, 0.5, 1.0); + const vec3 SKY_BOTTOM = vec3(0.025, 0.08, 0.2); + + const vec3 SUN_HALO_COLOR = vec3(1.0, 0.7, 0.5); + const vec3 SUN_SURF_COLOR = vec3(1.0, 0.9, 0.35) * 200.0; + + float sun_angle_rad = time_of_day * TIME_FACTOR; + vec3 sun_dir = vec3(sin(sun_angle_rad), 0.0, cos(sun_angle_rad)); + + vec3 sun_halo = pow(max(dot(dir, sun_dir), 0.0), 8.0) * SUN_HALO_COLOR; + vec3 sun_surf = pow(max(dot(dir, sun_dir) - 0.0045, 0.0), 1000.0) * SUN_SURF_COLOR; + vec3 sun_light = sun_halo + sun_surf; + + return mix(SKY_BOTTOM, SKY_TOP, (dir.z + 1.0) / 2.0) + sun_light; +} + +float fog(vec2 f_pos, vec2 cam_pos) { + float dist = distance(f_pos, cam_pos) / view_distance.x; + float min_fog = 0.5; + float max_fog = 0.95; + + return clamp((dist - min_fog) / (max_fog - min_fog), 0.0, 1.0); +} diff --git a/voxygen/shaders/postprocess.frag b/voxygen/shaders/postprocess.frag index 8eda152c57..62bd919f91 100644 --- a/voxygen/shaders/postprocess.frag +++ b/voxygen/shaders/postprocess.frag @@ -171,5 +171,5 @@ void main() { //hsva_color.z = 1.0 - 1.0 / (1.0 * hsva_color.z + 1.0); vec4 final_color = vec4(hsv2rgb(hsva_color.rgb), hsva_color.a); - tgt_color = vec4(final_color.rgb, 0.5); + tgt_color = vec4(final_color.rgb, 1); } diff --git a/voxygen/shaders/skybox.frag b/voxygen/shaders/skybox.frag index 986a3434fb..7cabdd09ec 100644 --- a/voxygen/shaders/skybox.frag +++ b/voxygen/shaders/skybox.frag @@ -1,6 +1,7 @@ #version 330 core #include +#include in vec3 f_pos; @@ -11,27 +12,6 @@ uniform u_locals { out vec4 tgt_color; -const float PI = 3.141592; - -vec3 get_sky_color(vec3 dir, float time_of_day) { - const float TIME_FACTOR = (PI * 2.0) / (3600.0 * 24.0); - - const vec3 SKY_TOP = vec3(0.1, 0.5, 1.0); - const vec3 SKY_BOTTOM = vec3(0.025, 0.08, 0.2); - - const vec3 SUN_HALO_COLOR = vec3(1.0, 0.7, 0.5); - const vec3 SUN_SURF_COLOR = vec3(1.0, 0.9, 0.35) * 200.0; - - float sun_angle_rad = time_of_day * TIME_FACTOR; - vec3 sun_dir = vec3(sin(sun_angle_rad), 0.0, cos(sun_angle_rad)); - - vec3 sun_halo = pow(max(dot(dir, sun_dir), 0.0), 8.0) * SUN_HALO_COLOR; - vec3 sun_surf = pow(max(dot(dir, sun_dir) - 0.0045, 0.0), 1000.0) * SUN_SURF_COLOR; - vec3 sun_light = sun_halo + sun_surf; - - return mix(SKY_BOTTOM, SKY_TOP, (dir.z + 1.0) / 2.0) + sun_light; -} - void main() { tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x), 1.0); } diff --git a/voxygen/shaders/terrain.frag b/voxygen/shaders/terrain.frag index ac07bd0ef9..93a08fe02b 100644 --- a/voxygen/shaders/terrain.frag +++ b/voxygen/shaders/terrain.frag @@ -1,6 +1,7 @@ #version 330 core #include +#include in vec3 f_pos; flat in uint f_pos_norm; @@ -14,11 +15,6 @@ uniform u_locals { out vec4 tgt_color; -float fog() { - float half_vd = 0.95 * view_distance.x / 2.0; - return clamp(distance(f_pos, cam_pos.xyz) / half_vd - 1.0, 0.0, 1.0); -} - void main() { // Calculate normal from packed data vec3 f_norm; @@ -45,9 +41,11 @@ void main() { vec3 light = vec3(static_light); - vec3 frag_color = f_col * light; + vec3 surf_color = f_col * light; - vec3 fog_color = vec3(0.0, 0.25, 0.55); + float fog_level = fog(f_pos.xy, cam_pos.xy); + vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x); + vec3 color = mix(surf_color, fog_color, fog_level); - tgt_color = vec4(mix(frag_color, fog_color, fog()), 1.0); + tgt_color = vec4(color, 1.0); } diff --git a/voxygen/src/anim/character/run.rs b/voxygen/src/anim/character/run.rs index 53845caeec..173caca70a 100644 --- a/voxygen/src/anim/character/run.rs +++ b/voxygen/src/anim/character/run.rs @@ -37,8 +37,8 @@ impl Animation for RunAnimation { ); next.head.offset = Vec3::new(0.0, 3.0, 12.0 + wave_cos * 1.3); - next.head.ori = - Quaternion::rotation_z(head_look.x + wave * 0.1) * Quaternion::rotation_x(head_look.y + 0.35); + next.head.ori = Quaternion::rotation_z(head_look.x + wave * 0.1) + * Quaternion::rotation_x(head_look.y + 0.35); next.head.scale = Vec3::one(); next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_cos * 1.1); diff --git a/voxygen/src/menu/main/start_singleplayer.rs b/voxygen/src/menu/main/start_singleplayer.rs index 9ab08b138a..8dc9a575a8 100644 --- a/voxygen/src/menu/main/start_singleplayer.rs +++ b/voxygen/src/menu/main/start_singleplayer.rs @@ -3,8 +3,8 @@ use crate::{ menu::char_selection::CharSelectionState, singleplayer::Singleplayer, Direction, GlobalState, PlayState, PlayStateResult, }; -use common::comp; use client::Client; +use common::comp; use log::warn; use std::net::SocketAddr; diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index e85e216d7e..d3619b615b 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -1,18 +1,14 @@ -// Library -use vek::*; - -// Project +use crate::{ + mesh::{vol, Meshable}, + render::{self, Mesh, Quad, TerrainPipeline}, +}; use common::{ terrain::Block, vol::{BaseVol, ReadVol, SizedVol, VolSize, Vox}, volumes::{dyna::Dyna, vol_map_2d::VolMap2d, vol_map_3d::VolMap3d}, }; - -// Crate -use crate::{ - mesh::{vol, Meshable}, - render::{self, Mesh, Quad, TerrainPipeline}, -}; +use std::fmt::Debug; +use vek::*; type TerrainVertex = ::Vertex; @@ -46,7 +42,7 @@ impl Meshable for Dyna { } */ -impl + ReadVol, S: VolSize + Clone> Meshable for VolMap2d { +impl + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap2d { type Pipeline = TerrainPipeline; type Supplement = Aabb; @@ -107,7 +103,7 @@ impl + ReadVol, S: VolSize + Clone> Meshable for VolMap2 } /* -impl + ReadVol, S: VolSize + Clone> Meshable for VolMap3d { +impl + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap3d { type Pipeline = TerrainPipeline; type Supplement = Aabb; diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 794b59ca4b..f82e11faba 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -85,7 +85,7 @@ impl Renderer { let mut include_ctx = IncludeContext::new(); include_ctx.include("globals.glsl", globals); - include_ctx.include("sky.glsl", globals); + include_ctx.include("sky.glsl", sky); // Construct a pipeline for rendering skyboxes let skybox_pipeline = create_pipeline( diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index ef747ab3df..08393f909c 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -11,7 +11,7 @@ use vek::*; const NEAR_PLANE: f32 = 0.1; const FAR_PLANE: f32 = 10000.0; -const INTERP_TIME: f32 = 0.1; +const INTERP_TIME: f32 = 0.05; pub struct Camera { tgt_focus: Vec3, diff --git a/voxygen/src/singleplayer.rs b/voxygen/src/singleplayer.rs index 27bb198596..eea93f8928 100644 --- a/voxygen/src/singleplayer.rs +++ b/voxygen/src/singleplayer.rs @@ -1,5 +1,5 @@ -use common::clock::Clock; use client::Client; +use common::clock::Clock; use log::info; use portpicker::pick_unused_port; use server::{Event, Input, Server}; @@ -33,8 +33,7 @@ impl Singleplayer { )); // Create server - let server = Server::bind(sock.clone()) - .expect("Failed to create server instance!"); + let server = Server::bind(sock.clone()).expect("Failed to create server instance!"); let server = match client { Some(client) => server.with_thread_pool(client.thread_pool().clone()), From fa6609574207a4205f68357d5c0a3559e6aa3f80 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 17:32:33 +0100 Subject: [PATCH 08/21] Added dynamic fog growth --- client/src/lib.rs | 37 +++++++++++++++++++++----------- server/src/lib.rs | 8 +++++-- voxygen/shaders/include/sky.glsl | 2 +- voxygen/src/scene/mod.rs | 8 ++++++- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index f6e2fa5d29..41c9ac5ab4 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -46,6 +46,7 @@ pub struct Client { state: State, entity: EcsEntity, view_distance: Option, + loaded_distance: Option, pending_chunks: HashMap, Instant>, } @@ -96,6 +97,7 @@ impl Client { state, entity, view_distance, + loaded_distance: None, pending_chunks: HashMap::new(), }) @@ -144,6 +146,10 @@ impl Client { self.view_distance } + pub fn loaded_distance(&self) -> Option { + self.loaded_distance + } + /// Send a chat message to the server. #[allow(dead_code)] pub fn send_chat(&mut self, msg: String) { @@ -253,7 +259,7 @@ impl Client { if (Vec2::from(chunk_pos) - Vec2::from(key)) .map(|e: i32| e.abs() as u32) .reduce_max() - > view_distance + > view_distance + 1 { chunks_to_remove.push(key); } @@ -264,23 +270,30 @@ impl Client { // Request chunks from the server. // TODO: This is really inefficient. + let mut all_loaded = true; 'outer: for dist in 0..=view_distance as i32 { - for i in chunk_pos.x - dist..=chunk_pos.x + dist { - for j in chunk_pos.y - dist..=chunk_pos.y + dist { + for i in chunk_pos.x - dist..=chunk_pos.x + 1 + dist { + for j in chunk_pos.y - dist..=chunk_pos.y + 1 + dist { let key = Vec2::new(i, j); - if self.state.terrain().get_key(key).is_none() - && !self.pending_chunks.contains_key(&key) - { - if self.pending_chunks.len() < 4 { - self.postbox - .send_message(ClientMsg::TerrainChunkRequest { key }); - self.pending_chunks.insert(key, Instant::now()); - } else { - break 'outer; + if self.state.terrain().get_key(key).is_none() { + if !self.pending_chunks.contains_key(&key) { + if self.pending_chunks.len() < 4 { + self.postbox + .send_message(ClientMsg::TerrainChunkRequest { key }); + self.pending_chunks.insert(key, Instant::now()); + } else { + break 'outer; + } } + + all_loaded = false; } } } + + if all_loaded { + self.loaded_distance = Some((dist - 1).max(0) as u32); + } } // If chunks are taking too long, assume they're no longer pending. diff --git a/server/src/lib.rs b/server/src/lib.rs index d680fe79a4..d6dd165f46 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -312,7 +312,7 @@ impl Server { .map(|e: i32| e.abs()) .reduce_max() as u32; - if dist <= view_distance { + if dist <= view_distance + 1 { self.clients.notify( entity, ServerMsg::TerrainChunkUpdate { @@ -344,7 +344,11 @@ impl Server { .map(|e: i32| e.abs() as u32) .reduce_max(); - if player.view_distance.map(|vd| dist <= vd).unwrap_or(false) { + if player + .view_distance + .map(|vd| dist <= vd + 1) + .unwrap_or(false) + { should_drop = false; break; } diff --git a/voxygen/shaders/include/sky.glsl b/voxygen/shaders/include/sky.glsl index e17e5288d3..ef280ca283 100644 --- a/voxygen/shaders/include/sky.glsl +++ b/voxygen/shaders/include/sky.glsl @@ -22,7 +22,7 @@ vec3 get_sky_color(vec3 dir, float time_of_day) { float fog(vec2 f_pos, vec2 cam_pos) { float dist = distance(f_pos, cam_pos) / view_distance.x; float min_fog = 0.5; - float max_fog = 0.95; + float max_fog = 1.0; return clamp((dist - min_fog) / (max_fog - min_fog), 0.0, 1.0); } diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index f768afa6c6..a76f3a2c9f 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -40,6 +40,7 @@ pub struct Scene { skybox: Skybox, postprocess: PostProcess, terrain: Terrain, + loaded_distance: f32, figure_mgr: FigureMgr, } @@ -64,6 +65,7 @@ impl Scene { .unwrap(), }, terrain: Terrain::new(), + loaded_distance: 0.0, figure_mgr: FigureMgr::new(), } } @@ -127,6 +129,10 @@ impl Scene { // Compute camera matrices. let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(client); + // Update chunk loaded distance smoothly for nice shader fog + let loaded_distance = client.loaded_distance().unwrap_or(1) as f32 * 32.0; + self.loaded_distance = 0.98 * self.loaded_distance + 0.02 * loaded_distance; + // Update global constants. renderer .update_consts( @@ -136,7 +142,7 @@ impl Scene { proj_mat, cam_pos, self.camera.get_focus_pos(), - client.view_distance().unwrap_or(0) as f32 * 32.0, // TODO: No magic numbers + self.loaded_distance, client.state().get_time_of_day(), client.state().get_time(), renderer.get_resolution(), From 5b55fe1be0637b4b67e1b20ff1c025f3368595ca Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 19:00:17 +0100 Subject: [PATCH 09/21] Reduced tree density, shortened chunk load timeout --- client/src/lib.rs | 2 +- world/src/sim.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 41c9ac5ab4..8320055dec 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -299,7 +299,7 @@ impl Client { // If chunks are taking too long, assume they're no longer pending. let now = Instant::now(); self.pending_chunks - .retain(|_, created| now.duration_since(*created) < Duration::from_secs(10)); + .retain(|_, created| now.duration_since(*created) < Duration::from_secs(3)); } // Send a ping to the server once every second diff --git a/world/src/sim.rs b/world/src/sim.rs index 2415bd2389..dc25f9bbb6 100644 --- a/world/src/sim.rs +++ b/world/src/sim.rs @@ -58,7 +58,7 @@ impl WorldSim { warp_nz: BasicMulti::new().set_octaves(3).set_seed(seed + 8), tree_nz: BasicMulti::new() .set_octaves(12) - .set_persistence(0.9) + .set_persistence(0.75) .set_seed(seed + 9), cave_0_nz: SuperSimplex::new().set_seed(seed + 10), cave_1_nz: SuperSimplex::new().set_seed(seed + 11), @@ -461,7 +461,7 @@ impl SimChunk { .add(1.0) .mul(0.5) .mul(1.0 - chaos * 0.85) - .mul(1.25) + .mul(1.2) .add(0.1) .mul(if alt > SEA_LEVEL + 2.0 { 1.0 } else { 0.0 }), } From 8602f2dd0b37afcf2a9f8c62aefbb82d3dced4cd Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 19:08:03 +0100 Subject: [PATCH 10/21] Made character the centre of the fog --- voxygen/shaders/figure.frag | 2 +- voxygen/shaders/include/sky.glsl | 4 ++-- voxygen/shaders/terrain.frag | 2 +- voxygen/src/scene/mod.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/voxygen/shaders/figure.frag b/voxygen/shaders/figure.frag index e68dbb4e5d..36dd375a00 100644 --- a/voxygen/shaders/figure.frag +++ b/voxygen/shaders/figure.frag @@ -40,7 +40,7 @@ void main() { vec3 surf_color = model_col.rgb * f_col * (ambient + sun_diffuse); - float fog_level = fog(f_pos.xy, cam_pos.xy); + float fog_level = fog(f_pos.xy, focus_pos.xy); vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x); vec3 color = mix(surf_color, fog_color, fog_level); diff --git a/voxygen/shaders/include/sky.glsl b/voxygen/shaders/include/sky.glsl index ef280ca283..4935c155f5 100644 --- a/voxygen/shaders/include/sky.glsl +++ b/voxygen/shaders/include/sky.glsl @@ -19,8 +19,8 @@ vec3 get_sky_color(vec3 dir, float time_of_day) { return mix(SKY_BOTTOM, SKY_TOP, (dir.z + 1.0) / 2.0) + sun_light; } -float fog(vec2 f_pos, vec2 cam_pos) { - float dist = distance(f_pos, cam_pos) / view_distance.x; +float fog(vec2 f_pos, vec2 focus_pos) { + float dist = distance(f_pos, focus_pos) / view_distance.x; float min_fog = 0.5; float max_fog = 1.0; diff --git a/voxygen/shaders/terrain.frag b/voxygen/shaders/terrain.frag index 93a08fe02b..b45d545ae4 100644 --- a/voxygen/shaders/terrain.frag +++ b/voxygen/shaders/terrain.frag @@ -43,7 +43,7 @@ void main() { vec3 surf_color = f_col * light; - float fog_level = fog(f_pos.xy, cam_pos.xy); + float fog_level = fog(f_pos.xy, focus_pos.xy); vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x); vec3 color = mix(surf_color, fog_color, fog_level); diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index a76f3a2c9f..305fbca348 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -131,7 +131,7 @@ impl Scene { // Update chunk loaded distance smoothly for nice shader fog let loaded_distance = client.loaded_distance().unwrap_or(1) as f32 * 32.0; - self.loaded_distance = 0.98 * self.loaded_distance + 0.02 * loaded_distance; + self.loaded_distance = (0.98 * self.loaded_distance + 0.02 * loaded_distance).max(0.1); // Update global constants. renderer From 851b60db25c351b6570bddd9f6ffd448d7094d31 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 20:51:49 +0100 Subject: [PATCH 11/21] Changed debug flag in client --- client/src/lib.rs | 6 ++---- voxygen/shaders/include/sky.glsl | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 8320055dec..aeb0536704 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -14,7 +14,7 @@ use common::{ state::State, terrain::chonk::ChonkMetrics, }; -use log::info; +use log::{info, log_enabled}; use std::{ collections::HashMap, net::SocketAddr, @@ -25,8 +25,6 @@ use vek::*; const SERVER_TIMEOUT: Duration = Duration::from_secs(20); -const DEBUG_METRICS: bool = true; - pub enum Event { Chat(String), Disconnect, @@ -335,7 +333,7 @@ impl Client { } // Output debug metrics - if DEBUG_METRICS && self.tick % 600 == 0 { + if log_enabled!(log::Level::Info) && self.tick % 600 == 0 { let metrics = self .state .terrain() diff --git a/voxygen/shaders/include/sky.glsl b/voxygen/shaders/include/sky.glsl index 4935c155f5..b7fe28d4ca 100644 --- a/voxygen/shaders/include/sky.glsl +++ b/voxygen/shaders/include/sky.glsl @@ -6,7 +6,7 @@ vec3 get_sky_color(vec3 dir, float time_of_day) { const vec3 SKY_TOP = vec3(0.1, 0.5, 1.0); const vec3 SKY_BOTTOM = vec3(0.025, 0.08, 0.2); - const vec3 SUN_HALO_COLOR = vec3(1.0, 0.7, 0.5); + const vec3 SUN_HALO_COLOR = vec3(1.0, 0.7, 0.5) * 0.5; const vec3 SUN_SURF_COLOR = vec3(1.0, 0.9, 0.35) * 200.0; float sun_angle_rad = time_of_day * TIME_FACTOR; From 3eea6c420fc9255c92f41a90272e2d4c31a08a02 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 21:07:36 +0100 Subject: [PATCH 12/21] Upped cave frequency --- world/src/sim.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/world/src/sim.rs b/world/src/sim.rs index dc25f9bbb6..f8873b2156 100644 --- a/world/src/sim.rs +++ b/world/src/sim.rs @@ -203,13 +203,13 @@ impl<'a> Sampler<'a> { let cave_at = |wposf: Vec2| { (sim.gen_ctx.cave_0_nz.get( Vec3::new(wposf.x, wposf.y, alt as f64 * 8.0) - .div(1000.0) + .div(800.0) .into_array(), ) as f32) .powf(2.0) .neg() .add(1.0) - .mul((1.15 - chaos).min(1.0)) + .mul((1.35 - chaos).min(1.0)) }; let cave_xy = cave_at(wposf); let cave_alt = alt - 32.0 From 888518bb5cfead0252fe7af928d312ac702724c0 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 21:33:06 +0100 Subject: [PATCH 13/21] Fixed caves again --- world/src/sim.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/world/src/sim.rs b/world/src/sim.rs index f8873b2156..01f8e262b8 100644 --- a/world/src/sim.rs +++ b/world/src/sim.rs @@ -305,7 +305,7 @@ impl<'a> Sampler<'a> { let water = Block::new(1, Rgb::new(100, 150, 255)); let warm_stone = Block::new(1, Rgb::new(165, 165, 90)); - let ground_block = if (wposf.z as f32) < height - 4.0 { + let block = if (wposf.z as f32) < height - 4.0 { // Underground Some(stone) } else if (wposf.z as f32) < height { @@ -319,7 +319,7 @@ impl<'a> Sampler<'a> { }; // Caves - let block = ground_block.or_else(|| { + let block = block.and_then(|block| { // Underground let cave = cave_xy.powf(2.0) * (wposf.z as f32 - cave_alt) @@ -332,7 +332,7 @@ impl<'a> Sampler<'a> { if cave { None } else { - ground_block + Some(block) } }); From dcbb51ea9bd75e21aa03450ce55162bddf13e166 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 21:40:47 +0100 Subject: [PATCH 14/21] Fewer caves on mountains --- world/src/sim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/world/src/sim.rs b/world/src/sim.rs index 01f8e262b8..68edf8862e 100644 --- a/world/src/sim.rs +++ b/world/src/sim.rs @@ -209,7 +209,7 @@ impl<'a> Sampler<'a> { .powf(2.0) .neg() .add(1.0) - .mul((1.35 - chaos).min(1.0)) + .mul((1.15 - chaos).min(1.0)) }; let cave_xy = cave_at(wposf); let cave_alt = alt - 32.0 From c991b840cc9dca87a987be8fcca451ea0f1b976c Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 22:38:43 +0100 Subject: [PATCH 15/21] Fixed mountain generation limits chonk bug --- world/src/sim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/world/src/sim.rs b/world/src/sim.rs index 68edf8862e..987ae0451a 100644 --- a/world/src/sim.rs +++ b/world/src/sim.rs @@ -468,7 +468,7 @@ impl SimChunk { } pub fn get_base_z(&self) -> f32 { - self.alt + self.alt - Z_TOLERANCE.0 * self.chaos } pub fn get_min_z(&self) -> f32 { From 5a3a88553aef900cc4cefe6b1fe395be7f76c7a2 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 6 Jun 2019 06:46:02 +0100 Subject: [PATCH 16/21] Comment cleanup --- voxygen/src/render/renderer.rs | 2 -- voxygen/src/scene/figure.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index f82e11faba..ef1af1728d 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -230,9 +230,7 @@ impl Renderer { /// Queue the clearing of the color and depth targets ready for a new frame to be rendered. /// TODO: Make a version of this that doesn't clear the colour target for speed. pub fn clear(&mut self, col: Rgba) { - //self.encoder.clear(&self.tgt_color_view, col.into_array()); self.encoder.clear_depth(&self.tgt_depth_view, 1.0); - //self.encoder.clear(&self.win_color_view, col.into_array()); self.encoder.clear_depth(&self.win_depth_view, 1.0); } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 8be3ca11b4..7c8394f080 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -742,7 +742,7 @@ impl FigureState { ) { let mat = Mat4::::identity() * Mat4::translation_3d(pos) - * Mat4::rotation_z(-ori.x.atan2(ori.y)) // + f32::consts::PI / 2.0); + * Mat4::rotation_z(-ori.x.atan2(ori.y)) * Mat4::scaling_3d(Vec3::from(0.8)); let locals = FigureLocals::new(mat, col); From d7d51e1810e1622b7ea24163b99c882b3731190c Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 6 Jun 2019 07:42:59 +0100 Subject: [PATCH 17/21] Made idx_for use idx_for_unchecked internally --- common/src/volumes/chunk.rs | 5 +---- common/src/volumes/dyna.rs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/common/src/volumes/chunk.rs b/common/src/volumes/chunk.rs index e395a762ef..6485b2248e 100644 --- a/common/src/volumes/chunk.rs +++ b/common/src/volumes/chunk.rs @@ -32,10 +32,7 @@ impl Chunk { if pos.map(|e| e >= 0).reduce_and() && pos.map2(S::SIZE, |e, lim| e < lim as i32).reduce_and() { - Some( - (pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 + pos.y * S::SIZE.z as i32 + pos.z) - as usize, - ) + Some(Self::idx_for_unchecked(pos)) } else { None } diff --git a/common/src/volumes/dyna.rs b/common/src/volumes/dyna.rs index 51d6d111d8..ffec84f273 100644 --- a/common/src/volumes/dyna.rs +++ b/common/src/volumes/dyna.rs @@ -27,7 +27,7 @@ impl Dyna { #[inline(always)] fn idx_for(sz: Vec3, pos: Vec3) -> Option { if pos.map(|e| e >= 0).reduce_and() && pos.map2(sz, |e, lim| e < lim as i32).reduce_and() { - Some((pos.x * sz.y as i32 * sz.z as i32 + pos.y * sz.z as i32 + pos.z) as usize) + Some(Self::idx_for_unchecked(sz, pos)) } else { None } From 77a3b47bdace578849715649fdb18984de40704e Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 6 Jun 2019 08:13:58 +0100 Subject: [PATCH 18/21] Only draw chunks outside of fog boundary, reduce fog strength --- voxygen/shaders/include/sky.glsl | 2 +- voxygen/src/scene/mod.rs | 7 ++++++- voxygen/src/scene/terrain.rs | 31 +++++++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/voxygen/shaders/include/sky.glsl b/voxygen/shaders/include/sky.glsl index b7fe28d4ca..6ee29fb132 100644 --- a/voxygen/shaders/include/sky.glsl +++ b/voxygen/shaders/include/sky.glsl @@ -21,7 +21,7 @@ vec3 get_sky_color(vec3 dir, float time_of_day) { float fog(vec2 f_pos, vec2 focus_pos) { float dist = distance(f_pos, focus_pos) / view_distance.x; - float min_fog = 0.5; + float min_fog = 0.75; float max_fog = 1.0; return clamp((dist - min_fog) / (max_fog - min_fog), 0.0, 1.0); diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 305fbca348..4f74fae068 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -166,7 +166,12 @@ impl Scene { renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals); // Render terrain and figures. - self.terrain.render(renderer, &self.globals); + self.terrain.render( + renderer, + &self.globals, + self.camera.get_focus_pos(), + self.loaded_distance, + ); self.figure_mgr.render(renderer, client, &self.globals); renderer.render_post_process( diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 8e1a39d57c..dfa13703a5 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -3,7 +3,11 @@ use crate::{ render::{Consts, Globals, Mesh, Model, Renderer, TerrainLocals, TerrainPipeline}, }; use client::Client; -use common::{terrain::TerrainMap, vol::SampleVol, volumes::vol_map_2d::VolMap2dErr}; +use common::{ + terrain::{TerrainChunkSize, TerrainMap}, + vol::{SampleVol, VolSize}, + volumes::vol_map_2d::VolMap2dErr, +}; use std::{collections::HashMap, i32, sync::mpsc, time::Duration}; use vek::*; @@ -200,9 +204,28 @@ impl Terrain { } } - pub fn render(&self, renderer: &mut Renderer, globals: &Consts) { - for (_, chunk) in &self.chunks { - renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals); + pub fn render( + &self, + renderer: &mut Renderer, + globals: &Consts, + focus_pos: Vec3, + loaded_distance: f32, + ) { + for (pos, chunk) in &self.chunks { + // Limit focus_pos to chunk bounds + let chunk_pos = pos.map2(TerrainChunkSize::SIZE.into(), |e, sz: u32| { + e as f32 * sz as f32 + }); + let nearest_in_chunk = Vec2::from(focus_pos).clamped( + chunk_pos, + chunk_pos + Vec2::from(TerrainChunkSize::SIZE).map(|e: u32| e as f32), + ); + + if Vec2::::from(focus_pos).distance_squared(nearest_in_chunk) + < loaded_distance.powf(2.0) + { + renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals); + } } } } From 1feff6c5aaaca78cce79f5bd03fb57b794a909c8 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 6 Jun 2019 10:04:37 +0100 Subject: [PATCH 19/21] Added frustum culling for chunks --- Cargo.lock | 7 +++ voxygen/Cargo.toml | 1 + voxygen/src/scene/mod.rs | 16 ++++--- voxygen/src/scene/terrain.rs | 86 +++++++++++++++++++++++++++--------- 4 files changed, 81 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c16661e04..5b4d241c35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -782,6 +782,11 @@ name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "frustum_query" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -2635,6 +2640,7 @@ dependencies = [ "euc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "frustum_query 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_device_gl 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_window_glutin 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2952,6 +2958,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +"checksum frustum_query 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e1771c26abed26b2527d888742fffd27dab86d205bf4846748abf29c06ef5a05" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index 56738e2c2b..d98b06017e 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -55,3 +55,4 @@ portpicker = "0.1" num = "0.2" backtrace = "0.3" rand = "0.5" +frustum_query = "0.1.2" diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 4f74fae068..64e37f4947 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -151,7 +151,14 @@ impl Scene { .expect("Failed to update global constants"); // Maintain the terrain. - self.terrain.maintain(renderer, client); + self.terrain.maintain( + renderer, + client, + self.camera.get_focus_pos(), + self.loaded_distance, + view_mat, + proj_mat, + ); // Maintain the figures. self.figure_mgr.maintain(renderer, client); @@ -166,12 +173,7 @@ impl Scene { renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals); // Render terrain and figures. - self.terrain.render( - renderer, - &self.globals, - self.camera.get_focus_pos(), - self.loaded_distance, - ); + self.terrain.render(renderer, &self.globals); self.figure_mgr.render(renderer, client, &self.globals); renderer.render_post_process( diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index dfa13703a5..19d4251a2d 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -8,13 +8,16 @@ use common::{ vol::{SampleVol, VolSize}, volumes::vol_map_2d::VolMap2dErr, }; -use std::{collections::HashMap, i32, sync::mpsc, time::Duration}; +use frustum_query::frustum::Frustum; +use std::{collections::HashMap, i32, ops::Mul, sync::mpsc, time::Duration}; use vek::*; struct TerrainChunk { // GPU data model: Model, locals: Consts, + visible: bool, + z_bounds: (f32, f32), } struct ChunkMeshState { @@ -26,6 +29,7 @@ struct ChunkMeshState { /// A type produced by mesh worker threads corresponding to the position and mesh of a chunk. struct MeshWorkerResponse { pos: Vec2, + z_bounds: (f32, f32), mesh: Mesh, started_tick: u64, } @@ -33,12 +37,14 @@ struct MeshWorkerResponse { /// Function executed by worker threads dedicated to chunk meshing. fn mesh_worker( pos: Vec2, + z_bounds: (f32, f32), started_tick: u64, volume: >>::Sample, range: Aabb, ) -> MeshWorkerResponse { MeshWorkerResponse { pos, + z_bounds, mesh: volume.generate_mesh(range), started_tick, } @@ -70,7 +76,15 @@ impl Terrain { } /// Maintain terrain data. To be called once per tick. - pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) { + pub fn maintain( + &mut self, + renderer: &mut Renderer, + client: &Client, + focus_pos: Vec3, + loaded_distance: f32, + view_mat: Mat4, + proj_mat: Mat4, + ) { let current_tick = client.get_tick(); // Add any recently created or changed chunks to the list of chunks to be meshed. @@ -165,7 +179,13 @@ impl Terrain { // Queue the worker thread. client.thread_pool().execute(move || { - let _ = send.send(mesh_worker(pos, current_tick, volume, aabb)); + let _ = send.send(mesh_worker( + pos, + (min_z as f32, max_z as f32), + current_tick, + volume, + aabb, + )); }); todo.active_worker = true; } @@ -194,6 +214,8 @@ impl Terrain { .into_array(), }]) .expect("Failed to upload chunk locals to the GPU!"), + visible: false, + z_bounds: response.z_bounds, }, ); } @@ -202,28 +224,48 @@ impl Terrain { _ => {} } } - } - pub fn render( - &self, - renderer: &mut Renderer, - globals: &Consts, - focus_pos: Vec3, - loaded_distance: f32, - ) { - for (pos, chunk) in &self.chunks { - // Limit focus_pos to chunk bounds - let chunk_pos = pos.map2(TerrainChunkSize::SIZE.into(), |e, sz: u32| { - e as f32 * sz as f32 - }); - let nearest_in_chunk = Vec2::from(focus_pos).clamped( - chunk_pos, - chunk_pos + Vec2::from(TerrainChunkSize::SIZE).map(|e: u32| e as f32), + // Construct view frustum + let frustum = Frustum::from_modelview_and_projection( + &view_mat.into_col_array(), + &proj_mat.into_col_array(), + ); + + // Update chunk visibility + let chunk_sz = TerrainChunkSize::SIZE.x as f32; + for (pos, chunk) in &mut self.chunks { + let chunk_pos = pos.map(|e| e as f32 * chunk_sz); + + // Limit focus_pos to chunk bounds and ensure the chunk is within the fog boundary + let nearest_in_chunk = Vec2::from(focus_pos).clamped(chunk_pos, chunk_pos + chunk_sz); + let in_range = Vec2::::from(focus_pos).distance_squared(nearest_in_chunk) + < loaded_distance.powf(2.0); + + // Ensure the chunk is within the view frustrum + let chunk_mid = Vec3::new( + chunk_pos.x + chunk_sz / 2.0, + chunk_pos.y + chunk_sz / 2.0, + (chunk.z_bounds.0 + chunk.z_bounds.1) * 0.5, + ); + let chunk_radius = (chunk.z_bounds.1 - chunk.z_bounds.0) + .max(chunk_sz / 2.0) + .powf(2.0) + .mul(2.0) + .sqrt(); + let in_frustum = frustum.sphere_intersecting( + &chunk_mid.x, + &chunk_mid.y, + &chunk_mid.z, + &chunk_radius, ); - if Vec2::::from(focus_pos).distance_squared(nearest_in_chunk) - < loaded_distance.powf(2.0) - { + chunk.visible = in_range && in_frustum; + } + } + + pub fn render(&self, renderer: &mut Renderer, globals: &Consts) { + for (pos, chunk) in &self.chunks { + if chunk.visible { renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals); } } From 1e0f90058ba195653881bed2a1132a6d0f7e94e7 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 6 Jun 2019 11:09:25 +0100 Subject: [PATCH 20/21] Smoothed fog VD opening --- voxygen/src/scene/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 64e37f4947..e15dac6f0d 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -130,8 +130,8 @@ impl Scene { let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(client); // Update chunk loaded distance smoothly for nice shader fog - let loaded_distance = client.loaded_distance().unwrap_or(1) as f32 * 32.0; - self.loaded_distance = (0.98 * self.loaded_distance + 0.02 * loaded_distance).max(0.1); + let loaded_distance = client.loaded_distance().unwrap_or(0) as f32 * 32.0; + self.loaded_distance = (0.98 * self.loaded_distance + 0.02 * loaded_distance).max(0.01); // Update global constants. renderer From ff5a6b9bcb71fc9b272b4ffd8d1956fccbdc5b9b Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 6 Jun 2019 12:25:06 +0100 Subject: [PATCH 21/21] Lighting fix --- common/src/terrain/block.rs | 8 ++++---- voxygen/src/mesh/terrain.rs | 18 ++++++++++++------ world/src/sim.rs | 3 +-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index f346ee4cb8..e5717ee025 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -26,11 +26,11 @@ impl Block { } } - pub fn get_opacity(&self) -> f32 { + pub fn get_opacity(&self) -> Option { match self.kind { - 0 => 0.0, - 1 => 0.3, - 2 => 1.0, + 0 => None, + 1 => Some(0.85), + 2 => Some(1.0), _ => unimplemented!(), } } diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index d3619b615b..1b70885145 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -51,7 +51,7 @@ impl + ReadVol + Debug, S: VolSize + Clone> Meshable for for x in range.min.x + 1..range.max.x - 1 { for y in range.min.y + 1..range.max.y - 1 { - let mut neighbour_light = [[1.0f32; 3]; 3]; + let mut neighbour_light = [[(1.0f32, 0.0); 3]; 3]; for z in (range.min.z..range.max.z).rev() { let pos = Vec3::new(x, y, z); @@ -62,7 +62,7 @@ impl + ReadVol + Debug, S: VolSize + Clone> Meshable for .iter() .map(|col| col.iter()) .flatten() - .fold(0.0, |a, x| a + x) + .fold(0.0, |a, (x, _)| a + x) / 9.0; let light = avg_light; @@ -85,13 +85,19 @@ impl + ReadVol + Debug, S: VolSize + Clone> Meshable for // Accumulate shade under opaque blocks for i in 0..3 { for j in 0..3 { - neighbour_light[i][j] = if let Ok(opacity) = self + let max_opacity = neighbour_light[i][j].1; + neighbour_light[i][j] = if let Some(opacity) = self .get(pos + Vec3::new(i as i32 - 1, j as i32 - 1, 0)) - .map(|vox| vox.get_opacity()) + .ok() + .and_then(|vox| vox.get_opacity()) { - neighbour_light[i][j] * (1.0 - opacity * 0.5) + ( + (neighbour_light[i][j].0 * (1.0 - max_opacity * 0.3)) + .max(1.0 - max_opacity * 0.999), + max_opacity.max(opacity), + ) } else { - (neighbour_light[i][j] * 1.05).min(1.0) + ((neighbour_light[i][j].0 * 1.02).min(1.0), max_opacity) }; } } diff --git a/world/src/sim.rs b/world/src/sim.rs index 987ae0451a..f2049f6076 100644 --- a/world/src/sim.rs +++ b/world/src/sim.rs @@ -181,7 +181,7 @@ impl<'a> Sampler<'a> { .mul(0.5); // Colours - let cold_grass = Rgb::new(0.1, 0.6, 0.3); + let cold_grass = Rgb::new(0.0, 0.55, 0.15); let warm_grass = Rgb::new(0.25, 0.8, 0.05); let cold_stone = Rgb::new(0.55, 0.7, 0.75); let warm_stone = Rgb::new(0.65, 0.65, 0.35); @@ -461,7 +461,6 @@ impl SimChunk { .add(1.0) .mul(0.5) .mul(1.0 - chaos * 0.85) - .mul(1.2) .add(0.1) .mul(if alt > SEA_LEVEL + 2.0 { 1.0 } else { 0.0 }), }