diff --git a/CHANGELOG.md b/CHANGELOG.md index aea2312d33..8eecd36a93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Saving of the last selected character in the character selection screen - Autoselecting the newly created character - Deselecting when the selected character is deleted +- Upscaling support ### Changed diff --git a/assets/voxygen/i18n/en.ron b/assets/voxygen/i18n/en.ron index 16cc9752a6..a705027832 100644 --- a/assets/voxygen/i18n/en.ron +++ b/assets/voxygen/i18n/en.ron @@ -337,6 +337,7 @@ magically infused items?"#, "hud.settings.gamma": "Gamma", "hud.settings.ambiance": "Ambiance Brightness", "hud.settings.antialiasing_mode": "AntiAliasing Mode", + "hud.settings.upscale_factor": "Upscale Factor", "hud.settings.cloud_rendering_mode": "Cloud Rendering Mode", "hud.settings.fluid_rendering_mode": "Fluid Rendering Mode", "hud.settings.fluid_rendering_mode.cheap": "Cheap", diff --git a/assets/voxygen/shaders/clouds-frag.glsl b/assets/voxygen/shaders/clouds-frag.glsl new file mode 100644 index 0000000000..082765829f --- /dev/null +++ b/assets/voxygen/shaders/clouds-frag.glsl @@ -0,0 +1,74 @@ +#version 330 core + +#include + +#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION) + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +#include +// Note: The sampler uniform is declared here because it differs for MSAA +#include +#include +#include + +uniform sampler2D src_depth; + +in vec2 f_pos; + +layout (std140) +uniform u_locals { + mat4 proj_mat_inv; + mat4 view_mat_inv; +}; + +out vec4 tgt_color; + +float depth_at(vec2 uv) { + float buf_depth = texture(src_depth, uv).x; + vec4 clip_space = vec4(uv * 2.0 - 1.0, buf_depth, 1.0); + vec4 view_space = proj_mat_inv * clip_space; + view_space /= view_space.w; + return -view_space.z; +} + +vec3 wpos_at(vec2 uv) { + float buf_depth = texture(src_depth, uv).x * 2.0 - 1.0; + mat4 inv = view_mat_inv * proj_mat_inv;//inverse(all_mat); + vec4 clip_space = vec4(uv * 2.0 - 1.0, buf_depth, 1.0); + vec4 view_space = inv * clip_space; + view_space /= view_space.w; + if (buf_depth == 1.0) { + vec3 direction = normalize(view_space.xyz); + return direction.xyz * 100000.0 + cam_pos.xyz; + } else { + return view_space.xyz; + } +} + +void main() { + vec2 uv = (f_pos + 1.0) * 0.5; + + vec4 color = texture(src_color, uv); + + // Apply clouds to `aa_color` + #if (CLOUD_MODE != CLOUD_MODE_NONE) + vec3 wpos = wpos_at(uv); + float dist = distance(wpos, cam_pos.xyz); + vec3 dir = (wpos - cam_pos.xyz) / dist; + + color.rgb = get_cloud_color(color.rgb, dir, cam_pos.xyz, time_of_day.x, dist, 1.0); + #endif + + tgt_color = vec4(color.rgb, 1); +} diff --git a/assets/voxygen/shaders/clouds-vert.glsl b/assets/voxygen/shaders/clouds-vert.glsl new file mode 100644 index 0000000000..35b786997f --- /dev/null +++ b/assets/voxygen/shaders/clouds-vert.glsl @@ -0,0 +1,29 @@ +#version 330 core + +#include + +#define LIGHTING_TYPE (LIGHTING_TYPE_TRANSMISSION | LIGHTING_TYPE_REFLECTION) + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_SPECULAR + +#if (FLUID_MODE == FLUID_MODE_CHEAP) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE +#elif (FLUID_MODE == FLUID_MODE_SHINY) +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE +#endif + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +#include + +in vec2 v_pos; + +out vec2 f_pos; + +void main() { + f_pos = v_pos; + + gl_Position = vec4(v_pos, -1.0, 1.0); +} diff --git a/assets/voxygen/shaders/postprocess-frag.glsl b/assets/voxygen/shaders/postprocess-frag.glsl index 7aa7c4522d..a1ff97f132 100644 --- a/assets/voxygen/shaders/postprocess-frag.glsl +++ b/assets/voxygen/shaders/postprocess-frag.glsl @@ -22,7 +22,7 @@ #include #include -uniform sampler2D src_depth; +//uniform sampler2D src_depth; in vec2 f_pos; @@ -145,6 +145,7 @@ vec3 _illuminate(float max_light, vec3 view_dir, /*vec3 max_light, */vec3 emitte // return /*srgb_to_linear*/(/*0.5*//*0.125 * */vec3(pow(color.x, gamma), pow(color.y, gamma), pow(color.z, gamma))); } +/* float depth_at(vec2 uv) { float buf_depth = texture(src_depth, uv).x; vec4 clip_space = vec4(uv * 2.0 - 1.0, buf_depth, 1.0); @@ -166,6 +167,7 @@ vec3 wpos_at(vec2 uv) { return view_space.xyz; } } +*/ void main() { vec2 uv = (f_pos + 1.0) * 0.5; @@ -202,6 +204,7 @@ void main() { vec4 aa_color = aa_apply(src_color, uv * screen_res.xy, screen_res.xy); + /* // Apply clouds to `aa_color` #if (CLOUD_MODE != CLOUD_MODE_NONE) vec3 wpos = wpos_at(uv); @@ -210,6 +213,7 @@ void main() { aa_color.rgb = get_cloud_color(aa_color.rgb, dir, cam_pos.xyz, time_of_day.x, dist, 1.0); #endif + */ // aa_color.rgb = (wpos + focus_off.xyz) / vec3(32768, 32768, /*view_distance.w*/2048); // aa_color.rgb = mod((wpos + focus_off.xyz), vec3(32768, 32768, view_distance.w)) / vec3(32768, 32768, view_distance.w);// / vec3(32768, 32768, view_distance.w); diff --git a/voxygen/src/hud/settings_window.rs b/voxygen/src/hud/settings_window.rs index 6eb62d2107..29ea570eda 100644 --- a/voxygen/src/hud/settings_window.rs +++ b/voxygen/src/hud/settings_window.rs @@ -6,7 +6,10 @@ use super::{ use crate::{ hud::BuffPosition, i18n::{list_localizations, LanguageMetadata, Localization}, - render::{AaMode, CloudMode, FluidMode, LightingMode, RenderMode, ShadowMapMode, ShadowMode}, + render::{ + AaMode, CloudMode, FluidMode, LightingMode, RenderMode, ShadowMapMode, ShadowMode, + UpscaleMode, + }, ui::{fonts::Fonts, ImageSlider, ScaleMode, ToggleButton}, window::{FullScreenSettings, FullscreenMode, GameInput}, GlobalState, @@ -126,6 +129,8 @@ widget_ids! { ambiance_value, aa_mode_text, aa_mode_list, + upscale_factor_text, + upscale_factor_list, cloud_mode_text, cloud_mode_list, fluid_mode_text, @@ -2060,13 +2065,55 @@ impl<'a> Widget for SettingsWindow<'a> { }))); } + // Upscaling factor + Text::new(&self.localized_strings.get("hud.settings.upscale_factor")) + .down_from(state.ids.aa_mode_list, 8.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.upscale_factor_text, ui); + + let upscale_factors = [ + // Upscaling + 0.15, 0.2, 0.25, 0.35, 0.5, 0.65, 0.75, 0.85, 1.0, + // Downscaling (equivalent to SSAA) + 1.25, 1.5, 1.75, 2.0, + ]; + + // Get which upscale factor is currently active + let selected = upscale_factors + .iter() + .position(|factor| (*factor - render_mode.upscale_mode.factor).abs() < 0.001); + + if let Some(clicked) = DropDownList::new( + &upscale_factors + .iter() + .map(|factor| format!("{n:.*}", 2, n = factor)) + .collect::>(), + selected, + ) + .w_h(400.0, 22.0) + .color(MENU_BG) + .label_color(TEXT_COLOR) + .label_font_id(self.fonts.cyri.conrod_id) + .down_from(state.ids.upscale_factor_text, 8.0) + .set(state.ids.upscale_factor_list, ui) + { + events.push(Event::ChangeRenderMode(Box::new(RenderMode { + upscale_mode: UpscaleMode { + factor: upscale_factors[clicked], + }, + ..render_mode.clone() + }))); + } + // CloudMode Text::new( &self .localized_strings .get("hud.settings.cloud_rendering_mode"), ) - .down_from(state.ids.aa_mode_list, 8.0) + .down_from(state.ids.upscale_factor_list, 8.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 4e2224b3b8..0c69b2cd86 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -16,6 +16,7 @@ pub use self::{ mesh::{Mesh, Quad, Tri}, model::{DynamicModel, Model}, pipelines::{ + clouds::{create_mesh as create_clouds_mesh, CloudsPipeline, Locals as CloudsLocals}, figure::{ BoneData as FigureBoneData, BoneMeshes, FigureModel, FigurePipeline, Locals as FigureLocals, @@ -257,6 +258,17 @@ impl ShadowMode { pub fn is_map(&self) -> bool { matches!(self, Self::Map(_)) } } +/// Upscale mode settings. +#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)] +pub struct UpscaleMode { + // Determines non-UI graphics upscaling. 0.25 to 2.0. + pub factor: f32, +} + +impl Default for UpscaleMode { + fn default() -> Self { Self { factor: 1.0 } } +} + /// Render modes #[derive(PartialEq, Clone, Debug, Default, Serialize, Deserialize)] #[serde(default)] @@ -266,4 +278,5 @@ pub struct RenderMode { pub fluid: FluidMode, pub lighting: LightingMode, pub shadow: ShadowMode, + pub upscale_mode: UpscaleMode, } diff --git a/voxygen/src/render/pipelines/clouds.rs b/voxygen/src/render/pipelines/clouds.rs new file mode 100644 index 0000000000..7ad0c782b9 --- /dev/null +++ b/voxygen/src/render/pipelines/clouds.rs @@ -0,0 +1,77 @@ +use super::{ + super::{Mesh, Pipeline, TgtColorFmt, TgtDepthStencilFmt, Tri}, + Globals, +}; +use gfx::{ + self, gfx_constant_struct_meta, 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 { + proj_mat_inv: [[f32; 4]; 4] = "proj_mat_inv", + view_mat_inv: [[f32; 4]; 4] = "view_mat_inv", + } + + pipeline pipe { + vbuf: gfx::VertexBuffer = (), + + locals: gfx::ConstantBuffer = "u_locals", + globals: gfx::ConstantBuffer = "u_globals", + + map: gfx::TextureSampler<[f32; 4]> = "t_map", + alt: gfx::TextureSampler<[f32; 2]> = "t_alt", + horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", + + color_sampler: gfx::TextureSampler<::View> = "src_color", + depth_sampler: gfx::TextureSampler<::View> = "src_depth", + + noise: gfx::TextureSampler = "t_noise", + + tgt_color: gfx::RenderTarget = "tgt_color", + } +} + +impl Default for Locals { + fn default() -> Self { Self::new(Mat4::identity(), Mat4::identity()) } +} + +impl Locals { + pub fn new(proj_mat_inv: Mat4, view_mat_inv: Mat4) -> Self { + Self { + proj_mat_inv: proj_mat_inv.into_col_arrays(), + view_mat_inv: view_mat_inv.into_col_arrays(), + } + } +} + +pub struct CloudsPipeline; + +impl Pipeline for CloudsPipeline { + type Vertex = Vertex; +} + +pub fn create_mesh() -> Mesh { + let mut mesh = Mesh::new(); + + #[rustfmt::skip] + mesh.push_tri(Tri::new( + Vertex { pos: [ 1.0, -1.0] }, + Vertex { pos: [-1.0, 1.0] }, + Vertex { pos: [-1.0, -1.0] }, + )); + + #[rustfmt::skip] + mesh.push_tri(Tri::new( + Vertex { pos: [1.0, -1.0] }, + Vertex { pos: [1.0, 1.0] }, + Vertex { pos: [-1.0, 1.0] }, + )); + + mesh +} diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index 62d7282ea1..28bf1954b4 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -1,3 +1,4 @@ +pub mod clouds; pub mod figure; pub mod fluid; pub mod lod_terrain; diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index fe6a8f8b8a..d669343aca 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -5,8 +5,8 @@ use super::{ mesh::Mesh, model::{DynamicModel, Model}, pipelines::{ - figure, fluid, lod_terrain, particle, postprocess, shadow, skybox, sprite, terrain, ui, - GlobalModel, Globals, + clouds, figure, fluid, lod_terrain, particle, postprocess, shadow, skybox, sprite, terrain, + ui, GlobalModel, Globals, }, texture::Texture, AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode, @@ -148,9 +148,11 @@ pub struct Renderer { tgt_color_view: TgtColorView, tgt_depth_stencil_view: TgtDepthStencilView, + tgt_color_view_pp: TgtColorView, tgt_color_res: TgtColorRes, tgt_depth_res: TgtDepthRes, + tgt_color_res_pp: TgtColorRes, sampler: Sampler, @@ -164,6 +166,7 @@ pub struct Renderer { particle_pipeline: GfxPipeline>, ui_pipeline: GfxPipeline>, lod_terrain_pipeline: GfxPipeline>, + clouds_pipeline: GfxPipeline>, postprocess_pipeline: GfxPipeline>, player_shadow_pipeline: GfxPipeline>, @@ -213,6 +216,7 @@ impl Renderer { particle_pipeline, ui_pipeline, lod_terrain_pipeline, + clouds_pipeline, postprocess_pipeline, player_shadow_pipeline, point_shadow_pipeline, @@ -225,8 +229,14 @@ impl Renderer { &mut shader_reload_indicator, )?; - let (tgt_color_view, tgt_depth_stencil_view, tgt_color_res, tgt_depth_res) = - Self::create_rt_views(&mut factory, (dims.0, dims.1), &mode)?; + let ( + tgt_color_view, + tgt_depth_stencil_view, + tgt_color_view_pp, + tgt_color_res, + tgt_depth_res, + tgt_color_res_pp, + ) = Self::create_rt_views(&mut factory, (dims.0, dims.1), &mode)?; let shadow_map = if let ( Some(point_pipeline), @@ -266,7 +276,10 @@ impl Renderer { None }; - let sampler = factory.create_sampler_linear(); + let sampler = factory.create_sampler(gfx::texture::SamplerInfo::new( + gfx::texture::FilterMethod::Bilinear, + gfx::texture::WrapMode::Clamp, + )); let noise_tex = Texture::new( &mut factory, @@ -286,9 +299,11 @@ impl Renderer { tgt_color_view, tgt_depth_stencil_view, + tgt_color_view_pp, tgt_color_res, tgt_depth_res, + tgt_color_res_pp, sampler, @@ -302,6 +317,7 @@ impl Renderer { particle_pipeline, ui_pipeline, lod_terrain_pipeline, + clouds_pipeline, postprocess_pipeline, player_shadow_pipeline, @@ -363,12 +379,20 @@ impl Renderer { // Avoid panics when creating texture with w,h of 0,0. if dims.0 != 0 && dims.1 != 0 { - let (tgt_color_view, tgt_depth_stencil_view, tgt_color_res, tgt_depth_res) = - Self::create_rt_views(&mut self.factory, (dims.0, dims.1), &self.mode)?; + let ( + tgt_color_view, + tgt_depth_stencil_view, + tgt_color_view_pp, + tgt_color_res, + tgt_depth_res, + tgt_color_res_pp, + ) = Self::create_rt_views(&mut self.factory, (dims.0, dims.1), &self.mode)?; self.tgt_color_res = tgt_color_res; self.tgt_depth_res = tgt_depth_res; + self.tgt_color_res_pp = tgt_color_res_pp; self.tgt_color_view = tgt_color_view; self.tgt_depth_stencil_view = tgt_depth_stencil_view; + self.tgt_color_view_pp = tgt_color_view_pp; if let (Some(shadow_map), ShadowMode::Map(mode)) = (self.shadow_map.as_mut(), self.mode.shadow) { @@ -403,42 +427,66 @@ impl Renderer { factory: &mut gfx_device_gl::Factory, size: (u16, u16), mode: &RenderMode, - ) -> Result<(TgtColorView, TgtDepthStencilView, TgtColorRes, TgtDepthRes), RenderError> { + ) -> Result< + ( + TgtColorView, + TgtDepthStencilView, + TgtColorView, + TgtColorRes, + TgtDepthRes, + TgtColorRes, + ), + RenderError, + > { + let upscaled = Vec2::from(size) + .map(|e: u16| (e as f32 * mode.upscale_mode.factor) as u16) + .into_tuple(); let kind = match mode.aa { AaMode::None | AaMode::Fxaa => { - gfx::texture::Kind::D2(size.0, size.1, gfx::texture::AaMode::Single) + gfx::texture::Kind::D2(upscaled.0, upscaled.1, gfx::texture::AaMode::Single) }, // TODO: Ensure sampling in the shader is exactly between the 4 texels AaMode::SsaaX4 => { + // TODO: Figure out how to do upscaling correctly with SSAA gfx::texture::Kind::D2(size.0 * 2, size.1 * 2, gfx::texture::AaMode::Single) }, AaMode::MsaaX4 => { - gfx::texture::Kind::D2(size.0, size.1, gfx::texture::AaMode::Multi(4)) + gfx::texture::Kind::D2(upscaled.0, upscaled.1, gfx::texture::AaMode::Multi(4)) }, AaMode::MsaaX8 => { - gfx::texture::Kind::D2(size.0, size.1, gfx::texture::AaMode::Multi(8)) + gfx::texture::Kind::D2(upscaled.0, upscaled.1, gfx::texture::AaMode::Multi(8)) }, AaMode::MsaaX16 => { - gfx::texture::Kind::D2(size.0, size.1, gfx::texture::AaMode::Multi(16)) + gfx::texture::Kind::D2(upscaled.0, upscaled.1, gfx::texture::AaMode::Multi(16)) }, }; let levels = 1; let color_cty = <::Channel as gfx::format::ChannelTyped >::get_channel_type(); - let tgt_color_tex = factory.create_texture( - kind, - levels, - gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::RENDER_TARGET, - gfx::memory::Usage::Data, - Some(color_cty), - )?; - let tgt_color_res = factory.view_texture_as_shader_resource::( - &tgt_color_tex, - (0, levels - 1), - gfx::format::Swizzle::new(), - )?; + let mut color_tex = || { + factory.create_texture( + kind, + levels, + gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::RENDER_TARGET, + gfx::memory::Usage::Data, + Some(color_cty), + ) + }; + let tgt_color_tex = color_tex()?; + let tgt_color_tex_pp = color_tex()?; + let mut color_res = |tex| { + factory.view_texture_as_shader_resource::( + tex, + (0, levels - 1), + gfx::format::Swizzle::new(), + ) + }; + let tgt_color_res = color_res(&tgt_color_tex)?; + let tgt_color_res_pp = color_res(&tgt_color_tex_pp)?; let tgt_color_view = factory.view_texture_as_render_target(&tgt_color_tex, 0, None)?; + let tgt_color_view_pp = + factory.view_texture_as_render_target(&tgt_color_tex_pp, 0, None)?; let depth_stencil_cty = <::Channel as gfx::format::ChannelTyped>::get_channel_type(); let tgt_depth_stencil_tex = factory.create_texture( @@ -459,8 +507,10 @@ impl Renderer { Ok(( tgt_color_view, tgt_depth_stencil_view, + tgt_color_view_pp, tgt_color_res, tgt_depth_res, + tgt_color_res_pp, )) } @@ -763,6 +813,7 @@ impl Renderer { particle_pipeline, ui_pipeline, lod_terrain_pipeline, + clouds_pipeline, postprocess_pipeline, player_shadow_pipeline, point_shadow_pipeline, @@ -777,6 +828,7 @@ impl Renderer { self.particle_pipeline = particle_pipeline; self.ui_pipeline = ui_pipeline; self.lod_terrain_pipeline = lod_terrain_pipeline; + self.clouds_pipeline = clouds_pipeline; self.postprocess_pipeline = postprocess_pipeline; self.player_shadow_pipeline = player_shadow_pipeline; if let ( @@ -1645,6 +1697,37 @@ impl Renderer { ); } + pub fn render_clouds( + &mut self, + model: &Model, + globals: &Consts, + locals: &Consts, + lod: &lod_terrain::LodData, + ) { + 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.clouds_pipeline.pso, + &clouds::pipe::Data { + vbuf: model.vbuf.clone(), + locals: locals.buf.clone(), + globals: globals.buf.clone(), + map: (lod.map.srv.clone(), lod.map.sampler.clone()), + alt: (lod.alt.srv.clone(), lod.alt.sampler.clone()), + horizon: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), + color_sampler: (self.tgt_color_res.clone(), self.sampler.clone()), + depth_sampler: (self.tgt_depth_res.clone(), self.sampler.clone()), + noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), + tgt_color: self.tgt_color_view_pp.clone(), + }, + ) + } + pub fn render_post_process( &mut self, model: &Model, @@ -1668,7 +1751,7 @@ impl Renderer { map: (lod.map.srv.clone(), lod.map.sampler.clone()), alt: (lod.alt.srv.clone(), lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(), lod.horizon.sampler.clone()), - color_sampler: (self.tgt_color_res.clone(), self.sampler.clone()), + color_sampler: (self.tgt_color_res_pp.clone(), self.sampler.clone()), depth_sampler: (self.tgt_depth_res.clone(), self.sampler.clone()), noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), tgt_color: self.win_color_view.clone(), @@ -1698,6 +1781,7 @@ fn create_pipelines( GfxPipeline>, GfxPipeline>, GfxPipeline>, + GfxPipeline>, GfxPipeline>, GfxPipeline>, Option>>, @@ -1908,6 +1992,16 @@ fn create_pipelines( gfx::state::CullFace::Back, )?; + // Construct a pipeline for rendering our clouds (a kind of post-processing) + let clouds_pipeline = create_pipeline( + factory, + clouds::pipe::new(), + &Glsl::load_watched("voxygen.shaders.clouds-vert", shader_reload_indicator).unwrap(), + &Glsl::load_watched("voxygen.shaders.clouds-frag", shader_reload_indicator).unwrap(), + &include_ctx, + gfx::state::CullFace::Back, + )?; + // Construct a pipeline for rendering our post-processing let postprocess_pipeline = create_pipeline( factory, @@ -2019,6 +2113,7 @@ fn create_pipelines( particle_pipeline, ui_pipeline, lod_terrain_pipeline, + clouds_pipeline, postprocess_pipeline, player_shadow_pipeline, point_shadow_pipeline, diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 4cd499c7f8..f1f62cb339 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -16,9 +16,9 @@ pub use self::{ use crate::{ audio::{music::MusicMgr, sfx::SfxMgr, AudioFrontend}, render::{ - create_pp_mesh, create_skybox_mesh, Consts, GlobalModel, Globals, Light, LodData, Model, - PostProcessLocals, PostProcessPipeline, Renderer, Shadow, ShadowLocals, SkyboxLocals, - SkyboxPipeline, + create_clouds_mesh, create_pp_mesh, create_skybox_mesh, CloudsLocals, CloudsPipeline, + Consts, GlobalModel, Globals, Light, LodData, Model, PostProcessLocals, + PostProcessPipeline, Renderer, Shadow, ShadowLocals, SkyboxLocals, SkyboxPipeline, }, settings::Settings, window::{AnalogGameInput, Event}, @@ -71,6 +71,11 @@ struct Skybox { locals: Consts, } +struct Clouds { + model: Model, + locals: Consts, +} + struct PostProcess { model: Model, locals: Consts, @@ -83,6 +88,7 @@ pub struct Scene { event_lights: Vec, skybox: Skybox, + clouds: Clouds, postprocess: PostProcess, terrain: Terrain, pub lod: Lod, @@ -283,6 +289,10 @@ impl Scene { model: renderer.create_model(&create_skybox_mesh()).unwrap(), locals: renderer.create_consts(&[SkyboxLocals::default()]).unwrap(), }, + clouds: Clouds { + model: renderer.create_model(&create_clouds_mesh()).unwrap(), + locals: renderer.create_consts(&[CloudsLocals::default()]).unwrap(), + }, postprocess: PostProcess { model: renderer.create_model(&create_pp_mesh()).unwrap(), locals: renderer @@ -664,6 +674,12 @@ impl Scene { scene_data.sprite_render_distance as f32 - 20.0, )]) .expect("Failed to update global constants"); + renderer + .update_consts(&mut self.clouds.locals, &[CloudsLocals::new( + proj_mat_inv, + view_mat_inv, + )]) + .expect("Failed to update cloud locals"); renderer .update_consts(&mut self.postprocess.locals, &[PostProcessLocals::new( proj_mat_inv, @@ -1075,6 +1091,14 @@ impl Scene { // Render particle effects. self.particle_mgr.render(renderer, scene_data, global, lod); + // Render clouds (a post-processing effect) + renderer.render_clouds( + &self.clouds.model, + &global.globals, + &self.clouds.locals, + self.lod.get_data(), + ); + renderer.render_post_process( &self.postprocess.model, &global.globals, diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 70a9a20b72..a48c877a3d 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -1,9 +1,10 @@ use crate::{ mesh::{greedy::GreedyMesh, Meshable}, render::{ - create_pp_mesh, create_skybox_mesh, BoneMeshes, Consts, FigureModel, FigurePipeline, - GlobalModel, Globals, Light, Mesh, Model, PostProcessLocals, PostProcessPipeline, Renderer, - Shadow, ShadowLocals, SkyboxLocals, SkyboxPipeline, TerrainPipeline, + create_clouds_mesh, create_pp_mesh, create_skybox_mesh, BoneMeshes, CloudsLocals, + CloudsPipeline, Consts, FigureModel, FigurePipeline, GlobalModel, Globals, Light, Mesh, + Model, PostProcessLocals, PostProcessPipeline, Renderer, Shadow, ShadowLocals, + SkyboxLocals, SkyboxPipeline, TerrainPipeline, }, scene::{ camera::{self, Camera, CameraMode}, @@ -61,11 +62,17 @@ struct PostProcess { locals: Consts, } +struct Clouds { + model: Model, + locals: Consts, +} + pub struct Scene { data: GlobalModel, camera: Camera, skybox: Skybox, + clouds: Clouds, postprocess: PostProcess, lod: LodData, map_bounds: Vec2, @@ -123,6 +130,10 @@ impl Scene { model: renderer.create_model(&create_skybox_mesh()).unwrap(), locals: renderer.create_consts(&[SkyboxLocals::default()]).unwrap(), }, + clouds: Clouds { + model: renderer.create_model(&create_clouds_mesh()).unwrap(), + locals: renderer.create_consts(&[CloudsLocals::default()]).unwrap(), + }, postprocess: PostProcess { model: renderer.create_model(&create_pp_mesh()).unwrap(), locals: renderer @@ -377,6 +388,13 @@ impl Scene { ); } + renderer.render_clouds( + &self.clouds.model, + &self.data.globals, + &self.clouds.locals, + &self.lod, + ); + renderer.render_post_process( &self.postprocess.model, &self.data.globals,