Added proper VD fog

This commit is contained in:
Joshua Barretto 2019-06-05 16:22:06 +01:00
parent cd630b0816
commit 9da2d82197
20 changed files with 153 additions and 72 deletions

1
Cargo.lock generated
View File

@ -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)",

View File

@ -23,3 +23,4 @@ rand = "0.6.5"
rayon = "1.0"
lazy_static = "1.3"
lz4-compress = "0.1"
fxhash = "0.2"

View File

@ -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<i32>) -> &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<Vec3<u8>, Block>),
Hash(Block, FxHashMap<Vec3<u8>, Block>),
Heterogeneous(Chunk<Block, TerrainChunkSize, ()>),
}

View File

@ -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<i32>) -> Result<&Self::Vox, Self::Err>;
#[inline(always)]
unsafe fn get_unchecked(&self, pos: Vec3<i32>) -> &Self::Vox {
self.get(pos).unwrap()
}
fn ray(&self, from: Vec3<f32>, to: Vec3<f32>) -> Ray<Self, fn(&Self::Vox) -> bool>
where
Self: Sized,

View File

@ -40,6 +40,13 @@ impl<V: Vox, S: VolSize, M> Chunk<V, S, M> {
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<i32>) -> 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<V: Vox, S: VolSize, M> BaseVol for Chunk<V, S, M> {
@ -61,6 +68,11 @@ impl<V: Vox, S: VolSize, M> ReadVol for Chunk<V, S, M> {
.and_then(|idx| self.vox.get(idx))
.ok_or(ChunkErr::OutOfBounds)
}
#[inline(always)]
unsafe fn get_unchecked(&self, pos: Vec3<i32>) -> &V {
self.vox.get_unchecked(Self::idx_for_unchecked(pos))
}
}
impl<V: Vox, S: VolSize, M> WriteVol for Chunk<V, S, M> {

View File

@ -32,6 +32,13 @@ impl<V: Vox, M> Dyna<V, M> {
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<u32>, pos: Vec3<i32>) -> usize {
(pos.x * sz.y as i32 * sz.z as i32 + pos.y * sz.z as i32 + pos.z) as usize
}
}
impl<V: Vox, M> BaseVol for Dyna<V, M> {
@ -53,6 +60,12 @@ impl<V: Vox, M> ReadVol for Dyna<V, M> {
.and_then(|idx| self.vox.get(idx))
.ok_or(DynaErr::OutOfBounds)
}
#[inline(always)]
unsafe fn get_unchecked(&self, pos: Vec3<i32>) -> &V {
self.vox
.get_unchecked(Self::idx_for_unchecked(self.sz, pos))
}
}
impl<V: Vox, M> WriteVol for Dyna<V, M> {

View File

@ -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<V: BaseVol> {
// M = Chunk metadata
#[derive(Clone)]
pub struct VolMap2d<V: BaseVol, S: VolSize> {
chunks: HashMap<Vec2<i32>, Arc<V>>,
chunks: FxHashMap<Vec2<i32>, Arc<V>>,
phantom: PhantomData<S>,
}
@ -50,12 +52,12 @@ impl<V: BaseVol, S: VolSize> VolMap2d<V, S> {
}
}
impl<V: BaseVol, S: VolSize> BaseVol for VolMap2d<V, S> {
impl<V: BaseVol + Debug, S: VolSize> BaseVol for VolMap2d<V, S> {
type Vox = V::Vox;
type Err = VolMap2dErr<V>;
}
impl<V: BaseVol + ReadVol, S: VolSize> ReadVol for VolMap2d<V, S> {
impl<V: BaseVol + ReadVol + Debug, S: VolSize> ReadVol for VolMap2d<V, S> {
#[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&V::Vox, VolMap2dErr<V>> {
let ck = Self::chunk_key(pos);
@ -67,11 +69,18 @@ impl<V: BaseVol + ReadVol, S: VolSize> ReadVol for VolMap2d<V, S> {
chunk.get(co).map_err(|err| VolMap2dErr::ChunkErr(err))
})
}
#[inline(always)]
unsafe fn get_unchecked(&self, pos: Vec3<i32>) -> &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<I: Into<Aabr<i32>>, V: BaseVol + ReadVol, S: VolSize> SampleVol<I> for VolMap2d<V, S> {
impl<I: Into<Aabr<i32>>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol<I> for VolMap2d<V, S> {
type Sample = VolMap2d<V, S>;
/// Take a sample of the terrain by cloning the voxels within the provided range.
@ -99,7 +108,7 @@ impl<I: Into<Aabr<i32>>, V: BaseVol + ReadVol, S: VolSize> SampleVol<I> for VolM
}
}
impl<V: BaseVol + WriteVol + Clone, S: VolSize + Clone> WriteVol for VolMap2d<V, S> {
impl<V: BaseVol + WriteVol + Clone + Debug, S: VolSize + Clone> WriteVol for VolMap2d<V, S> {
#[inline(always)]
fn set(&mut self, pos: Vec3<i32>, vox: V::Vox) -> Result<(), VolMap2dErr<V>> {
let ck = Self::chunk_key(pos);
@ -122,7 +131,7 @@ impl<V: BaseVol, S: VolSize> VolMap2d<V, S> {
.reduce_and()
{
Ok(Self {
chunks: HashMap::new(),
chunks: FxHashMap::default(),
phantom: PhantomData,
})
} else {

View File

@ -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<V: BaseVol, S: VolSize> VolMap3d<V, S> {
}
}
impl<V: BaseVol, S: VolSize> BaseVol for VolMap3d<V, S> {
impl<V: BaseVol + Debug, S: VolSize> BaseVol for VolMap3d<V, S> {
type Vox = V::Vox;
type Err = VolMap3dErr<V>;
}
impl<V: BaseVol + ReadVol, S: VolSize> ReadVol for VolMap3d<V, S> {
impl<V: BaseVol + ReadVol + Debug, S: VolSize> ReadVol for VolMap3d<V, S> {
#[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&V::Vox, VolMap3dErr<V>> {
let ck = Self::chunk_key(pos);
@ -66,7 +66,7 @@ impl<V: BaseVol + ReadVol, S: VolSize> ReadVol for VolMap3d<V, S> {
// TODO: This actually breaks the API: samples are supposed to have an offset of zero!
// TODO: Should this be changed, perhaps?
impl<I: Into<Aabb<i32>>, V: BaseVol + ReadVol, S: VolSize> SampleVol<I> for VolMap3d<V, S> {
impl<I: Into<Aabb<i32>>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol<I> for VolMap3d<V, S> {
type Sample = VolMap3d<V, S>;
/// Take a sample of the terrain by cloning the voxels within the provided range.
@ -95,7 +95,7 @@ impl<I: Into<Aabb<i32>>, V: BaseVol + ReadVol, S: VolSize> SampleVol<I> for VolM
}
}
impl<V: BaseVol + WriteVol + Clone, S: VolSize + Clone> WriteVol for VolMap3d<V, S> {
impl<V: BaseVol + WriteVol + Clone + Debug, S: VolSize + Clone> WriteVol for VolMap3d<V, S> {
#[inline(always)]
fn set(&mut self, pos: Vec3<i32>, vox: V::Vox) -> Result<(), VolMap3dErr<V>> {
let ck = Self::chunk_key(pos);

View File

@ -1,6 +1,7 @@
#version 330 core
#include <globals.glsl>
#include <sky.glsl>
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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -1,6 +1,7 @@
#version 330 core
#include <globals.glsl>
#include <sky.glsl>
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);
}

View File

@ -1,6 +1,7 @@
#version 330 core
#include <globals.glsl>
#include <sky.glsl>
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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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 = <TerrainPipeline as render::Pipeline>::Vertex;
@ -46,7 +42,7 @@ impl<M> Meshable for Dyna<Block, M> {
}
*/
impl<V: BaseVol<Vox = Block> + ReadVol, S: VolSize + Clone> Meshable for VolMap2d<V, S> {
impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap2d<V, S> {
type Pipeline = TerrainPipeline;
type Supplement = Aabb<i32>;
@ -107,7 +103,7 @@ impl<V: BaseVol<Vox = Block> + ReadVol, S: VolSize + Clone> Meshable for VolMap2
}
/*
impl<V: BaseVol<Vox = Block> + ReadVol, S: VolSize + Clone> Meshable for VolMap3d<V, S> {
impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap3d<V, S> {
type Pipeline = TerrainPipeline;
type Supplement = Aabb<i32>;

View File

@ -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(

View File

@ -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<f32>,

View File

@ -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()),