diff --git a/voxygen/src/mesh/mod.rs b/voxygen/src/mesh/mod.rs index 1f938ff930..7fb9f8e43d 100644 --- a/voxygen/src/mesh/mod.rs +++ b/voxygen/src/mesh/mod.rs @@ -1,11 +1,9 @@ +mod vol; pub mod segment; pub mod terrain; // Crate -use crate::render::{ - self, - Mesh, -}; +use crate::render::{self, Mesh}; pub trait Meshable { type Pipeline: render::Pipeline; diff --git a/voxygen/src/mesh/segment.rs b/voxygen/src/mesh/segment.rs index d7eb6d4274..620adcfc30 100644 --- a/voxygen/src/mesh/segment.rs +++ b/voxygen/src/mesh/segment.rs @@ -3,43 +3,20 @@ use vek::*; // Project use common::{ - vol::{ - Vox, - SizedVol, - ReadVol, - }, figure::Segment, + vol::{ReadVol, SizedVol, Vox}, }; // Crate use crate::{ - mesh::Meshable, - render::{ - self, - Mesh, - Quad, - FigurePipeline, - }, + mesh::{vol, Meshable}, + render::{self, FigurePipeline, Mesh, Quad}, }; type FigureVertex = ::Vertex; -// Utility function -// TODO: Evaluate how useful this is -fn create_quad( - origin: Vec3, - unit_x: Vec3, - unit_y: Vec3, - norm: Vec3, - col: Rgb, - bone: u8, -) -> Quad { - Quad::new( - FigureVertex::new(origin, norm, col, bone), - FigureVertex::new(origin + unit_x, norm, col, bone), - FigureVertex::new(origin + unit_x + unit_y, norm, col, bone), - FigureVertex::new(origin + unit_y, norm, col, bone), - ) +fn create_vertex(origin: Vec3, norm: Vec3, col: Rgb) -> FigureVertex { + FigureVertex::new(origin, norm, col, 0) } impl Meshable for Segment { @@ -50,97 +27,17 @@ impl Meshable for Segment { let mut mesh = Mesh::new(); for pos in self.iter_positions() { - if let Some(col) = self - .get(pos) - .ok() - .and_then(|vox| vox.get_color()) - { + if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { let col = col.map(|e| e as f32 / 255.0); - // -x - if self.get(pos - Vec3::unit_x()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs + pos.map(|e| e as f32) + Vec3::unit_y(), - -Vec3::unit_y(), - Vec3::unit_z(), - -Vec3::unit_x(), - col, - 0, - )); - } - // +x - if self.get(pos + Vec3::unit_x()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs + pos.map(|e| e as f32) + Vec3::unit_x(), - Vec3::unit_y(), - Vec3::unit_z(), - Vec3::unit_x(), - col, - 0, - )); - } - // -y - if self.get(pos - Vec3::unit_y()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs + pos.map(|e| e as f32), - Vec3::unit_x(), - Vec3::unit_z(), - -Vec3::unit_y(), - col, - 0, - )); - } - // +y - if self.get(pos + Vec3::unit_y()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs + pos.map(|e| e as f32) + Vec3::unit_y(), - Vec3::unit_z(), - Vec3::unit_x(), - Vec3::unit_y(), - col, - 0, - )); - } - // -z - if self.get(pos - Vec3::unit_z()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs + pos.map(|e| e as f32), - Vec3::unit_y(), - Vec3::unit_x(), - -Vec3::unit_z(), - col, - 0, - )); - } - // +z - if self.get(pos + Vec3::unit_z()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs + pos.map(|e| e as f32) + Vec3::unit_z(), - Vec3::unit_x(), - Vec3::unit_y(), - Vec3::unit_z(), - col, - 0, - )); - } + vol::push_vox_verts( + &mut mesh, + self, + pos, + offs + pos.map(|e| e as f32), + col, + create_vertex, + ); } } diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index b6cd2dd67e..a9157419e7 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -3,45 +3,19 @@ use vek::*; // Project use common::{ - vol::{ - Vox, - SizedVol, - ReadVol, - }, - volumes::dyna::Dyna, terrain::Block, + vol::{ReadVol, SizedVol, Vox}, + volumes::dyna::Dyna, }; // Crate use crate::{ - mesh::Meshable, - render::{ - self, - Mesh, - Quad, - TerrainPipeline, - }, + mesh::{vol, Meshable}, + render::{self, Mesh, Quad, TerrainPipeline}, }; type TerrainVertex = ::Vertex; -// Utility function -// TODO: Evaluate how useful this is -fn create_quad( - origin: Vec3, - unit_x: Vec3, - unit_y: Vec3, - norm: Vec3, - col: Rgb, -) -> Quad { - Quad::new( - TerrainVertex::new(origin, norm, col), - TerrainVertex::new(origin + unit_x, norm, col), - TerrainVertex::new(origin + unit_x + unit_y, norm, col), - TerrainVertex::new(origin + unit_y, norm, col), - ) -} - impl Meshable for Dyna { type Pipeline = TerrainPipeline; type Supplement = (); @@ -52,95 +26,17 @@ impl Meshable for Dyna { 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()) + .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()) - { + if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { let col = col.map(|e| e as f32 / 255.0); - // -x - if self.get(pos - Vec3::unit_x()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs, - Vec3::unit_z(), - Vec3::unit_y(), - -Vec3::unit_x(), - col, - )); - } - // +x - if self.get(pos + Vec3::unit_x()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs + Vec3::unit_x(), - Vec3::unit_y(), - Vec3::unit_z(), - Vec3::unit_x(), - col, - )); - } - // -y - if self.get(pos - Vec3::unit_y()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs, - Vec3::unit_x(), - Vec3::unit_z(), - -Vec3::unit_y(), - col, - )); - } - // +y - if self.get(pos + Vec3::unit_y()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs + Vec3::unit_y(), - Vec3::unit_z(), - Vec3::unit_x(), - Vec3::unit_y(), - col, - )); - } - // -z - if self.get(pos - Vec3::unit_z()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs, - Vec3::unit_y(), - Vec3::unit_x(), - -Vec3::unit_z(), - col, - )); - } - // +z - if self.get(pos + Vec3::unit_z()) - .map(|v| v.is_empty()) - .unwrap_or(true) - { - mesh.push_quad(create_quad( - offs + Vec3::unit_z(), - Vec3::unit_x(), - Vec3::unit_y(), - Vec3::unit_z(), - col, - )); - } + vol::push_vox_verts(&mut mesh, self, pos, offs, col, TerrainVertex::new); } } diff --git a/voxygen/src/mesh/vol.rs b/voxygen/src/mesh/vol.rs new file mode 100644 index 0000000000..ea47d9bde5 --- /dev/null +++ b/voxygen/src/mesh/vol.rs @@ -0,0 +1,179 @@ +use vek::*; + +use common::vol::{ReadVol, Vox}; + +use crate::render::{ + mesh::{Mesh, Quad}, + Pipeline, +}; + +/// Given a volume, a position and the cardinal directions, compute each vertex' AO value +/// `dirs` should be a slice of length 5 so that the sliding window of size 2 over the slice +/// yields each vertex' adjacent positions. +fn get_ao_quad(vol: &V, pos: Vec3, dirs: &[Vec3]) -> Vec4 { + dirs.windows(2) + .map(|offs| { + let (s1, s2) = ( + vol.get(pos + offs[0]) + .map(|v| v.is_empty() as i32) + .unwrap_or(1), + vol.get(pos + offs[1]) + .map(|v| v.is_empty() as i32) + .unwrap_or(1), + ); + + if s1 == 0 && s2 == 0 { + 0 + } else { + let corner = vol + .get(pos + offs[0] + offs[1]) + .map(|v| v.is_empty() as i32) + .unwrap_or(1); + s1 + s2 + corner + } + }) + .map(|i| i as f32 / 3.0) + .collect::>() +} + +// Utility function +fn create_quad, Vec3, Rgb) -> P::Vertex>( + origin: Vec3, + unit_x: Vec3, + unit_y: Vec3, + norm: Vec3, + col: Rgb, + ao: Vec4, + vcons: &F, +) -> Quad

