diff --git a/voxygen/shaders/fluid.frag b/assets/voxygen/shaders/fluid-frag.glsl similarity index 60% rename from voxygen/shaders/fluid.frag rename to assets/voxygen/shaders/fluid-frag.glsl index f037f5bcbe..5583c72df2 100644 --- a/voxygen/shaders/fluid.frag +++ b/assets/voxygen/shaders/fluid-frag.glsl @@ -22,9 +22,13 @@ void main() { vec3 light = get_sun_diffuse(f_norm, time_of_day.x) * f_light + light_at(f_pos, f_norm); vec3 surf_color = f_col * light; - float fog_level = fog(f_pos.xy, focus_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); + + vec3 warped_norm = normalize(f_norm + (sin(f_pos.xyz + tick.x + 13.7) + sin(f_pos.zxy + tick.x + 19.3)) * 0.3); + vec3 reflect_color = get_sky_color(reflect(normalize(f_pos - cam_pos.xyz), warped_norm), time_of_day.x); + + vec3 color = mix(surf_color + reflect_color * 0.5, fog_color, fog_level); tgt_color = vec4(color, f_opac); } diff --git a/voxygen/shaders/fluid.vert b/assets/voxygen/shaders/fluid-vert.glsl similarity index 73% rename from voxygen/shaders/fluid.vert rename to assets/voxygen/shaders/fluid-vert.glsl index d62d9da725..71b14ea98e 100644 --- a/voxygen/shaders/fluid.vert +++ b/assets/voxygen/shaders/fluid-vert.glsl @@ -14,15 +14,16 @@ out vec3 f_pos; flat out vec3 f_norm; out vec3 f_col; out float f_light; +out float f_opac; // First 3 normals are negative, next 3 are positive vec3 normals[6] = vec3[]( vec3(-1,0,0), vec3(0,-1,0), vec3(0,0,-1), vec3(1,0,0), vec3(0,1,0), vec3(0,0,1) ); void main() { f_pos = vec3( - float((v_pos_norm >> 0) & 0x00FFu), - float((v_pos_norm >> 8) & 0x00FFu), - float((v_pos_norm >> 16) & 0x1FFFu) + float((v_pos_norm >> 0) & 0x00FFu), + float((v_pos_norm >> 8) & 0x00FFu), + float((v_pos_norm >> 16) & 0x1FFFu) ) + model_offs; // TODO: last 3 bits in v_pos_norm should be a number between 0 and 5, rather than 0-2 and a direction. @@ -35,15 +36,17 @@ void main() { f_norm = normals[norm_axis + norm_dir]; f_col = vec3( - float((v_col_light >> 8) & 0xFFu), - float((v_col_light >> 16) & 0xFFu), - float((v_col_light >> 24) & 0xFFu) + float((v_col_light >> 8) & 0xFFu), + float((v_col_light >> 16) & 0xFFu), + float((v_col_light >> 24) & 0xFFu) ) / 200.0; f_light = float(v_col_light & 0xFFu) / 255.0; + f_opac = 0.1; + gl_Position = - proj_mat * - view_mat * - vec4(f_pos, 1); -} \ No newline at end of file + proj_mat * + view_mat * + vec4(f_pos, 1); +} diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index f95f2cd9aa..812391f416 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -1,47 +1,97 @@ use crate::vol::Vox; use serde_derive::{Deserialize, Serialize}; +use std::ops::Deref; use vek::*; #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +#[repr(u8)] +pub enum BlockKind { + Air, + Normal, + Dense, + Water, +} + +impl BlockKind { + pub fn is_air(&self) -> bool { + match self { + BlockKind::Air => true, + _ => false, + } + } + + pub fn is_fluid(&self) -> bool { + match self { + BlockKind::Water => true, + _ => false, + } + } + + pub fn is_opaque(&self) -> bool { + match self { + BlockKind::Air => false, + BlockKind::Water => false, + _ => true, + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +#[repr(packed)] pub struct Block { - kind: u8, + kind: BlockKind, color: [u8; 3], } impl Block { - pub fn new(kind: u8, color: Rgb) -> Self { + pub fn new(kind: BlockKind, color: Rgb) -> Self { Self { kind, color: color.into_array(), } } - pub fn get_color(self) -> Option> { - if self.is_empty() { - None - } else { + pub fn get_color(&self) -> Option> { + if !self.is_air() { Some(self.color.into()) + } else { + None } } - pub fn get_opacity(self) -> Option { - match self.kind { - 0 => None, - 1 => Some(0.85), - _ => Some(3.0), - } + pub fn kind(&self) -> BlockKind { + self.kind + } +} + +impl Deref for Block { + type Target = BlockKind; + + fn deref(&self) -> &Self::Target { + &self.kind } } impl Vox for Block { fn empty() -> Self { Self { - kind: 0, + kind: BlockKind::Air, color: [0; 3], } } fn is_empty(&self) -> bool { - self.kind == 0 + self.is_air() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn block_size() { + assert_eq!(std::mem::size_of::(), 1); + assert_eq!(std::mem::size_of::(), 4); } } diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs index 96f70ac059..a8d1391161 100644 --- a/common/src/terrain/mod.rs +++ b/common/src/terrain/mod.rs @@ -4,7 +4,11 @@ pub mod chonk; pub mod structure; // Reexports -pub use self::{biome::BiomeKind, block::Block, structure::Structure}; +pub use self::{ + biome::BiomeKind, + block::{Block, BlockKind}, + structure::Structure, +}; use crate::{vol::VolSize, volumes::vol_map_2d::VolMap2d}; use serde_derive::{Deserialize, Serialize}; diff --git a/common/src/terrain/structure.rs b/common/src/terrain/structure.rs index 7302160a05..d8b3d2455d 100644 --- a/common/src/terrain/structure.rs +++ b/common/src/terrain/structure.rs @@ -1,4 +1,4 @@ -use super::Block; +use super::{Block, BlockKind}; use crate::{ assets::{self, Asset}, vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol}, @@ -103,7 +103,7 @@ impl Asset for Structure { .get(index as usize) .copied() .unwrap_or_else(|| Rgb::broadcast(0)); - StructureBlock::Block(Block::new(1, color)) + StructureBlock::Block(Block::new(BlockKind::Normal, color)) } }; diff --git a/voxygen/src/mesh/mod.rs b/voxygen/src/mesh/mod.rs index 096536477e..c8b3b36308 100644 --- a/voxygen/src/mesh/mod.rs +++ b/voxygen/src/mesh/mod.rs @@ -6,7 +6,12 @@ use crate::render::{self, Mesh}; pub trait Meshable { type Pipeline: render::Pipeline; + type TranslucentPipeline: render::Pipeline; type Supplement; - fn generate_mesh(&self, supp: Self::Supplement) -> Mesh; + // Generate meshes - one opaque, one translucent + fn generate_mesh( + &self, + supp: Self::Supplement, + ) -> (Mesh, Mesh); } diff --git a/voxygen/src/mesh/segment.rs b/voxygen/src/mesh/segment.rs index ac1667688d..1aac195d16 100644 --- a/voxygen/src/mesh/segment.rs +++ b/voxygen/src/mesh/segment.rs @@ -5,7 +5,7 @@ use crate::{ use common::{ figure::Segment, util::{linear_to_srgb, srgb_to_linear}, - vol::{ReadVol, SizedVol}, + vol::{ReadVol, SizedVol, Vox}, }; use vek::*; @@ -13,9 +13,13 @@ type FigureVertex = ::Vertex; impl Meshable for Segment { type Pipeline = FigurePipeline; + type TranslucentPipeline = FigurePipeline; type Supplement = Vec3; - fn generate_mesh(&self, offs: Self::Supplement) -> Mesh { + fn generate_mesh( + &self, + offs: Self::Supplement, + ) -> (Mesh, Mesh) { let mut mesh = Mesh::new(); for pos in self.iter_positions() { @@ -38,10 +42,11 @@ impl Meshable for Segment { }, true, &[[[1.0; 3]; 3]; 3], + |vox| vox.is_empty(), ); } } - mesh + (mesh, Mesh::new()) } } diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index 49134f4dc0..588a7130f0 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -1,9 +1,9 @@ use crate::{ mesh::{vol, Meshable}, - render::{self, Mesh, TerrainPipeline}, + render::{self, FluidPipeline, Mesh, TerrainPipeline}, }; use common::{ - terrain::Block, + terrain::{Block, BlockKind}, vol::{BaseVol, ReadVol, VolSize}, volumes::vol_map_2d::VolMap2d, }; @@ -11,43 +11,28 @@ use std::fmt::Debug; use vek::*; type TerrainVertex = ::Vertex; +type FluidVertex = ::Vertex; -/* -impl Meshable for Dyna { - type Pipeline = TerrainPipeline; - type Supplement = (); - - fn generate_mesh(&self, _: Self::Supplement) -> Mesh { - let mut mesh = Mesh::new(); - - for pos in self - .iter_positions() - .filter(|pos| pos.map(|e| e >= 1).reduce_and()) - .filter(|pos| { - pos.map2(self.get_size(), |e, sz| e < sz as i32 - 1) - .reduce_and() - }) - { - let offs = pos.map(|e| e as f32 - 1.0); - - if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { - let col = col.map(|e| e as f32 / 255.0); - - vol::push_vox_verts(&mut mesh, self, pos, offs, col, TerrainVertex::new, true); - } - } - - mesh +fn block_shadow_density(kind: BlockKind) -> Option { + match kind { + BlockKind::Air => None, + BlockKind::Normal => Some(0.85), + BlockKind::Dense => Some(3.0), + BlockKind::Water => Some(0.01), } } -*/ impl + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap2d { type Pipeline = TerrainPipeline; + type TranslucentPipeline = FluidPipeline; type Supplement = Aabb; - fn generate_mesh(&self, range: Self::Supplement) -> Mesh { - let mut mesh = Mesh::new(); + fn generate_mesh( + &self, + range: Self::Supplement, + ) -> (Mesh, Mesh) { + let mut opaque_mesh = Mesh::new(); + let mut fluid_mesh = Mesh::new(); for x in range.min.x + 1..range.max.x - 1 { for y in range.min.y + 1..range.max.y - 1 { @@ -55,16 +40,19 @@ impl + ReadVol + Debug, S: VolSize + Clone> Meshable for for z in (range.min.z..range.max.z).rev() { let pos = Vec3::new(x, y, z); + let offs = (pos - (range.min + 1) * Vec3::new(1, 1, 0)).map(|e| e as f32); + + let block = self.get(pos).ok(); // Create mesh polygons - if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { + if let Some(col) = block + .filter(|vox| vox.is_opaque()) + .and_then(|vox| vox.get_color()) + { let col = col.map(|e| e as f32 / 255.0); - let offs = (pos - range.min * Vec3::new(1, 1, 0)).map(|e| e as f32) - - Vec3::new(1.0, 1.0, 0.0); - vol::push_vox_verts( - &mut mesh, + &mut opaque_mesh, self, pos, offs, @@ -74,6 +62,26 @@ impl + ReadVol + Debug, S: VolSize + Clone> Meshable for }, false, &neighbour_light, + |vox| !vox.is_opaque(), + ); + } else if let Some(col) = block + .filter(|vox| vox.is_fluid()) + .and_then(|vox| vox.get_color()) + { + let col = col.map(|e| e as f32 / 255.0); + + vol::push_vox_verts( + &mut fluid_mesh, + self, + pos, + offs, + col, + |pos, norm, col, ao, light| { + FluidVertex::new(pos, norm, col, light * ao, 0.3) + }, + false, + &neighbour_light, + |vox| vox.is_air(), ); } @@ -84,13 +92,13 @@ 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[0][i][j] = if let Some(opacity) = self + neighbour_light[0][i][j] = if let Some(density) = self .get(pos + Vec3::new(i as i32 - 1, j as i32 - 1, -1)) .ok() - .and_then(|vox| vox.get_opacity()) + .and_then(|vox| block_shadow_density(vox.kind())) { - (neighbour_light[0][i][j] * (1.0 - opacity * 0.1)) - .max(1.0 - opacity) + (neighbour_light[0][i][j] * (1.0 - density * 0.1)) + .max(1.0 - density) } else { (neighbour_light[0][i][j] * 1.025).min(1.0) }; @@ -108,7 +116,8 @@ impl + ReadVol + Debug, S: VolSize + Clone> Meshable for } } } - mesh + + (opaque_mesh, fluid_mesh) } } diff --git a/voxygen/src/mesh/vol.rs b/voxygen/src/mesh/vol.rs index 0e98b84511..1d8a6d4d9e 100644 --- a/voxygen/src/mesh/vol.rs +++ b/voxygen/src/mesh/vol.rs @@ -88,26 +88,23 @@ fn create_quad, Vec3, Rgb, f32, f32) -> P } } -pub fn push_vox_verts< - V: ReadVol, - P: Pipeline, - F: Fn(Vec3, Vec3, Rgb, f32, f32) -> P::Vertex, ->( +pub fn push_vox_verts( mesh: &mut Mesh

