From 63d1b2bb2292898d59fb4f4e502201103dfeb86f Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 21 Nov 2019 20:57:46 +0000 Subject: [PATCH] Working LoD shader --- assets/voxygen/shaders/include/light.glsl | 9 +-- assets/voxygen/shaders/include/lod.glsl | 46 ++++++++++++ assets/voxygen/shaders/include/random.glsl | 2 + assets/voxygen/shaders/include/sky.glsl | 79 +++++++++++++++++++- assets/voxygen/shaders/lod-terrain-frag.glsl | 28 +++++++ assets/voxygen/shaders/lod-terrain-vert.glsl | 15 +--- assets/voxygen/shaders/terrain-frag.glsl | 2 +- voxygen/src/render/error.rs | 55 +++++++++++++- voxygen/src/render/renderer.rs | 30 +++----- voxygen/src/scene/lod.rs | 4 +- 10 files changed, 223 insertions(+), 47 deletions(-) create mode 100644 assets/voxygen/shaders/include/lod.glsl create mode 100644 assets/voxygen/shaders/lod-terrain-frag.glsl diff --git a/assets/voxygen/shaders/include/light.glsl b/assets/voxygen/shaders/include/light.glsl index e937535b78..45a5ad6904 100644 --- a/assets/voxygen/shaders/include/light.glsl +++ b/assets/voxygen/shaders/include/light.glsl @@ -1,3 +1,5 @@ +#include + struct Light { vec4 light_pos; vec4 light_col; @@ -17,13 +19,6 @@ uniform u_shadows { Shadow shadows[24]; }; -#include - -vec3 illuminate(vec3 color, vec3 light, vec3 diffuse, vec3 ambience) { - float avg_col = (color.r + color.g + color.b) / 3.0; - return ((color - avg_col) * light + (diffuse + ambience) * avg_col) * (diffuse + ambience); -} - float attenuation_strength(vec3 rpos) { return 1.0 / (rpos.x * rpos.x + rpos.y * rpos.y + rpos.z * rpos.z); } diff --git a/assets/voxygen/shaders/include/lod.glsl b/assets/voxygen/shaders/include/lod.glsl new file mode 100644 index 0000000000..41549a79ab --- /dev/null +++ b/assets/voxygen/shaders/include/lod.glsl @@ -0,0 +1,46 @@ +#include + +float alt_at(vec2 pos) { + 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 + + texture(t_noise, pos * 0.003).x * 30.0; +} + +vec2 splay(vec2 pos, float e) { + return pos * pow(length(pos), e); +} + +vec3 lod_pos(vec2 v_pos) { + vec2 hpos = focus_pos.xy + splay(v_pos, 3.0) * 20000.0; + return vec3(hpos, alt_at(hpos)); +} + +vec3 lod_norm(vec2 pos) { + float alt00 = alt_at(pos); + float alt10 = alt_at(pos + vec2(100, 0)); + float alt01 = alt_at(pos + vec2(0, 100)); + float slope = abs(alt00 - alt10) + abs(alt00 - alt01); + + return normalize(vec3( + (alt00 - alt10) / 100, + (alt00 - alt01) / 100, + 100 / slope + )); +} + +vec3 lod_col(vec2 pos) { + vec3 warmth = mix( + vec3(0.05, 0.4, 0.15), + vec3(0.5, 0.4, 0.0), + (texture(t_noise, pos * 0.0002).x - 0.5) * 2.0 + 0.5 + ); + + vec3 color = mix( + warmth, + vec3(0.5, 0.5, 0.5), + alt_at(pos) / 1200.0 + ); + + return color; +} diff --git a/assets/voxygen/shaders/include/random.glsl b/assets/voxygen/shaders/include/random.glsl index b1f0e18a21..694758bb69 100644 --- a/assets/voxygen/shaders/include/random.glsl +++ b/assets/voxygen/shaders/include/random.glsl @@ -1,3 +1,5 @@ +uniform sampler2D t_noise; + float hash(vec4 p) { p = fract( p*0.3183099+.1); p *= 17.0; diff --git a/assets/voxygen/shaders/include/sky.glsl b/assets/voxygen/shaders/include/sky.glsl index 5b3869c8ac..39bb8c920f 100644 --- a/assets/voxygen/shaders/include/sky.glsl +++ b/assets/voxygen/shaders/include/sky.glsl @@ -1,7 +1,6 @@ #include #include - const float PI = 3.141592; const vec3 SKY_DAY_TOP = vec3(0.1, 0.2, 0.9); @@ -105,6 +104,79 @@ float is_star_at(vec3 dir) { return 0.0; } +const float CLOUD_AVG_HEIGHT = 1025.0; +const float CLOUD_HEIGHT_MIN = CLOUD_AVG_HEIGHT - 35.0; +const float CLOUD_HEIGHT_MAX = CLOUD_AVG_HEIGHT + 35.0; +const float CLOUD_THRESHOLD = 0.3; +const float CLOUD_SCALE = 1.0; +const float CLOUD_DENSITY = 100.0; + +float vsum(vec3 v) { + return v.x + v.y + v.z; +} + +vec2 cloud_at(vec3 pos) { + float tick_offs = 0.0 + + texture(t_noise, pos.xy * 0.0001 + tick.x * 0.001).x * 1.0 + + texture(t_noise, pos.xy * 0.000003).x * 5.0; + + float value = ( + 0.0 + + texture(t_noise, pos.xy / CLOUD_SCALE * 0.0003 + tick_offs).x + + texture(t_noise, pos.xy / CLOUD_SCALE * 0.0009 - tick_offs).x * 0.5 + + texture(t_noise, pos.xy / CLOUD_SCALE * 0.0025 - tick.x * 0.01).x * 0.25 + + texture(t_noise, pos.xy / CLOUD_SCALE * 0.008 + tick.x * 0.02).x * 0.1 + ) / 3.0; + + float density = max((value - CLOUD_THRESHOLD) - abs(pos.z - CLOUD_AVG_HEIGHT) / 500.0, 0.0) * CLOUD_DENSITY; + + float shade = ((pos.z - CLOUD_AVG_HEIGHT) / (CLOUD_AVG_HEIGHT - CLOUD_HEIGHT_MIN) + 0.5); + + return vec2(shade, density / (1.0 + vsum(abs(pos - cam_pos.xyz)) / 5000)); +} + +vec4 get_cloud_color(vec3 dir, vec3 origin, float time_of_day, float max_dist, float quality) { + + const float INCR = 0.06; + + float mind = (CLOUD_HEIGHT_MIN - origin.z) / dir.z; + float maxd = (CLOUD_HEIGHT_MAX - origin.z) / dir.z; + + float start = max(min(mind, maxd), 0.0); + float delta = min(abs(mind - maxd), max_dist); + + bool do_cast = true; + if (mind < 0.0 && maxd < 0.0) { + do_cast = false; + } + + float incr = INCR; + + float fuzz = sin(texture(t_noise, dir.xz * 100000.0).x * 100.0) * incr * delta; + + float cloud_shade = 1.0; + float passthrough = 1.0; + if (do_cast) { + for (float d = 0.0; d < 1.0; d += incr) { + float dist = start + d * delta; + dist += fuzz * min(pow(dist * 0.005, 2.0), 1.0); + + vec3 pos = origin + dir * min(dist, max_dist); + vec2 sample = cloud_at(pos); + + float integral = sample.y * incr; + passthrough *= max(1.0 - integral, 0.0); + cloud_shade = mix(cloud_shade, sample.x, passthrough * integral); + } + } + + float total_density = 1.0 - passthrough;// / (1.0 + max(max_dist, start) * 0.0001); + + total_density = max(total_density - 1.0 / pow(max_dist, 0.25), 0.0); // Hack + + return vec4(vec3(cloud_shade), total_density); +} + vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float quality, bool with_stars, out vec4 clouds) { // Sky color vec3 sun_dir = get_sun_dir(time_of_day); @@ -211,3 +283,8 @@ float fog(vec3 f_pos, vec3 focus_pos, uint medium) { return pow(clamp((max(fog, mist) - min_fog) / (max_fog - min_fog), 0.0, 1.0), 1.7); } + +vec3 illuminate(vec3 color, vec3 light, vec3 diffuse, vec3 ambience) { + float avg_col = (color.r + color.g + color.b) / 3.0; + return ((color - avg_col) * light + (diffuse + ambience) * avg_col) * (diffuse + ambience); +} diff --git a/assets/voxygen/shaders/lod-terrain-frag.glsl b/assets/voxygen/shaders/lod-terrain-frag.glsl new file mode 100644 index 0000000000..119055e58c --- /dev/null +++ b/assets/voxygen/shaders/lod-terrain-frag.glsl @@ -0,0 +1,28 @@ +#version 330 core + +#include +#include +#include +#include + +in vec3 f_pos; + +out vec4 tgt_color; + +#include + +void main() { + vec3 f_norm = lod_norm(f_pos.xy); + vec3 f_col = lod_col(f_pos.xy); + + vec3 light, diffuse_light, ambient_light; + get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0); + vec3 surf_color = illuminate(srgb_to_linear(f_col), light, diffuse_light, ambient_light); + + float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); + vec4 clouds; + vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 1.0, true, clouds); + vec3 color = mix(mix(surf_color, fog_color, 0.0), clouds.rgb, clouds.a); + + tgt_color = vec4(color, 1.0); +} diff --git a/assets/voxygen/shaders/lod-terrain-vert.glsl b/assets/voxygen/shaders/lod-terrain-vert.glsl index 0f7690972b..996bc7c366 100644 --- a/assets/voxygen/shaders/lod-terrain-vert.glsl +++ b/assets/voxygen/shaders/lod-terrain-vert.glsl @@ -2,8 +2,7 @@ #include #include - -uniform sampler2D t_noise; +#include in vec2 v_pos; @@ -13,23 +12,15 @@ uniform u_locals { }; 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 = lod_pos(v_pos); - 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_pos.z -= 25.0 / pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0); f_light = 1.0; - f_norm = vec3(0, 0, 1); - gl_Position = proj_mat * view_mat * diff --git a/assets/voxygen/shaders/terrain-frag.glsl b/assets/voxygen/shaders/terrain-frag.glsl index b6a17e48f2..615947d70a 100644 --- a/assets/voxygen/shaders/terrain-frag.glsl +++ b/assets/voxygen/shaders/terrain-frag.glsl @@ -36,7 +36,7 @@ void main() { float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x); vec4 clouds; vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 1.0, true, clouds); - vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a); + vec3 color = mix(mix(surf_color, fog_color, 0.0), clouds.rgb, clouds.a); tgt_color = vec4(color, 1.0); } diff --git a/voxygen/src/render/error.rs b/voxygen/src/render/error.rs index 85c08ca4a2..7a66b47488 100644 --- a/voxygen/src/render/error.rs +++ b/voxygen/src/render/error.rs @@ -18,11 +18,60 @@ 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`. match err { gfx::PipelineStateError::DescriptorInit(err) => { - gfx::PipelineStateError::DescriptorInit(err.into()) - }, - err => 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, + code_offset, + } => gfx::pso::ElementError::Offset { + name: name.to_string(), + shader_offset, + code_offset, + }, + gfx::pso::ElementError::Format { + name, + shader_format, + code_format, + } => gfx::pso::ElementError::Format { + name: name.to_string(), + shader_format, + code_format, + }, + }), + ) + } + 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), } .into() } diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 3d6c5d0bc3..d50003b724 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -760,8 +760,6 @@ fn create_pipelines( ), RenderError, > { - dbg!("start"); - let globals = assets::load_watched::("voxygen.shaders.include.globals", shader_reload_indicator) .unwrap(); @@ -777,6 +775,9 @@ fn create_pipelines( let random = assets::load_watched::("voxygen.shaders.include.random", shader_reload_indicator) .unwrap(); + let lod = + assets::load_watched::("voxygen.shaders.include.lod", shader_reload_indicator) + .unwrap(); let anti_alias = assets::load_watched::( &["voxygen.shaders.antialias.", match aa_mode { @@ -807,6 +808,7 @@ fn create_pipelines( include_ctx.include("light.glsl", &light); include_ctx.include("srgb.glsl", &srgb); include_ctx.include("random.glsl", &random); + include_ctx.include("lod.glsl", &lod); include_ctx.include("anti-aliasing.glsl", &anti_alias); include_ctx.include("cloud.glsl", &cloud); @@ -898,14 +900,15 @@ fn create_pipelines( shader_reload_indicator, ) .unwrap(), - &assets::load_watched::("voxygen.shaders.terrain-frag", shader_reload_indicator) - .unwrap(), + &assets::load_watched::( + "voxygen.shaders.lod-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, @@ -924,8 +927,6 @@ fn create_pipelines( gfx::state::CullFace::Back, )?; - dbg!("created pipelines"); - Ok(( skybox_pipeline, figure_pipeline, @@ -947,22 +948,11 @@ 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())?; - dbg!("linked"); - let result = Ok(GfxPipeline { pso: factory.create_pipeline_from_program( &program, @@ -978,7 +968,5 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>( )?, }); - dbg!("finished pipeline"); - result } diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index 16e989bbe8..d96b9e9142 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -13,7 +13,7 @@ impl Lod { pub fn new(renderer: &mut Renderer) -> Self { Self { model: renderer - .create_model(&create_lod_terrain_mesh(256)) + .create_model(&create_lod_terrain_mesh(100)) .unwrap(), locals: renderer.create_consts(&[Locals::default()]).unwrap(), } @@ -25,7 +25,7 @@ impl Lod { } fn create_lod_terrain_mesh(detail: usize) -> Mesh { - let transform = |x| (2.0 * x as f32) / detail as f32 - 2.0; + let transform = |x| (2.0 * x as f32) / detail as f32 - 1.0; let mut mesh = Mesh::new();