diff --git a/assets/voxygen/shaders/lod-terrain-vert.glsl b/assets/voxygen/shaders/lod-terrain-vert.glsl new file mode 100644 index 0000000000..0f7690972b --- /dev/null +++ b/assets/voxygen/shaders/lod-terrain-vert.glsl @@ -0,0 +1,38 @@ +#version 330 core + +#include +#include + +uniform sampler2D t_noise; + +in vec2 v_pos; + +layout (std140) +uniform u_locals { + vec4 nul; +}; + +out vec3 f_pos; +out vec3 f_norm; +out vec3 f_col; +out float f_light; + +void main() { + vec2 pos = v_pos * 1000.0; + + f_pos = vec3(pos, texture(t_noise, pos * 0.001).x * 1000.0); + + //f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0); + + f_col = vec3(0.5, 1.0, 0.3); + + f_light = 1.0; + + f_norm = vec3(0, 0, 1); + + gl_Position = + proj_mat * + view_mat * + vec4(f_pos, 1); + gl_Position.z = 1.0 / (1.0 - gl_Position.z - 10.0); +} diff --git a/assets/voxygen/shaders/terrain-frag.glsl b/assets/voxygen/shaders/terrain-frag.glsl index 069cc01f11..b6a17e48f2 100644 --- a/assets/voxygen/shaders/terrain-frag.glsl +++ b/assets/voxygen/shaders/terrain-frag.glsl @@ -3,16 +3,10 @@ #include in vec3 f_pos; -flat in uint f_pos_norm; +in vec3 f_norm; in vec3 f_col; in float f_light; -layout (std140) -uniform u_locals { - vec3 model_offs; - float load_time; -}; - out vec4 tgt_color; #include diff --git a/assets/voxygen/shaders/terrain-vert.glsl b/assets/voxygen/shaders/terrain-vert.glsl index 52b21fad54..0c08908a76 100644 --- a/assets/voxygen/shaders/terrain-vert.glsl +++ b/assets/voxygen/shaders/terrain-vert.glsl @@ -13,7 +13,7 @@ uniform u_locals { }; out vec3 f_pos; -flat out uint f_pos_norm; +out vec3 f_norm; out vec3 f_col; out float f_light; @@ -27,7 +27,15 @@ void main() { f_light = float(v_col_light & 0xFFu) / 255.0; - f_pos_norm = v_pos_norm; + // 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)); + + // TODO: last 3 bits in v_pos_norm should be a number between 0 and 5, rather than 0-2 and a direction. + uint norm_axis = (v_pos_norm >> 30) & 0x3u; + // Increase array access by 3 to access positive values + uint norm_dir = ((v_pos_norm >> 29) & 0x1u) * 3u; + // Use an array to avoid conditional branching + f_norm = normals[norm_axis + norm_dir]; gl_Position = all_mat * diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index e848b80ed0..78c3758dc9 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -18,6 +18,7 @@ pub use self::{ pipelines::{ figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals}, fluid::FluidPipeline, + lod_terrain::{Locals as LodTerrainLocals, LodTerrainPipeline}, postprocess::{ create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline, }, diff --git a/voxygen/src/render/pipelines/lod_terrain.rs b/voxygen/src/render/pipelines/lod_terrain.rs new file mode 100644 index 0000000000..334a1295b7 --- /dev/null +++ b/voxygen/src/render/pipelines/lod_terrain.rs @@ -0,0 +1,57 @@ +use super::{ + super::{Pipeline, TgtColorFmt, TgtDepthFmt}, + Globals, +}; +use gfx::{ + self, + gfx_constant_struct_meta, + // Macros + gfx_defines, + gfx_impl_struct_meta, + gfx_pipeline, + gfx_pipeline_inner, + gfx_vertex_struct_meta, +}; +use vek::*; + +gfx_defines! { + vertex Vertex { + pos: [f32; 2] = "v_pos", + } + + constant Locals { + nul: [f32; 4] = "nul", + } + + pipeline pipe { + vbuf: gfx::VertexBuffer = (), + + locals: gfx::ConstantBuffer = "u_locals", + globals: gfx::ConstantBuffer = "u_globals", + + noise: gfx::TextureSampler = "t_noise", + + tgt_color: gfx::RenderTarget = "tgt_color", + tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, + } +} + +impl Vertex { + pub fn new(pos: Vec2) -> Self { + Self { + pos: pos.into_array(), + } + } +} + +impl Locals { + pub fn default() -> Self { + Self { nul: [0.0; 4] } + } +} + +pub struct LodTerrainPipeline; + +impl Pipeline for LodTerrainPipeline { + type Vertex = Vertex; +} diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index 4e6fd5b282..974c49b7c7 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -1,5 +1,6 @@ pub mod figure; pub mod fluid; +pub mod lod_terrain; pub mod postprocess; pub mod skybox; pub mod sprite; diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 3cf3ff7fcb..3d6c5d0bc3 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -4,7 +4,10 @@ use super::{ instances::Instances, mesh::Mesh, model::{DynamicModel, Model}, - pipelines::{figure, fluid, postprocess, skybox, sprite, terrain, ui, Globals, Light, Shadow}, + pipelines::{ + figure, fluid, lod_terrain, postprocess, skybox, sprite, terrain, ui, Globals, Light, + Shadow, + }, texture::Texture, AaMode, CloudMode, FluidMode, Pipeline, RenderError, }; @@ -69,6 +72,7 @@ pub struct Renderer { fluid_pipeline: GfxPipeline>, sprite_pipeline: GfxPipeline>, ui_pipeline: GfxPipeline>, + lod_terrain_pipeline: GfxPipeline>, postprocess_pipeline: GfxPipeline>, shader_reload_indicator: ReloadIndicator, @@ -101,6 +105,7 @@ impl Renderer { fluid_pipeline, sprite_pipeline, ui_pipeline, + lod_terrain_pipeline, postprocess_pipeline, ) = create_pipelines( &mut factory, @@ -143,6 +148,7 @@ impl Renderer { fluid_pipeline, sprite_pipeline, ui_pipeline, + lod_terrain_pipeline, postprocess_pipeline, shader_reload_indicator, @@ -335,6 +341,7 @@ impl Renderer { fluid_pipeline, sprite_pipeline, ui_pipeline, + lod_terrain_pipeline, postprocess_pipeline, )) => { self.skybox_pipeline = skybox_pipeline; @@ -343,6 +350,7 @@ impl Renderer { self.fluid_pipeline = fluid_pipeline; self.sprite_pipeline = sprite_pipeline; self.ui_pipeline = ui_pipeline; + self.lod_terrain_pipeline = lod_terrain_pipeline; self.postprocess_pipeline = postprocess_pipeline; }, Err(e) => error!( @@ -638,6 +646,33 @@ impl Renderer { ); } + /// 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, + ) { + self.encoder.draw( + &gfx::Slice { + start: model.vertex_range().start, + end: model.vertex_range().end, + base_vertex: 0, + instances: None, + buffer: gfx::IndexBuffer::Auto, + }, + &self.lod_terrain_pipeline.pso, + &lod_terrain::pipe::Data { + vbuf: model.vbuf.clone(), + locals: locals.buf.clone(), + globals: globals.buf.clone(), + noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.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, @@ -720,10 +755,13 @@ fn create_pipelines( GfxPipeline>, GfxPipeline>, GfxPipeline>, + GfxPipeline>, GfxPipeline>, ), RenderError, > { + dbg!("start"); + let globals = assets::load_watched::("voxygen.shaders.include.globals", shader_reload_indicator) .unwrap(); @@ -851,6 +889,23 @@ fn create_pipelines( gfx::state::CullFace::Back, )?; + // Construct a pipeline for rendering terrain + let lod_terrain_pipeline = create_pipeline( + factory, + lod_terrain::pipe::new(), + &assets::load_watched::( + "voxygen.shaders.lod-terrain-vert", + shader_reload_indicator, + ) + .unwrap(), + &assets::load_watched::("voxygen.shaders.terrain-frag", shader_reload_indicator) + .unwrap(), + &include_ctx, + gfx::state::CullFace::Back, + )?; + + dbg!("created lod pipeline"); + // Construct a pipeline for rendering our post-processing let postprocess_pipeline = create_pipeline( factory, @@ -869,6 +924,8 @@ fn create_pipelines( gfx::state::CullFace::Back, )?; + dbg!("created pipelines"); + Ok(( skybox_pipeline, figure_pipeline, @@ -876,6 +933,7 @@ fn create_pipelines( fluid_pipeline, sprite_pipeline, ui_pipeline, + lod_terrain_pipeline, postprocess_pipeline, )) } @@ -889,12 +947,23 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>( ctx: &IncludeContext, cull_face: gfx::state::CullFace, ) -> Result, RenderError> { + dbg!("Expanding context..."); + let vs = ctx.expand(vs)?; + + dbg!("expanded vs!"); + let fs = ctx.expand(fs)?; + dbg!("expanded fs!"); + + dbg!("vs = {}, fs = {}", vs.as_bytes().len(), fs.as_bytes().len()); + let program = factory.link_program(vs.as_bytes(), fs.as_bytes())?; - Ok(GfxPipeline { + dbg!("linked"); + + let result = Ok(GfxPipeline { pso: factory.create_pipeline_from_program( &program, gfx::Primitive::TriangleList, @@ -907,5 +976,9 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>( }, pipe, )?, - }) + }); + + dbg!("finished pipeline"); + + result } diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs new file mode 100644 index 0000000000..16e989bbe8 --- /dev/null +++ b/voxygen/src/scene/lod.rs @@ -0,0 +1,44 @@ +use crate::render::{ + pipelines::lod_terrain::{Locals, Vertex}, + Consts, Globals, LodTerrainPipeline, Mesh, Model, Quad, Renderer, +}; +use vek::*; + +pub struct Lod { + model: Model, + locals: Consts, +} + +impl Lod { + pub fn new(renderer: &mut Renderer) -> Self { + Self { + model: renderer + .create_model(&create_lod_terrain_mesh(256)) + .unwrap(), + locals: renderer.create_consts(&[Locals::default()]).unwrap(), + } + } + + pub fn render(&self, renderer: &mut Renderer, globals: &Consts) { + renderer.render_lod_terrain(&self.model, globals, &self.locals); + } +} + +fn create_lod_terrain_mesh(detail: usize) -> Mesh { + let transform = |x| (2.0 * x as f32) / detail as f32 - 2.0; + + let mut mesh = Mesh::new(); + + for x in 0..detail { + for y in 0..detail { + mesh.push_quad(Quad::new( + Vertex::new(Vec2::new(x + 0, y + 0).map(transform)), + Vertex::new(Vec2::new(x + 1, y + 0).map(transform)), + Vertex::new(Vec2::new(x + 1, y + 1).map(transform)), + Vertex::new(Vec2::new(x + 0, y + 1).map(transform)), + )); + } + } + + mesh +} diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 6653a75e8e..3a8a5a01fc 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -54,6 +54,7 @@ pub struct Scene { skybox: Skybox, postprocess: PostProcess, terrain: Terrain, + lod: Lod, loaded_distance: f32, select_pos: Option>, @@ -88,6 +89,7 @@ impl Scene { .unwrap(), }, terrain: Terrain::new(renderer), + lod: Lod::new(renderer), loaded_distance: 0.0, select_pos: None, @@ -340,6 +342,7 @@ impl Scene { &self.shadows, self.camera.get_focus_pos(), ); + self.lod.render(renderer, &self.globals); // Render the skybox. renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);