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

View File

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

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

View File

@ -18,20 +18,21 @@ impl From<gfx::PipelineStateError<String>> for RenderError {
impl From<gfx::PipelineStateError<&str>> 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<gfx::PipelineStateError<&str>> 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),
}

View File

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

View File

@ -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<Locals> = "u_locals",
globals: gfx::ConstantBuffer<Globals> = "u_globals",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
noise: gfx::TextureSampler<f32> = "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;

View File

@ -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<gfx::texture::FilterMethod>,
wrap_mode: Option<gfx::texture::WrapMode>,
filter_method: Option<FilterMethod>,
wrap_mode: Option<WrapMode>,
) -> Result<Texture, RenderError> {
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<lod_terrain::LodTerrainPipeline>,
globals: &Consts<Globals>,
locals: &Consts<lod_terrain::Locals>,
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(),
},

View File

@ -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<LodTerrainPipeline>,
locals: Consts<Locals>,
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<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::{
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,

View File

@ -1240,7 +1240,8 @@ impl<V: RectRasterableVol> Terrain<V> {
// 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,

View File

@ -39,7 +39,7 @@ impl SessionState {
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
// 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);

View File

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