, vol: &V, pos: Vec3, offs: Vec3, col: Rgb, - vcons: F, + vcons: impl Fn(Vec3, Vec3, Rgb, f32, f32) -> P::Vertex, error_makes_face: bool, darknesses: &[[[f32; 3]; 3]; 3], + should_add: impl Fn(&V::Vox) -> bool, ) { let (x, y, z) = (Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z()); // -x if vol .get(pos - Vec3::unit_x()) - .map(|v| v.is_empty()) + .map(|v| should_add(v)) .unwrap_or(error_makes_face) { mesh.push_quad(create_quad( @@ -123,7 +120,7 @@ pub fn push_vox_verts< // +x if vol .get(pos + Vec3::unit_x()) - .map(|v| v.is_empty()) + .map(|v| should_add(v)) .unwrap_or(error_makes_face) { mesh.push_quad(create_quad( @@ -139,7 +136,7 @@ pub fn push_vox_verts< // -y if vol .get(pos - Vec3::unit_y()) - .map(|v| v.is_empty()) + .map(|v| should_add(v)) .unwrap_or(error_makes_face) { mesh.push_quad(create_quad( @@ -155,7 +152,7 @@ pub fn push_vox_verts< // +y if vol .get(pos + Vec3::unit_y()) - .map(|v| v.is_empty()) + .map(|v| should_add(v)) .unwrap_or(error_makes_face) { mesh.push_quad(create_quad( @@ -171,7 +168,7 @@ pub fn push_vox_verts< // -z if vol .get(pos - Vec3::unit_z()) - .map(|v| v.is_empty()) + .map(|v| should_add(v)) .unwrap_or(error_makes_face) { mesh.push_quad(create_quad( @@ -187,7 +184,7 @@ pub fn push_vox_verts< // +z if vol .get(pos + Vec3::unit_z()) - .map(|v| v.is_empty()) + .map(|v| should_add(v)) .unwrap_or(error_makes_face) { mesh.push_quad(create_quad( diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 4cd3e676b2..369142cd90 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -13,6 +13,7 @@ pub use self::{ model::{DynamicModel, Model}, pipelines::{ figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals}, + fluid::FluidPipeline, postprocess::{ create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline, }, @@ -22,7 +23,6 @@ pub use self::{ create_quad as create_ui_quad, create_tri as create_ui_tri, Locals as UiLocals, Mode as UiMode, UiPipeline, }, - fluid::{Locals as FluidLocals, FluidPipeline}, Globals, Light, }, renderer::{Renderer, TgtColorFmt, TgtDepthFmt, WinColorFmt, WinDepthFmt}, diff --git a/voxygen/src/render/pipelines/fluid.rs b/voxygen/src/render/pipelines/fluid.rs index e91e143d64..c88dc6f454 100644 --- a/voxygen/src/render/pipelines/fluid.rs +++ b/voxygen/src/render/pipelines/fluid.rs @@ -1,16 +1,16 @@ use super::{ - super::{Pipeline, TgtColorFmt, TgtDepthFmt}, + super::{Pipeline, TerrainLocals, TgtColorFmt, TgtDepthFmt}, Globals, Light, }; use gfx::{ self, - gfx_constant_struct_meta, // Macros gfx_defines, gfx_impl_struct_meta, gfx_pipeline, gfx_pipeline_inner, gfx_vertex_struct_meta, + state::ColorMask, }; use std::ops::Mul; use vek::*; @@ -21,18 +21,14 @@ gfx_defines! { col_light: u32 = "v_col_light", } - constant Locals { - model_offs: [f32; 3] = "model_offs", - } - pipeline pipe { vbuf: gfx::VertexBuffer = (), - locals: gfx::ConstantBuffer = "u_locals", + locals: gfx::ConstantBuffer = "u_locals", globals: gfx::ConstantBuffer = "u_globals", lights: gfx::ConstantBuffer = "u_lights", - tgt_color: gfx::RenderTarget = "tgt_color", + tgt_color: gfx::BlendTarget = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA), tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, } } @@ -57,16 +53,8 @@ impl Vertex { | ((col.r.mul(200.0) as u32) & 0xFF) << 8 | ((col.g.mul(200.0) as u32) & 0xFF) << 16 | ((col.b.mul(200.0) as u32) & 0xFF) << 24 - | ((light.mul(255.0) as u32) & 0xFF) << 0 - | ((opac.mul(0.4) as u32) & 0xFF) << 0, - } - } -} - -impl Locals { - pub fn default() -> Self { - Self { - model_offs: [0.0; 3], + | ((light.mul(255.0) as u32) & 0xFF) << 0, + //| ((opac.mul(0.4) as u32) & 0xFF) << 0, } } } diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index 6184e74a39..801e3b9a74 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -1,9 +1,9 @@ pub mod figure; +pub mod fluid; pub mod postprocess; pub mod skybox; pub mod terrain; pub mod ui; -pub mod fluid; use super::util::arr_to_mat; use gfx::{ diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index e659e9869d..91e76032f5 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -3,7 +3,7 @@ use super::{ gfx_backend, mesh::Mesh, model::{DynamicModel, Model}, - pipelines::{figure, postprocess, skybox, terrain, ui, Globals, Light, fluid}, + pipelines::{figure, fluid, postprocess, skybox, terrain, ui, Globals, Light}, texture::Texture, Pipeline, RenderError, }; @@ -64,6 +64,7 @@ pub struct Renderer { skybox_pipeline: GfxPipeline>, figure_pipeline: GfxPipeline>, terrain_pipeline: GfxPipeline>, + fluid_pipeline: GfxPipeline>, ui_pipeline: GfxPipeline>, postprocess_pipeline: GfxPipeline>, @@ -80,18 +81,9 @@ impl Renderer { ) -> Result { let mut shader_reload_indicator = ReloadIndicator::new(); - let (skybox_pipeline, figure_pipeline, terrain_pipeline, ui_pipeline, postprocess_pipeline) = + let (skybox_pipeline, figure_pipeline, terrain_pipeline, fluid_pipeline, ui_pipeline, postprocess_pipeline) = create_pipelines(&mut factory, &mut shader_reload_indicator)?; - // Construct a pipeline for rendering fluids - let fluid_pipeline = create_pipeline( - &mut factory, - fluid::pipe::new(), - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/fluid.vert")), - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/fluid.frag")), - &include_ctx, - )?; - let dims = win_color_view.get_dimensions(); let (tgt_color_view, tgt_depth_view, tgt_color_res) = Self::create_rt_views(&mut factory, (dims.0, dims.1))?; @@ -115,6 +107,7 @@ impl Renderer { skybox_pipeline, figure_pipeline, terrain_pipeline, + fluid_pipeline, ui_pipeline, postprocess_pipeline, @@ -200,13 +193,15 @@ impl Renderer { Ok(( skybox_pipeline, figure_pipeline, - terrain_pipline, + terrain_pipeline, + fluid_pipeline, ui_pipeline, postprocess_pipeline, )) => { self.skybox_pipeline = skybox_pipeline; self.figure_pipeline = figure_pipeline; - self.terrain_pipeline = terrain_pipline; + self.terrain_pipeline = terrain_pipeline; + self.fluid_pipeline = fluid_pipeline; self.ui_pipeline = ui_pipeline; self.postprocess_pipeline = postprocess_pipeline; } @@ -407,6 +402,28 @@ impl Renderer { ); } + /// Queue the rendering of the provided terrain chunk model in the upcoming frame. + pub fn render_fluid_chunk( + &mut self, + model: &Model, + globals: &Consts, + locals: &Consts, + lights: &Consts, + ) { + self.encoder.draw( + &model.slice, + &self.fluid_pipeline.pso, + &fluid::pipe::Data { + vbuf: model.vbuf.clone(), + locals: locals.buf.clone(), + globals: globals.buf.clone(), + lights: lights.buf.clone(), + tgt_color: self.tgt_color_view.clone(), + tgt_depth: self.tgt_depth_view.clone(), + }, + ); + } + /// Queue the rendering of the provided UI element in the upcoming frame. pub fn render_ui_element( &mut self, @@ -471,6 +488,7 @@ fn create_pipelines( GfxPipeline>, GfxPipeline>, GfxPipeline>, + GfxPipeline>, GfxPipeline>, GfxPipeline>, ), @@ -528,6 +546,17 @@ fn create_pipelines( &include_ctx, )?; + // Construct a pipeline for rendering fluids + let fluid_pipeline = create_pipeline( + factory, + fluid::pipe::new(), + &assets::load_watched::("voxygen.shaders.fluid-vert", shader_reload_indicator) + .unwrap(), + &assets::load_watched::("voxygen.shaders.fluid-frag", shader_reload_indicator) + .unwrap(), + &include_ctx, + )?; + // Construct a pipeline for rendering UI elements let ui_pipeline = create_pipeline( factory, @@ -560,6 +589,7 @@ fn create_pipelines( skybox_pipeline, figure_pipeline, terrain_pipeline, + fluid_pipeline, ui_pipeline, postprocess_pipeline, )) diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 94275944a9..dea1155706 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -165,6 +165,7 @@ impl FigureModelCache { let full_specifier: String = ["voxygen.voxel.", mesh_name].concat(); Segment::from(assets::load_expect::(full_specifier.as_str()).as_ref()) .generate_mesh(position) + .0 } fn load_head(race: humanoid::Race, body_type: humanoid::BodyType) -> Mesh { diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 50acb1a533..a043709fc8 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -221,9 +221,9 @@ impl Scene { renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals); // Render terrain and figures. - self.terrain.render(renderer, &self.globals, &self.lights); self.figure_mgr .render(renderer, client, &self.globals, &self.lights, &self.camera); + self.terrain.render(renderer, &self.globals, &self.lights); renderer.render_post_process( &self.postprocess.model, diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 637f76ea24..deed0a9fcb 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -1,6 +1,9 @@ use crate::{ mesh::Meshable, - render::{Consts, Globals, Light, Mesh, Model, Renderer, TerrainLocals, TerrainPipeline}, + render::{ + Consts, FluidPipeline, Globals, Light, Mesh, Model, Renderer, TerrainLocals, + TerrainPipeline, + }, }; use client::Client; use common::{ @@ -16,7 +19,8 @@ use vek::*; struct TerrainChunk { // GPU data - model: Model, + opaque_model: Model, + fluid_model: Model, locals: Consts, visible: bool, z_bounds: (f32, f32), @@ -32,7 +36,8 @@ struct ChunkMeshState { struct MeshWorkerResponse { pos: Vec2, z_bounds: (f32, f32), - mesh: Mesh, + opaque_mesh: Mesh, + fluid_mesh: Mesh, started_tick: u64, } @@ -44,10 +49,12 @@ fn mesh_worker( volume: >>::Sample, range: Aabb, ) -> MeshWorkerResponse { + let (opaque_mesh, fluid_mesh) = volume.generate_mesh(range); MeshWorkerResponse { pos, z_bounds, - mesh: volume.generate_mesh(range), + opaque_mesh, + fluid_mesh, started_tick, } } @@ -262,8 +269,11 @@ impl Terrain { self.chunks.insert( response.pos, TerrainChunk { - model: renderer - .create_model(&response.mesh) + opaque_model: renderer + .create_model(&response.opaque_mesh) + .expect("Failed to upload chunk mesh to the GPU!"), + fluid_model: renderer + .create_model(&response.fluid_mesh) .expect("Failed to upload chunk mesh to the GPU!"), locals: renderer .create_consts(&[TerrainLocals { @@ -334,9 +344,17 @@ impl Terrain { globals: &Consts, lights: &Consts, ) { + // Opaque for (_pos, chunk) in &self.chunks { if chunk.visible { - renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals, lights); + renderer.render_terrain_chunk(&chunk.opaque_model, globals, &chunk.locals, lights); + } + } + + // Translucent + for (_pos, chunk) in &self.chunks { + if chunk.visible { + renderer.render_fluid_chunk(&chunk.fluid_model, globals, &chunk.locals, lights); } } } diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 36cd3d995f..99e84bd260 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -8,7 +8,13 @@ use crate::{ }; use client::{self, Client}; use common::{ - clock::Clock, comp, comp::Pos, comp::Vel, msg::ClientState, terrain::Block, vol::ReadVol, + clock::Clock, + comp, + comp::Pos, + comp::Vel, + msg::ClientState, + terrain::{Block, BlockKind}, + vol::ReadVol, }; use log::error; use specs::Join; @@ -39,7 +45,7 @@ impl SessionState { key_state: KeyState::new(), controller: comp::Controller::default(), hud: Hud::new(global_state), - selected_block: Block::new(1, Rgb::broadcast(255)), + selected_block: Block::new(BlockKind::Normal, Rgb::broadcast(255)), } } } diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index fc4e7123f2..2396b9fdeb 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -6,7 +6,7 @@ use crate::{ World, CONFIG, }; use common::{ - terrain::{structure::StructureBlock, Block, Structure}, + terrain::{structure::StructureBlock, Block, BlockKind, Structure}, util::saturate_srgb, vol::{ReadVol, Vox}, }; @@ -221,8 +221,7 @@ impl<'a> BlockGen<'a> { // let sand = Block::new(1, Rgb::new(180, 150, 50)); // let warm_stone = Block::new(1, Rgb::new(165, 165, 130)); - //let water = Block::new(1, Rgb::new(100, 150, 255)); - let water = Block::new(1, Rgb::new(0, 24, 255)); + let water = Block::new(BlockKind::Water, Rgb::new(0, 24, 255)); let grass_depth = 1.5 + 2.0 * chaos; let block = if (wposf.z as f32) < height - grass_depth { @@ -234,9 +233,9 @@ impl<'a> BlockGen<'a> { // Underground if (wposf.z as f32) > alt - 32.0 * chaos { - Some(Block::new(1, col)) + Some(Block::new(BlockKind::Normal, col)) } else { - Some(Block::new(2, col)) + Some(Block::new(BlockKind::Dense, col)) } } else if (wposf.z as f32) < height { let col = Lerp::lerp( @@ -248,7 +247,7 @@ impl<'a> BlockGen<'a> { ); // Surface Some(Block::new( - 1, + BlockKind::Normal, saturate_srgb(col, 0.45).map(|e| (e * 255.0) as u8), )) } else if (wposf.z as f32) < water_height { @@ -284,7 +283,7 @@ impl<'a> BlockGen<'a> { let field2 = RandomField::new(world.sim().seed + 2); Some(Block::new( - 1, + BlockKind::Normal, stone_col - Rgb::new( field0.get(wpos) as u8 % 16, @@ -415,7 +414,7 @@ impl StructureInfo { .map(|e: i32| (e.abs() / 2) * 2) .reduce_max() { - Some(Block::new(2, Rgb::new(203, 170, 146))) + Some(Block::new(BlockKind::Dense, Rgb::new(203, 170, 146))) } else { None } @@ -452,39 +451,27 @@ fn block_from_structure( match sblock { StructureBlock::TemperateLeaves => Some(Block::new( - 1, - Lerp::lerp( - Rgb::new(0.0, 132.0, 94.0), - Rgb::new(142.0, 181.0, 0.0), - lerp, - ) - .map(|e| e as u8), + BlockKind::Normal, + Lerp::lerp(Rgb::new(0.0, 132.0, 94.0), Rgb::new(142.0, 181.0, 0.0), lerp) + .map(|e| e as u8), )), StructureBlock::PineLeaves => Some(Block::new( - 1, - Lerp::lerp( - Rgb::new(0.0, 108.0, 113.0), - Rgb::new(30.0, 156.0, 10.0), - lerp, - ) - .map(|e| e as u8), + BlockKind::Normal, + Lerp::lerp(Rgb::new(0.0, 60.0, 50.0), Rgb::new(30.0, 100.0, 10.0), lerp) + .map(|e| e as u8), )), StructureBlock::PalmLeaves => Some(Block::new( - 1, - Lerp::lerp( - Rgb::new(15.0, 156.0, 70.0), - Rgb::new(40.0, 222.0, 0.0), - lerp, - ) - .map(|e| e as u8), + BlockKind::Normal, + Lerp::lerp(Rgb::new(0.0, 108.0, 113.0), Rgb::new(30.0, 156.0, 10.0), lerp) + .map(|e| e as u8), )), StructureBlock::Acacia => Some(Block::new( - 1, + BlockKind::Normal, Lerp::lerp(Rgb::new(35.0, 156.0, 0.0), Rgb::new(62.0, 208.0, 0.0), lerp) .map(|e| e as u8), )), StructureBlock::Fruit => Some(Block::new( - 1, + BlockKind::Normal, Lerp::lerp(Rgb::new(237.0, 0.0, 0.0), Rgb::new(200.0, 237.0, 0.0), lerp) .map(|e| e as u8), )), diff --git a/world/src/lib.rs b/world/src/lib.rs index b93b4bdcca..d84c128f7f 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -16,7 +16,7 @@ use crate::{ util::{Sampler, SamplerMut}, }; use common::{ - terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize}, + terrain::{Block, BlockKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize}, vol::{ReadVol, VolSize, Vox, WriteVol}, }; use rand::Rng; @@ -59,8 +59,8 @@ impl World { pub fn generate_chunk(&self, chunk_pos: Vec2) -> (TerrainChunk, ChunkSupplement) { let air = Block::empty(); - let stone = Block::new(2, Rgb::new(200, 220, 255)); - let water = Block::new(5, Rgb::new(100, 150, 255)); + let stone = Block::new(BlockKind::Dense, Rgb::new(200, 220, 255)); + let water = Block::new(BlockKind::Water, Rgb::new(100, 150, 255)); let chunk_size2d = Vec2::from(TerrainChunkSize::SIZE); let (base_z, sim_chunk) = match self