Use world map as LoD source

This commit is contained in:
Joshua Barretto 2020-02-21 13:48:40 +00:00
parent dbf650f504
commit 2400786c13
12 changed files with 67 additions and 44 deletions

View File

@ -1,6 +1,15 @@
#include <random.glsl> #include <random.glsl>
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) { float alt_at(vec2 pos) {
return texture(t_map, pos_to_uv(pos)).a * (1500.0);
return 0.0 return 0.0
+ pow(texture(t_noise, pos * 0.00005).x * 1.4, 3.0) * 1000.0 + pow(texture(t_noise, pos * 0.00005).x * 1.4, 3.0) * 1000.0
+ texture(t_noise, pos * 0.001).x * 100.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); 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) { vec3 lod_pos(vec2 v_pos) {
vec2 hpos = focus_pos.xy + splay(v_pos, 5.0) * 1000000.0; 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) { vec3 lod_norm(vec2 pos) {
@ -25,11 +44,13 @@ vec3 lod_norm(vec2 pos) {
return normalize(vec3( return normalize(vec3(
(alt00 - alt10) / 100, (alt00 - alt10) / 100,
(alt00 - alt01) / 100, (alt00 - alt01) / 100,
100 / slope 100 / (slope + 0.00001) // Avoid NaN
)); ));
} }
vec3 lod_col(vec2 pos) { vec3 lod_col(vec2 pos) {
return texture(t_map, pos_to_uv(pos)).rgb;
vec3 warmth = mix( vec3 warmth = mix(
vec3(0.05, 0.4, 0.1), vec3(0.05, 0.4, 0.1),
vec3(0.5, 0.4, 0.0), vec3(0.5, 0.4, 0.0),

View File

@ -15,9 +15,9 @@ out vec3 f_pos;
out float f_light; out float f_light;
void main() { 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; f_light = 1.0;

View File

@ -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 = 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 *= 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; f_col = vec3((uvec3(v_col_light) >> uvec3(8, 16, 24)) & uvec3(0xFFu)) / 255.0;

View File

@ -18,20 +18,21 @@ impl From<gfx::PipelineStateError<String>> for RenderError {
impl From<gfx::PipelineStateError<&str>> for RenderError { impl From<gfx::PipelineStateError<&str>> for RenderError {
fn from(err: gfx::PipelineStateError<&str>) -> Self { 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 { match err {
gfx::PipelineStateError::DescriptorInit(err) => { gfx::PipelineStateError::DescriptorInit(err) => {
gfx::PipelineStateError::DescriptorInit(match err { gfx::PipelineStateError::DescriptorInit(match err {
gfx::pso::InitError::VertexImport(s, x) => { gfx::pso::InitError::VertexImport(s, x) => {
gfx::pso::InitError::VertexImport(s.to_string(), x) gfx::pso::InitError::VertexImport(s.to_string(), x)
} },
gfx::pso::InitError::ConstantBuffer(s, x) => { gfx::pso::InitError::ConstantBuffer(s, x) => {
gfx::pso::InitError::ConstantBuffer( gfx::pso::InitError::ConstantBuffer(
s.to_string(), s.to_string(),
x.map(|x| match x { x.map(|x| match x {
gfx::pso::ElementError::NotFound(s) => { gfx::pso::ElementError::NotFound(s) => {
gfx::pso::ElementError::NotFound(s.to_string()) gfx::pso::ElementError::NotFound(s.to_string())
} },
gfx::pso::ElementError::Offset { gfx::pso::ElementError::Offset {
name, name,
shader_offset, shader_offset,
@ -52,24 +53,24 @@ impl From<gfx::PipelineStateError<&str>> for RenderError {
}, },
}), }),
) )
} },
gfx::pso::InitError::GlobalConstant(s, x) => { gfx::pso::InitError::GlobalConstant(s, x) => {
gfx::pso::InitError::GlobalConstant(s.to_string(), x) gfx::pso::InitError::GlobalConstant(s.to_string(), x)
} },
gfx::pso::InitError::ResourceView(s, x) => { gfx::pso::InitError::ResourceView(s, x) => {
gfx::pso::InitError::ResourceView(s.to_string(), x) gfx::pso::InitError::ResourceView(s.to_string(), x)
} },
gfx::pso::InitError::UnorderedView(s, x) => { gfx::pso::InitError::UnorderedView(s, x) => {
gfx::pso::InitError::UnorderedView(s.to_string(), x) gfx::pso::InitError::UnorderedView(s.to_string(), x)
} },
gfx::pso::InitError::Sampler(s, x) => { gfx::pso::InitError::Sampler(s, x) => {
gfx::pso::InitError::Sampler(s.to_string(), x) gfx::pso::InitError::Sampler(s.to_string(), x)
} },
gfx::pso::InitError::PixelExport(s, x) => { gfx::pso::InitError::PixelExport(s, x) => {
gfx::pso::InitError::PixelExport(s.to_string(), x) gfx::pso::InitError::PixelExport(s.to_string(), x)
} },
}) })
} },
gfx::PipelineStateError::Program(p) => gfx::PipelineStateError::Program(p), gfx::PipelineStateError::Program(p) => gfx::PipelineStateError::Program(p),
gfx::PipelineStateError::DeviceCreate(c) => gfx::PipelineStateError::DeviceCreate(c), gfx::PipelineStateError::DeviceCreate(c) => gfx::PipelineStateError::DeviceCreate(c),
} }

View File

@ -34,6 +34,7 @@ pub use self::{
renderer::{Renderer, TgtColorFmt, TgtDepthFmt, WinColorFmt, WinDepthFmt}, renderer::{Renderer, TgtColorFmt, TgtDepthFmt, WinColorFmt, WinDepthFmt},
texture::Texture, texture::Texture,
}; };
pub use gfx::texture::{FilterMethod, WrapMode};
#[cfg(feature = "gl")] #[cfg(feature = "gl")]
use gfx_device_gl as gfx_backend; use gfx_device_gl as gfx_backend;

View File

@ -3,14 +3,8 @@ use super::{
Globals, Globals,
}; };
use gfx::{ use gfx::{
self, self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline,
gfx_constant_struct_meta, gfx_pipeline_inner, gfx_vertex_struct_meta,
// Macros
gfx_defines,
gfx_impl_struct_meta,
gfx_pipeline,
gfx_pipeline_inner,
gfx_vertex_struct_meta,
}; };
use vek::*; use vek::*;
@ -28,6 +22,7 @@ gfx_defines! {
locals: gfx::ConstantBuffer<Locals> = "u_locals", locals: gfx::ConstantBuffer<Locals> = "u_locals",
globals: gfx::ConstantBuffer<Globals> = "u_globals", globals: gfx::ConstantBuffer<Globals> = "u_globals",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
noise: gfx::TextureSampler<f32> = "t_noise", noise: gfx::TextureSampler<f32> = "t_noise",
@ -45,9 +40,7 @@ impl Vertex {
} }
impl Locals { impl Locals {
pub fn default() -> Self { pub fn default() -> Self { Self { nul: [0.0; 4] } }
Self { nul: [0.0; 4] }
}
} }
pub struct LodTerrainPipeline; pub struct LodTerrainPipeline;

View File

@ -9,7 +9,7 @@ use super::{
Shadow, Shadow,
}, },
texture::Texture, texture::Texture,
AaMode, CloudMode, FluidMode, Pipeline, RenderError, AaMode, CloudMode, FilterMethod, FluidMode, Pipeline, RenderError, WrapMode,
}; };
use common::assets::{self, watch::ReloadIndicator}; use common::assets::{self, watch::ReloadIndicator};
use gfx::{ use gfx::{
@ -419,8 +419,8 @@ impl Renderer {
pub fn create_texture( pub fn create_texture(
&mut self, &mut self,
image: &image::DynamicImage, image: &image::DynamicImage,
filter_method: Option<gfx::texture::FilterMethod>, filter_method: Option<FilterMethod>,
wrap_mode: Option<gfx::texture::WrapMode>, wrap_mode: Option<WrapMode>,
) -> Result<Texture, RenderError> { ) -> Result<Texture, RenderError> {
Texture::new(&mut self.factory, image, filter_method, wrap_mode) 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( pub fn render_lod_terrain(
&mut self, &mut self,
model: &Model<lod_terrain::LodTerrainPipeline>, model: &Model<lod_terrain::LodTerrainPipeline>,
globals: &Consts<Globals>, globals: &Consts<Globals>,
locals: &Consts<lod_terrain::Locals>, locals: &Consts<lod_terrain::Locals>,
map: &Texture,
) { ) {
self.encoder.draw( self.encoder.draw(
&gfx::Slice { &gfx::Slice {
@ -667,6 +669,7 @@ impl Renderer {
locals: locals.buf.clone(), locals: locals.buf.clone(),
globals: globals.buf.clone(), globals: globals.buf.clone(),
noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.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_color: self.tgt_color_view.clone(),
tgt_depth: self.tgt_depth_view.clone(), tgt_depth: self.tgt_depth_view.clone(),
}, },

View File

@ -1,26 +1,31 @@
use crate::render::{ use crate::render::{
pipelines::lod_terrain::{Locals, Vertex}, 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::*; use vek::*;
pub struct Lod { pub struct Lod {
model: Model<LodTerrainPipeline>, model: Model<LodTerrainPipeline>,
locals: Consts<Locals>, locals: Consts<Locals>,
map: Texture,
} }
impl Lod { impl Lod {
pub fn new(renderer: &mut Renderer) -> Self { pub fn new(renderer: &mut Renderer, client: &Client) -> Self {
Self { Self {
model: renderer model: renderer
.create_model(&create_lod_terrain_mesh(175)) .create_model(&create_lod_terrain_mesh(300)) //175
.unwrap(), .unwrap(),
locals: renderer.create_consts(&[Locals::default()]).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<Globals>) { pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
renderer.render_lod_terrain(&self.model, globals, &self.locals); renderer.render_lod_terrain(&self.model, globals, &self.locals, &self.map);
} }
} }

View File

@ -6,8 +6,8 @@ pub mod terrain;
use self::{ use self::{
camera::{Camera, CameraMode}, camera::{Camera, CameraMode},
figure::FigureMgr, figure::FigureMgr,
music::MusicMgr,
lod::Lod, lod::Lod,
music::MusicMgr,
terrain::Terrain, terrain::Terrain,
}; };
use crate::{ use crate::{
@ -67,7 +67,7 @@ pub struct Scene {
impl Scene { impl Scene {
/// Create a new `Scene` with default parameters. /// 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); let resolution = renderer.get_resolution().map(|e| e as f32);
Self { Self {
@ -91,7 +91,7 @@ impl Scene {
.unwrap(), .unwrap(),
}, },
terrain: Terrain::new(renderer), terrain: Terrain::new(renderer),
lod: Lod::new(renderer), lod: Lod::new(renderer, client),
loaded_distance: 0.0, loaded_distance: 0.0,
select_pos: None, select_pos: None,

View File

@ -1240,7 +1240,8 @@ impl<V: RectRasterableVol> Terrain<V> {
// a sample of the terrain that includes both the chunk we want and // a sample of the terrain that includes both the chunk we want and
// its neighbours. // its neighbours.
let volume = match client.state().terrain().sample(aabr) { 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 // 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. // queue to be processed at a later date when we have its neighbours.
Err(VolGrid2dError::NoSuchChunk) => return, Err(VolGrid2dError::NoSuchChunk) => return,

View File

@ -39,7 +39,7 @@ impl SessionState {
pub fn new(global_state: &mut GlobalState, client: Rc<RefCell<Client>>) -> Self { pub fn new(global_state: &mut GlobalState, client: Rc<RefCell<Client>>) -> Self {
// Create a scene for this session. The scene handles visible elements of the // Create a scene for this session. The scene handles visible elements of the
// game world. // 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 scene
.camera_mut() .camera_mut()
.set_fov_deg(global_state.settings.graphics.fov); .set_fov_deg(global_state.settings.graphics.fov);

View File

@ -242,7 +242,7 @@ impl MapConfig {
let water_color_factor = 2.0; let water_color_factor = 2.0;
let g_water = 32.0 * water_color_factor; let g_water = 32.0 * water_color_factor;
let b_water = 64.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)) => { (_, (false, _)) | (None, (_, true)) => {
let (r, g, b) = ( let (r, g, b) = (
(if is_shaded { alt } else { alt } (if is_shaded { alt } else { alt }
@ -270,20 +270,17 @@ impl MapConfig {
(r * light * 255.0) as u8, (r * light * 255.0) as u8,
(g * light * 255.0) as u8, (g * light * 255.0) as u8,
(b * light * 255.0) as u8, (b * light * 255.0) as u8,
255,
) )
}, },
(Some(RiverKind::Ocean), _) => ( (Some(RiverKind::Ocean), _) => (
0, 0,
((g_water - water_depth * g_water) * 1.0) as u8, ((g_water - water_depth * g_water) * 1.0) as u8,
((b_water - water_depth * b_water) * 1.0) as u8, ((b_water - water_depth * b_water) * 1.0) as u8,
255,
), ),
(Some(RiverKind::River { .. }), _) => ( (Some(RiverKind::River { .. }), _) => (
0, 0,
g_water as u8 + (alt * (127.0 - g_water)) as u8, g_water as u8 + (alt * (127.0 - g_water)) as u8,
b_water as u8 + (alt * (255.0 - b_water)) as u8, b_water as u8 + (alt * (255.0 - b_water)) as u8,
255,
), ),
(None, _) | (Some(RiverKind::Lake { .. }), _) => ( (None, _) | (Some(RiverKind::Lake { .. }), _) => (
0, 0,
@ -291,10 +288,11 @@ impl MapConfig {
as u8, as u8,
(((b_water + water_alt * (255.0 - b_water)) + (-water_depth * b_water)) (((b_water + water_alt * (255.0 - b_water)) + (-water_depth * b_water))
* 1.0) as u8, * 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); write_pixel(Vec2::new(i, j), rgba);
}); });