{ + let ao_scale = 1.0; + let dark = col * (1.0 - ao_scale); + + if ao[0] + ao[2] < ao[1] + ao[3] { + Quad::new( + vcons(origin + unit_y, norm, Rgb::lerp(dark, col, ao[3])), + vcons(origin, norm, Rgb::lerp(dark, col, ao[0])), + vcons(origin + unit_x, norm, Rgb::lerp(dark, col, ao[1])), + vcons(origin + unit_x + unit_y, norm, Rgb::lerp(dark, col, ao[2])), + ) + } else { + Quad::new( + vcons(origin, norm, Rgb::lerp(dark, col, ao[0])), + vcons(origin + unit_x, norm, Rgb::lerp(dark, col, ao[1])), + vcons(origin + unit_x + unit_y, norm, Rgb::lerp(dark, col, ao[2])), + vcons(origin + unit_y, norm, Rgb::lerp(dark, col, ao[3])), + ) + } +} + +pub fn push_vox_verts< + V: ReadVol, + P: Pipeline, + F: Fn(Vec3, Vec3, Rgb) -> P::Vertex, +>( + mesh: &mut Mesh

, + vol: &V, + pos: Vec3, + offs: Vec3, + col: Rgb, + vcons: F, +) { + 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()) + .unwrap_or(true) + { + mesh.push_quad(create_quad( + offs, + Vec3::unit_z(), + Vec3::unit_y(), + -Vec3::unit_x(), + col, + get_ao_quad(vol, pos - Vec3::unit_x(), &[-z, -y, z, y, -z]), + &vcons, + )); + } + // +x + if vol + .get(pos + Vec3::unit_x()) + .map(|v| v.is_empty()) + .unwrap_or(true) + { + mesh.push_quad(create_quad( + offs + Vec3::unit_x(), + Vec3::unit_y(), + Vec3::unit_z(), + Vec3::unit_x(), + col, + get_ao_quad(vol, pos + Vec3::unit_x(), &[-y, -z, y, z, -y]), + &vcons, + )); + } + // -y + if vol + .get(pos - Vec3::unit_y()) + .map(|v| v.is_empty()) + .unwrap_or(true) + { + mesh.push_quad(create_quad( + offs, + Vec3::unit_x(), + Vec3::unit_z(), + -Vec3::unit_y(), + col, + get_ao_quad(vol, pos - Vec3::unit_y(), &[-x, -z, x, z, -x]), + &vcons, + )); + } + // +y + if vol + .get(pos + Vec3::unit_y()) + .map(|v| v.is_empty()) + .unwrap_or(true) + { + mesh.push_quad(create_quad( + offs + Vec3::unit_y(), + Vec3::unit_z(), + Vec3::unit_x(), + Vec3::unit_y(), + col, + get_ao_quad(vol, pos + Vec3::unit_y(), &[-z, -x, z, x, -z]), + &vcons, + )); + } + // -z + if vol + .get(pos - Vec3::unit_z()) + .map(|v| v.is_empty()) + .unwrap_or(true) + { + mesh.push_quad(create_quad( + offs, + Vec3::unit_y(), + Vec3::unit_x(), + -Vec3::unit_z(), + col, + get_ao_quad(vol, pos - Vec3::unit_z(), &[-y, -x, y, x, -y]), + &vcons, + )); + } + // +z + if vol + .get(pos + Vec3::unit_z()) + .map(|v| v.is_empty()) + .unwrap_or(true) + { + mesh.push_quad(create_quad( + offs + Vec3::unit_z(), + Vec3::unit_x(), + Vec3::unit_y(), + Vec3::unit_z(), + col, + get_ao_quad(vol, pos + Vec3::unit_z(), &[-x, -y, x, y, -x]), + &vcons, + )); + } +}