From 9da2d82197ee894b86c86685d35921d8a113e442 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 5 Jun 2019 16:22:06 +0100 Subject: [PATCH] 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()),