diff --git a/assets/voxygen/shaders/include/lod.glsl b/assets/voxygen/shaders/include/lod.glsl index d363645b48..704d0a35b4 100644 --- a/assets/voxygen/shaders/include/lod.glsl +++ b/assets/voxygen/shaders/include/lod.glsl @@ -1,6 +1,15 @@ #include +uniform sampler2D t_map; + +vec2 pos_to_uv(vec2 pos) { + vec2 uv_pos = pos / 32768.0; + return vec2(uv_pos.x, 1.0 - uv_pos.y); +} + float alt_at(vec2 pos) { + return texture(t_map, pos_to_uv(pos)).a * (1500.0); + return 0.0 + pow(texture(t_noise, pos * 0.00005).x * 1.4, 3.0) * 1000.0 + texture(t_noise, pos * 0.001).x * 100.0 @@ -11,9 +20,19 @@ vec2 splay(vec2 pos, float e) { return pos * pow(length(pos), e); } +float splay_scale(vec2 pos, float e) { + return distance(splay(pos, e), splay(pos + 0.001, e)) * 500000.0; +} + vec3 lod_pos(vec2 v_pos) { vec2 hpos = focus_pos.xy + splay(v_pos, 5.0) * 1000000.0; - return vec3(hpos, alt_at(hpos)); + float splay = splay_scale(v_pos, 5.0); + return vec3(hpos, ( + alt_at(hpos + vec2(-1, 1) * splay) + + alt_at(hpos + vec2(1, 1) * splay) + + alt_at(hpos + vec2(1, -1) * splay) + + alt_at(hpos + vec2(-1, -1) * splay) + ) / 4.0); } vec3 lod_norm(vec2 pos) { @@ -25,11 +44,13 @@ vec3 lod_norm(vec2 pos) { return normalize(vec3( (alt00 - alt10) / 100, (alt00 - alt01) / 100, - 100 / slope + 100 / (slope + 0.00001) // Avoid NaN )); } vec3 lod_col(vec2 pos) { + return texture(t_map, pos_to_uv(pos)).rgb; + vec3 warmth = mix( vec3(0.05, 0.4, 0.1), vec3(0.5, 0.4, 0.0), diff --git a/assets/voxygen/shaders/lod-terrain-vert.glsl b/assets/voxygen/shaders/lod-terrain-vert.glsl index 5801c5d0cf..d319c9430e 100644 --- a/assets/voxygen/shaders/lod-terrain-vert.glsl +++ b/assets/voxygen/shaders/lod-terrain-vert.glsl @@ -15,9 +15,9 @@ out vec3 f_pos; out float f_light; void main() { - f_pos = lod_pos(v_pos); + f_pos = lod_pos(v_pos + vec2(0, -v_pos.x * 0.5)); - f_pos.z -= 25.0 / pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0); + f_pos.z -= 5.0 / pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.9), 20.0); f_light = 1.0; diff --git a/assets/voxygen/shaders/terrain-vert.glsl b/assets/voxygen/shaders/terrain-vert.glsl index 52b21fad54..afb0ac114e 100644 --- a/assets/voxygen/shaders/terrain-vert.glsl +++ b/assets/voxygen/shaders/terrain-vert.glsl @@ -21,7 +21,7 @@ void main() { f_pos = vec3((uvec3(v_pos_norm) >> uvec3(0, 8, 16)) & uvec3(0xFFu, 0xFFu, 0x1FFFu)) + model_offs; f_pos.z *= min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0); - f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0); + f_pos.z -= 5.0 * pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.9), 20.0); f_col = vec3((uvec3(v_col_light) >> uvec3(8, 16, 24)) & uvec3(0xFFu)) / 255.0; diff --git a/voxygen/src/render/error.rs b/voxygen/src/render/error.rs index 7a66b47488..12351d427f 100644 --- a/voxygen/src/render/error.rs +++ b/voxygen/src/render/error.rs @@ -18,20 +18,21 @@ impl From> for RenderError { impl From> for RenderError { fn from(err: gfx::PipelineStateError<&str>) -> Self { - // This is horrid. We do it to get rid of the `&str`'s lifetime bound by turning it into a `String`. + // This is horrid. We do it to get rid of the `&str`'s lifetime bound by turning + // it into a `String`. match err { gfx::PipelineStateError::DescriptorInit(err) => { gfx::PipelineStateError::DescriptorInit(match err { gfx::pso::InitError::VertexImport(s, x) => { gfx::pso::InitError::VertexImport(s.to_string(), x) - } + }, gfx::pso::InitError::ConstantBuffer(s, x) => { gfx::pso::InitError::ConstantBuffer( s.to_string(), x.map(|x| match x { gfx::pso::ElementError::NotFound(s) => { gfx::pso::ElementError::NotFound(s.to_string()) - } + }, gfx::pso::ElementError::Offset { name, shader_offset, @@ -52,24 +53,24 @@ impl From> for RenderError { }, }), ) - } + }, gfx::pso::InitError::GlobalConstant(s, x) => { gfx::pso::InitError::GlobalConstant(s.to_string(), x) - } + }, gfx::pso::InitError::ResourceView(s, x) => { gfx::pso::InitError::ResourceView(s.to_string(), x) - } + }, gfx::pso::InitError::UnorderedView(s, x) => { gfx::pso::InitError::UnorderedView(s.to_string(), x) - } + }, gfx::pso::InitError::Sampler(s, x) => { gfx::pso::InitError::Sampler(s.to_string(), x) - } + }, gfx::pso::InitError::PixelExport(s, x) => { gfx::pso::InitError::PixelExport(s.to_string(), x) - } + }, }) - } + }, gfx::PipelineStateError::Program(p) => gfx::PipelineStateError::Program(p), gfx::PipelineStateError::DeviceCreate(c) => gfx::PipelineStateError::DeviceCreate(c), } diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 78c3758dc9..f4ec260afd 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -34,6 +34,7 @@ pub use self::{ renderer::{Renderer, TgtColorFmt, TgtDepthFmt, WinColorFmt, WinDepthFmt}, texture::Texture, }; +pub use gfx::texture::{FilterMethod, WrapMode}; #[cfg(feature = "gl")] use gfx_device_gl as gfx_backend; diff --git a/voxygen/src/render/pipelines/lod_terrain.rs b/voxygen/src/render/pipelines/lod_terrain.rs index 334a1295b7..83ca581c0b 100644 --- a/voxygen/src/render/pipelines/lod_terrain.rs +++ b/voxygen/src/render/pipelines/lod_terrain.rs @@ -3,14 +3,8 @@ use super::{ Globals, }; use gfx::{ - self, - gfx_constant_struct_meta, - // Macros - gfx_defines, - gfx_impl_struct_meta, - gfx_pipeline, - gfx_pipeline_inner, - gfx_vertex_struct_meta, + self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, + gfx_pipeline_inner, gfx_vertex_struct_meta, }; use vek::*; @@ -28,6 +22,7 @@ gfx_defines! { locals: gfx::ConstantBuffer = "u_locals", globals: gfx::ConstantBuffer = "u_globals", + map: gfx::TextureSampler<[f32; 4]> = "t_map", noise: gfx::TextureSampler = "t_noise", @@ -45,9 +40,7 @@ impl Vertex { } impl Locals { - pub fn default() -> Self { - Self { nul: [0.0; 4] } - } + pub fn default() -> Self { Self { nul: [0.0; 4] } } } pub struct LodTerrainPipeline; diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 8081d42792..0939adc730 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -9,7 +9,7 @@ use super::{ Shadow, }, texture::Texture, - AaMode, CloudMode, FluidMode, Pipeline, RenderError, + AaMode, CloudMode, FilterMethod, FluidMode, Pipeline, RenderError, WrapMode, }; use common::assets::{self, watch::ReloadIndicator}; use gfx::{ @@ -419,8 +419,8 @@ impl Renderer { pub fn create_texture( &mut self, image: &image::DynamicImage, - filter_method: Option, - wrap_mode: Option, + filter_method: Option, + wrap_mode: Option, ) -> Result { Texture::new(&mut self.factory, image, filter_method, wrap_mode) } @@ -646,12 +646,14 @@ impl Renderer { ); } - /// Queue the rendering of the provided LoD terrain model in the upcoming frame. + /// Queue the rendering of the provided LoD terrain model in the upcoming + /// frame. pub fn render_lod_terrain( &mut self, model: &Model, globals: &Consts, locals: &Consts, + map: &Texture, ) { self.encoder.draw( &gfx::Slice { @@ -667,6 +669,7 @@ impl Renderer { locals: locals.buf.clone(), globals: globals.buf.clone(), noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), + map: (map.srv.clone(), map.sampler.clone()), tgt_color: self.tgt_color_view.clone(), tgt_depth: self.tgt_depth_view.clone(), }, diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index fc9fa8169d..10b7b3eae1 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -1,26 +1,31 @@ use crate::render::{ pipelines::lod_terrain::{Locals, Vertex}, - Consts, Globals, LodTerrainPipeline, Mesh, Model, Quad, Renderer, + Consts, FilterMethod, Globals, LodTerrainPipeline, Mesh, Model, Quad, Renderer, Texture, }; +use client::Client; use vek::*; pub struct Lod { model: Model, locals: Consts, + map: Texture, } impl Lod { - pub fn new(renderer: &mut Renderer) -> Self { + pub fn new(renderer: &mut Renderer, client: &Client) -> Self { Self { model: renderer - .create_model(&create_lod_terrain_mesh(175)) + .create_model(&create_lod_terrain_mesh(300)) //175 .unwrap(), locals: renderer.create_consts(&[Locals::default()]).unwrap(), + map: renderer + .create_texture(&client.world_map.0, Some(FilterMethod::Bilinear), None) + .expect("Failed to generate map texture"), } } pub fn render(&self, renderer: &mut Renderer, globals: &Consts) { - renderer.render_lod_terrain(&self.model, globals, &self.locals); + renderer.render_lod_terrain(&self.model, globals, &self.locals, &self.map); } } diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index ac6845772c..3038236c4b 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -6,8 +6,8 @@ pub mod terrain; use self::{ camera::{Camera, CameraMode}, figure::FigureMgr, - music::MusicMgr, lod::Lod, + music::MusicMgr, terrain::Terrain, }; use crate::{ @@ -67,7 +67,7 @@ pub struct Scene { impl Scene { /// Create a new `Scene` with default parameters. - pub fn new(renderer: &mut Renderer) -> Self { + pub fn new(renderer: &mut Renderer, client: &Client) -> Self { let resolution = renderer.get_resolution().map(|e| e as f32); Self { @@ -91,7 +91,7 @@ impl Scene { .unwrap(), }, terrain: Terrain::new(renderer), - lod: Lod::new(renderer), + lod: Lod::new(renderer, client), loaded_distance: 0.0, select_pos: None, diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index f4eae9911e..80e98e3a37 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -1240,7 +1240,8 @@ impl Terrain { // a sample of the terrain that includes both the chunk we want and // its neighbours. let volume = match client.state().terrain().sample(aabr) { - Ok(sample) => sample, // TODO: Ensure that all of the chunk's neighbours still exist to avoid buggy shadow borders + Ok(sample) => sample, /* TODO: Ensure that all of the chunk's neighbours still + * exist to avoid buggy shadow borders */ // Either this chunk or its neighbours doesn't yet exist, so we keep it in the // queue to be processed at a later date when we have its neighbours. Err(VolGrid2dError::NoSuchChunk) => return, diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index a45ab1ad0f..16ff5f1742 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -39,7 +39,7 @@ impl SessionState { pub fn new(global_state: &mut GlobalState, client: Rc>) -> Self { // Create a scene for this session. The scene handles visible elements of the // game world. - let mut scene = Scene::new(global_state.window.renderer_mut()); + let mut scene = Scene::new(global_state.window.renderer_mut(), &*client.borrow()); scene .camera_mut() .set_fov_deg(global_state.settings.graphics.fov); diff --git a/world/src/sim/map.rs b/world/src/sim/map.rs index 0707abd0d6..aa812ab478 100644 --- a/world/src/sim/map.rs +++ b/world/src/sim/map.rs @@ -242,7 +242,7 @@ impl MapConfig { let water_color_factor = 2.0; let g_water = 32.0 * water_color_factor; let b_water = 64.0 * water_color_factor; - let rgba = match (river_kind, (is_water, true_alt >= true_sea_level)) { + let rgb = match (river_kind, (is_water, true_alt >= true_sea_level)) { (_, (false, _)) | (None, (_, true)) => { let (r, g, b) = ( (if is_shaded { alt } else { alt } @@ -270,20 +270,17 @@ impl MapConfig { (r * light * 255.0) as u8, (g * light * 255.0) as u8, (b * light * 255.0) as u8, - 255, ) }, (Some(RiverKind::Ocean), _) => ( 0, ((g_water - water_depth * g_water) * 1.0) as u8, ((b_water - water_depth * b_water) * 1.0) as u8, - 255, ), (Some(RiverKind::River { .. }), _) => ( 0, g_water as u8 + (alt * (127.0 - g_water)) as u8, b_water as u8 + (alt * (255.0 - b_water)) as u8, - 255, ), (None, _) | (Some(RiverKind::Lake { .. }), _) => ( 0, @@ -291,10 +288,11 @@ impl MapConfig { as u8, (((b_water + water_alt * (255.0 - b_water)) + (-water_depth * b_water)) * 1.0) as u8, - 255, ), }; + let rgba = (rgb.0, rgb.1, rgb.2, (255.0 * alt) as u8); + write_pixel(Vec2::new(i, j), rgba); });