diff --git a/CHANGELOG.md b/CHANGELOG.md index ca2dbe62bf..3c66b44eac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fleshed out range attack into charging and shooting anims for staff/bow - Customized attack animation for hammers and axes - German translation +- Added a silhouette for players when they are occluded +- Added transparency to the player when zooming in ### Changed @@ -56,7 +58,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Asset cleanup to lower client-size - Rewrote the humanoid skeleton to be more ideal for attack animations - ### Removed ## [0.5.0] - 2019-01-31 diff --git a/assets/voxygen/shaders/figure-frag.glsl b/assets/voxygen/shaders/figure-frag.glsl index aba60bf8d5..d02fba8f17 100644 --- a/assets/voxygen/shaders/figure-frag.glsl +++ b/assets/voxygen/shaders/figure-frag.glsl @@ -10,6 +10,9 @@ layout (std140) uniform u_locals { mat4 model_mat; vec4 model_col; + // bit 0 - is player + // bit 1-31 - unused + int flags; }; struct BoneData { @@ -43,5 +46,13 @@ void main() { vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.5, true, clouds); vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a); - tgt_color = vec4(color, 1.0); + float opacity = 1.0; + + if ((flags & 1) == 1 && int(cam_mode) == 1) { + float distance = distance(vec3(cam_pos), f_pos) - 1; + + opacity = clamp(distance / 3, 0, 1); + } + + tgt_color = vec4(color, opacity); } diff --git a/assets/voxygen/shaders/figure-vert.glsl b/assets/voxygen/shaders/figure-vert.glsl index eced69e5ea..c42e5d68bc 100644 --- a/assets/voxygen/shaders/figure-vert.glsl +++ b/assets/voxygen/shaders/figure-vert.glsl @@ -11,6 +11,9 @@ layout (std140) uniform u_locals { mat4 model_mat; vec4 model_col; + // bit 0 - is player + // bit 1-31 - unused + int flags; }; struct BoneData { diff --git a/assets/voxygen/shaders/include/globals.glsl b/assets/voxygen/shaders/include/globals.glsl index e0e97949e2..fb80fe9909 100644 --- a/assets/voxygen/shaders/include/globals.glsl +++ b/assets/voxygen/shaders/include/globals.glsl @@ -13,4 +13,5 @@ uniform u_globals { uvec4 medium; ivec4 select_pos; vec4 gamma; + uint cam_mode; }; diff --git a/assets/voxygen/shaders/player-shadow-frag.glsl b/assets/voxygen/shaders/player-shadow-frag.glsl new file mode 100644 index 0000000000..66c0dac893 --- /dev/null +++ b/assets/voxygen/shaders/player-shadow-frag.glsl @@ -0,0 +1,33 @@ +#version 330 core + +#include + +in vec3 f_pos; +in vec3 f_col; +flat in vec3 f_norm; + +layout (std140) +uniform u_locals { + mat4 model_mat; + vec4 model_col; + int flags; +}; + +struct BoneData { + mat4 bone_mat; +}; + +layout (std140) +uniform u_bones { + BoneData bones[16]; +}; + +#include +#include +#include + +out vec4 tgt_color; + +void main() { + tgt_color = vec4(0.0,0.0,0.0, 1.0); +} \ No newline at end of file diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index e848b80ed0..906493865b 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -30,7 +30,7 @@ pub use self::{ }, Globals, Light, Shadow, }, - renderer::{Renderer, TgtColorFmt, TgtDepthFmt, WinColorFmt, WinDepthFmt}, + renderer::{Renderer, TgtColorFmt, TgtDepthStencilFmt, WinColorFmt, WinDepthFmt}, texture::Texture, }; diff --git a/voxygen/src/render/pipelines/figure.rs b/voxygen/src/render/pipelines/figure.rs index ace2a54533..94a252e68c 100644 --- a/voxygen/src/render/pipelines/figure.rs +++ b/voxygen/src/render/pipelines/figure.rs @@ -1,10 +1,11 @@ use super::{ - super::{util::arr_to_mat, Pipeline, TgtColorFmt, TgtDepthFmt}, + super::{util::arr_to_mat, Pipeline, TgtColorFmt, TgtDepthStencilFmt}, Globals, Light, Shadow, }; use gfx::{ self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, gfx_pipeline_inner, gfx_vertex_struct_meta, + state::{ColorMask, Comparison, Stencil, StencilOp}, }; use vek::*; @@ -19,6 +20,7 @@ gfx_defines! { constant Locals { model_mat: [[f32; 4]; 4] = "model_mat", model_col: [f32; 4] = "model_col", + flags: u32 = "flags", } constant BoneData { @@ -36,8 +38,8 @@ gfx_defines! { noise: gfx::TextureSampler = "t_noise", - tgt_color: gfx::RenderTarget = "tgt_color", - tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, + tgt_color: gfx::BlendTarget = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA), + tgt_depth_stencil: gfx::DepthStencilTarget = (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Replace))), } } @@ -58,16 +60,20 @@ impl Vertex { } impl Locals { - pub fn new(model_mat: Mat4, col: Rgba) -> Self { + pub fn new(model_mat: Mat4, col: Rgba, is_player: bool) -> Self { + let mut flags = 0; + flags |= is_player as u32; + Self { model_mat: arr_to_mat(model_mat.into_col_array()), model_col: col.into_array(), + flags, } } } impl Default for Locals { - fn default() -> Self { Self::new(Mat4::identity(), Rgba::broadcast(1.0)) } + fn default() -> Self { Self::new(Mat4::identity(), Rgba::broadcast(1.0), false) } } impl BoneData { diff --git a/voxygen/src/render/pipelines/fluid.rs b/voxygen/src/render/pipelines/fluid.rs index ec13e96df9..dfae0af2df 100644 --- a/voxygen/src/render/pipelines/fluid.rs +++ b/voxygen/src/render/pipelines/fluid.rs @@ -1,10 +1,11 @@ use super::{ - super::{Pipeline, TerrainLocals, TgtColorFmt, TgtDepthFmt}, + super::{Pipeline, TerrainLocals, TgtColorFmt, TgtDepthStencilFmt}, Globals, Light, Shadow, }; use gfx::{ self, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, gfx_pipeline_inner, - gfx_vertex_struct_meta, state::ColorMask, + gfx_vertex_struct_meta, + state::{ColorMask, Comparison, Stencil, StencilOp}, }; use std::ops::Mul; use vek::*; @@ -27,7 +28,7 @@ gfx_defines! { waves: gfx::TextureSampler<[f32; 4]> = "t_waves", tgt_color: gfx::BlendTarget = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA), - tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_TEST, + tgt_depth_stencil: gfx::DepthStencilTarget = (gfx::preset::depth::LESS_EQUAL_TEST,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), } } diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index 4e6fd5b282..a4edd0e598 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -7,6 +7,7 @@ pub mod terrain; pub mod ui; use super::util::arr_to_mat; +use crate::scene::camera::CameraMode; use common::terrain::BlockKind; use gfx::{self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta}; use vek::*; @@ -27,6 +28,7 @@ gfx_defines! { medium: [u32; 4] = "medium", select_pos: [i32; 4] = "select_pos", gamma: [f32; 4] = "gamma", + cam_mode: u32 = "cam_mode", } constant Light { @@ -55,6 +57,7 @@ impl Globals { medium: BlockKind, select_pos: Option>, gamma: f32, + cam_mode: CameraMode, ) -> Self { Self { view_mat: arr_to_mat(view_mat.into_col_array()), @@ -73,6 +76,7 @@ impl Globals { .unwrap_or(Vec4::zero()) .into_array(), gamma: [gamma; 4], + cam_mode: cam_mode as u32, } } } @@ -93,6 +97,7 @@ impl Default for Globals { BlockKind::Air, None, 1.0, + CameraMode::ThirdPerson, ) } } diff --git a/voxygen/src/render/pipelines/skybox.rs b/voxygen/src/render/pipelines/skybox.rs index 9baf76596d..e6cbd95649 100644 --- a/voxygen/src/render/pipelines/skybox.rs +++ b/voxygen/src/render/pipelines/skybox.rs @@ -1,10 +1,11 @@ use super::{ - super::{Mesh, Pipeline, Quad, TgtColorFmt, TgtDepthFmt}, + super::{Mesh, Pipeline, Quad, TgtColorFmt, TgtDepthStencilFmt}, Globals, }; use gfx::{ self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, gfx_pipeline_inner, gfx_vertex_struct_meta, + state::{Comparison, Stencil, StencilOp}, }; gfx_defines! { @@ -25,7 +26,7 @@ gfx_defines! { noise: gfx::TextureSampler = "t_noise", tgt_color: gfx::RenderTarget = "tgt_color", - tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, + tgt_depth_stencil: gfx::DepthStencilTarget = (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), } } diff --git a/voxygen/src/render/pipelines/sprite.rs b/voxygen/src/render/pipelines/sprite.rs index 31178e4b1d..b39ca90a17 100644 --- a/voxygen/src/render/pipelines/sprite.rs +++ b/voxygen/src/render/pipelines/sprite.rs @@ -1,10 +1,11 @@ use super::{ - super::{util::arr_to_mat, Pipeline, TgtColorFmt, TgtDepthFmt}, + super::{util::arr_to_mat, Pipeline, TgtColorFmt, TgtDepthStencilFmt}, Globals, Light, Shadow, }; use gfx::{ self, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, gfx_pipeline_inner, - gfx_vertex_struct_meta, state::ColorMask, + gfx_vertex_struct_meta, + state::{ColorMask, Comparison, Stencil, StencilOp}, }; use vek::*; @@ -35,7 +36,7 @@ gfx_defines! { noise: gfx::TextureSampler = "t_noise", tgt_color: gfx::BlendTarget = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA), - tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, + tgt_depth_stencil: gfx::DepthStencilTarget = (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), } } diff --git a/voxygen/src/render/pipelines/terrain.rs b/voxygen/src/render/pipelines/terrain.rs index 6899a8eb18..8fe5658a6b 100644 --- a/voxygen/src/render/pipelines/terrain.rs +++ b/voxygen/src/render/pipelines/terrain.rs @@ -1,10 +1,11 @@ use super::{ - super::{Pipeline, TgtColorFmt, TgtDepthFmt}, + super::{Pipeline, TgtColorFmt, TgtDepthStencilFmt}, Globals, Light, Shadow, }; use gfx::{ self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, gfx_pipeline_inner, gfx_vertex_struct_meta, + state::{Comparison, Stencil, StencilOp}, }; use std::ops::Mul; use vek::*; @@ -31,7 +32,7 @@ gfx_defines! { noise: gfx::TextureSampler = "t_noise", tgt_color: gfx::RenderTarget = "tgt_color", - tgt_depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, + tgt_depth_stencil: gfx::DepthStencilTarget = (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), } } diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 3cf3ff7fcb..ab369c7419 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -12,6 +12,7 @@ use common::assets::{self, watch::ReloadIndicator}; use gfx::{ self, handle::Sampler, + state::{Comparison, Stencil, StencilOp}, traits::{Device, Factory, FactoryExt}, }; use glsl_include::Context as IncludeContext; @@ -20,8 +21,8 @@ use vek::*; /// Represents the format of the pre-processed color target. pub type TgtColorFmt = gfx::format::Srgba8; -/// Represents the format of the pre-processed depth target. -pub type TgtDepthFmt = gfx::format::Depth; +/// Represents the format of the pre-processed depth and stencil target. +pub type TgtDepthStencilFmt = gfx::format::DepthStencil; /// Represents the format of the window's color target. pub type WinColorFmt = gfx::format::Srgba8; @@ -31,7 +32,8 @@ pub type WinDepthFmt = gfx::format::Depth; /// A handle to a pre-processed color target. pub type TgtColorView = gfx::handle::RenderTargetView; /// A handle to a pre-processed depth target. -pub type TgtDepthView = gfx::handle::DepthStencilView; +pub type TgtDepthStencilView = + gfx::handle::DepthStencilView; /// A handle to a window color target. pub type WinColorView = gfx::handle::RenderTargetView; @@ -57,7 +59,7 @@ pub struct Renderer { win_depth_view: WinDepthView, tgt_color_view: TgtColorView, - tgt_depth_view: TgtDepthView, + tgt_depth_stencil_view: TgtDepthStencilView, tgt_color_res: TgtColorRes, @@ -70,6 +72,7 @@ pub struct Renderer { sprite_pipeline: GfxPipeline>, ui_pipeline: GfxPipeline>, postprocess_pipeline: GfxPipeline>, + player_shadow_pipeline: GfxPipeline>, shader_reload_indicator: ReloadIndicator, @@ -102,6 +105,7 @@ impl Renderer { sprite_pipeline, ui_pipeline, postprocess_pipeline, + player_shadow_pipeline, ) = create_pipelines( &mut factory, aa_mode, @@ -111,7 +115,7 @@ impl Renderer { )?; let dims = win_color_view.get_dimensions(); - let (tgt_color_view, tgt_depth_view, tgt_color_res) = + let (tgt_color_view, tgt_depth_stencil_view, tgt_color_res) = Self::create_rt_views(&mut factory, (dims.0, dims.1), aa_mode)?; let sampler = factory.create_sampler_linear(); @@ -132,7 +136,7 @@ impl Renderer { win_depth_view, tgt_color_view, - tgt_depth_view, + tgt_depth_stencil_view, tgt_color_res, sampler, @@ -144,6 +148,7 @@ impl Renderer { sprite_pipeline, ui_pipeline, postprocess_pipeline, + player_shadow_pipeline, shader_reload_indicator, @@ -158,8 +163,8 @@ impl Renderer { /// Get references to the internal render target views that get rendered to /// before post-processing. #[allow(dead_code)] - pub fn tgt_views(&self) -> (&TgtColorView, &TgtDepthView) { - (&self.tgt_color_view, &self.tgt_depth_view) + pub fn tgt_views(&self) -> (&TgtColorView, &TgtDepthStencilView) { + (&self.tgt_color_view, &self.tgt_depth_stencil_view) } /// Get references to the internal render target views that get displayed @@ -172,8 +177,8 @@ impl Renderer { /// Get mutable references to the internal render target views that get /// rendered to before post-processing. #[allow(dead_code)] - pub fn tgt_views_mut(&mut self) -> (&mut TgtColorView, &mut TgtDepthView) { - (&mut self.tgt_color_view, &mut self.tgt_depth_view) + pub fn tgt_views_mut(&mut self) -> (&mut TgtColorView, &mut TgtDepthStencilView) { + (&mut self.tgt_color_view, &mut self.tgt_depth_stencil_view) } /// Get mutable references to the internal render target views that get @@ -228,11 +233,11 @@ 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_view, tgt_color_res) = + let (tgt_color_view, tgt_depth_stencil_view, tgt_color_res) = Self::create_rt_views(&mut self.factory, (dims.0, dims.1), self.aa_mode)?; self.tgt_color_res = tgt_color_res; self.tgt_color_view = tgt_color_view; - self.tgt_depth_view = tgt_depth_view; + self.tgt_depth_stencil_view = tgt_depth_stencil_view; } Ok(()) @@ -242,7 +247,7 @@ impl Renderer { factory: &mut gfx_device_gl::Factory, size: (u16, u16), aa_mode: AaMode, - ) -> Result<(TgtColorView, TgtDepthView, TgtColorRes), RenderError> { + ) -> Result<(TgtColorView, TgtDepthStencilView, TgtColorRes), RenderError> { let kind = match aa_mode { AaMode::None | AaMode::Fxaa => { gfx::texture::Kind::D2(size.0, size.1, gfx::texture::AaMode::Single) @@ -279,17 +284,18 @@ impl Renderer { )?; let tgt_color_view = factory.view_texture_as_render_target(&tgt_color_tex, 0, None)?; - let depth_cty = <::Channel as gfx::format::ChannelTyped>::get_channel_type(); - let tgt_depth_tex = factory.create_texture( + let depth_stencil_cty = <::Channel as gfx::format::ChannelTyped>::get_channel_type(); + let tgt_depth_stencil_tex = factory.create_texture( kind, levels, gfx::memory::Bind::DEPTH_STENCIL, gfx::memory::Usage::Data, - Some(depth_cty), + Some(depth_stencil_cty), )?; - let tgt_depth_view = factory.view_texture_as_depth_stencil_trivial(&tgt_depth_tex)?; + let tgt_depth_stencil_view = + factory.view_texture_as_depth_stencil_trivial(&tgt_depth_stencil_tex)?; - Ok((tgt_color_view, tgt_depth_view, tgt_color_res)) + Ok((tgt_color_view, tgt_depth_stencil_view, tgt_color_res)) } /// Get the resolution of the render target. @@ -303,7 +309,8 @@ impl Renderer { /// Queue the clearing of the depth target ready for a new frame to be /// rendered. pub fn clear(&mut self) { - self.encoder.clear_depth(&self.tgt_depth_view, 1.0); + self.encoder.clear_depth(&self.tgt_depth_stencil_view, 1.0); + self.encoder.clear_stencil(&self.tgt_depth_stencil_view, 0); self.encoder.clear_depth(&self.win_depth_view, 1.0); } @@ -336,6 +343,7 @@ impl Renderer { sprite_pipeline, ui_pipeline, postprocess_pipeline, + player_shadow_pipeline, )) => { self.skybox_pipeline = skybox_pipeline; self.figure_pipeline = figure_pipeline; @@ -344,6 +352,7 @@ impl Renderer { self.sprite_pipeline = sprite_pipeline; self.ui_pipeline = ui_pipeline; self.postprocess_pipeline = postprocess_pipeline; + self.player_shadow_pipeline = player_shadow_pipeline; }, Err(e) => error!( "Could not recreate shaders from assets due to an error: {:#?}", @@ -502,7 +511,7 @@ impl Renderer { 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(), + tgt_depth_stencil: (self.tgt_depth_stencil_view.clone(), (1, 1)), }, ); } @@ -535,7 +544,73 @@ impl Renderer { shadows: shadows.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(), + tgt_depth_stencil: (self.tgt_depth_stencil_view.clone(), (1, 1)), + }, + ); + } + + /// Queue the rendering of the player silhouette in the upcoming frame. + pub fn render_player_shadow( + &mut self, + model: &Model, + globals: &Consts, + locals: &Consts, + bones: &Consts, + lights: &Consts, + shadows: &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.player_shadow_pipeline.pso, + &figure::pipe::Data { + vbuf: model.vbuf.clone(), + locals: locals.buf.clone(), + globals: globals.buf.clone(), + bones: bones.buf.clone(), + lights: lights.buf.clone(), + shadows: shadows.buf.clone(), + noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), + tgt_color: self.tgt_color_view.clone(), + tgt_depth_stencil: (self.tgt_depth_stencil_view.clone(), (0, 0)), + }, + ); + } + + /// Queue the rendering of the player model in the upcoming frame. + pub fn render_player( + &mut self, + model: &Model, + globals: &Consts, + locals: &Consts, + bones: &Consts, + lights: &Consts, + shadows: &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.figure_pipeline.pso, + &figure::pipe::Data { + vbuf: model.vbuf.clone(), + locals: locals.buf.clone(), + globals: globals.buf.clone(), + bones: bones.buf.clone(), + lights: lights.buf.clone(), + shadows: shadows.buf.clone(), + noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), + tgt_color: self.tgt_color_view.clone(), + tgt_depth_stencil: (self.tgt_depth_stencil_view.clone(), (1, 1)), }, ); } @@ -567,7 +642,7 @@ impl Renderer { shadows: shadows.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(), + tgt_depth_stencil: (self.tgt_depth_stencil_view.clone(), (1, 1)), }, ); } @@ -601,7 +676,7 @@ impl Renderer { noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), waves: (waves.srv.clone(), waves.sampler.clone()), tgt_color: self.tgt_color_view.clone(), - tgt_depth: self.tgt_depth_view.clone(), + tgt_depth_stencil: (self.tgt_depth_stencil_view.clone(), (1, 1)), }, ); } @@ -633,7 +708,7 @@ impl Renderer { shadows: shadows.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(), + tgt_depth_stencil: (self.tgt_depth_stencil_view.clone(), (1, 1)), }, ); } @@ -721,6 +796,7 @@ fn create_pipelines( GfxPipeline>, GfxPipeline>, GfxPipeline>, + GfxPipeline>, ), RenderError, > { @@ -869,6 +945,31 @@ fn create_pipelines( gfx::state::CullFace::Back, )?; + // Construct a pipeline for rendering the player silhouette + let player_shadow_pipeline = create_pipeline( + factory, + figure::pipe::Init { + tgt_depth_stencil: ( + gfx::preset::depth::PASS_TEST, + Stencil::new( + Comparison::Equal, + 0xff, + (StencilOp::Keep, StencilOp::Keep, StencilOp::Keep), + ), + ), + ..figure::pipe::new() + }, + &assets::load_watched::("voxygen.shaders.figure-vert", shader_reload_indicator) + .unwrap(), + &assets::load_watched::( + "voxygen.shaders.player-shadow-frag", + shader_reload_indicator, + ) + .unwrap(), + &include_ctx, + gfx::state::CullFace::Back, + )?; + Ok(( skybox_pipeline, figure_pipeline, @@ -877,6 +978,7 @@ fn create_pipelines( sprite_pipeline, ui_pipeline, postprocess_pipeline, + player_shadow_pipeline, )) } diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index bb29781c25..3847b0293e 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -13,8 +13,8 @@ pub const MIN_ZOOM: f32 = 0.1; // Possible TODO: Add more modes #[derive(PartialEq, Clone, Copy, Eq, Hash)] pub enum CameraMode { - FirstPerson, - ThirdPerson, + FirstPerson = 0, + ThirdPerson = 1, } impl Default for CameraMode { diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 5fa3f1e485..c9ac36634c 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -144,6 +144,8 @@ impl FigureMgr { ) .join() { + let is_player = scene_data.player_entity == entity; + let (pos, ori) = interpolated .map(|i| (Pos(i.pos), *i.ori)) .unwrap_or((*pos, Vec3::unit_y())); @@ -380,7 +382,7 @@ impl FigureMgr { let col = stats .map(|s| { Rgba::broadcast(1.0) - + Rgba::new(2.0, 2.0, 2.0, 0.0).map(|c| { + + Rgba::new(2.0, 2.0, 2., 0.00).map(|c| { (c / (1.0 + DAMAGE_FADE_COEFFICIENT * s.health.last_change.0)) as f32 }) }) @@ -627,6 +629,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, Body::QuadrupedSmall(_) => { @@ -707,6 +710,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, Body::QuadrupedMedium(_) => { @@ -789,6 +793,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, Body::BirdMedium(_) => { @@ -863,6 +868,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, Body::FishMedium(_) => { @@ -937,6 +943,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, Body::Dragon(_) => { @@ -1011,6 +1018,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, Body::Critter(_) => { @@ -1085,6 +1093,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, Body::BirdSmall(_) => { @@ -1159,6 +1168,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, Body::FishSmall(_) => { @@ -1233,6 +1243,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, Body::BipedLarge(_) => { @@ -1307,6 +1318,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, Body::Object(_) => { @@ -1326,6 +1338,7 @@ impl FigureMgr { state_animation_rate, lpindex, true, + is_player, ); }, } @@ -1386,201 +1399,110 @@ impl FigureMgr { .filter(|(_, _, _, _, stats, _, _)| stats.map_or(true, |s| !s.is_dead)) { let is_player = entity == player_entity; - let player_camera_mode = if is_player { - camera.get_mode() - } else { - CameraMode::default() - }; - let character_state = if is_player { character_state } else { None }; - let FigureMgr { - model_cache, - critter_model_cache, - quadruped_small_model_cache, - quadruped_medium_model_cache, - bird_medium_model_cache, - bird_small_model_cache, - dragon_model_cache, - fish_medium_model_cache, - fish_small_model_cache, - biped_large_model_cache, - character_states, - quadruped_small_states, - quadruped_medium_states, - bird_medium_states, - fish_medium_states, - critter_states, - dragon_states, - bird_small_states, - fish_small_states, - biped_large_states, - object_states, - } = self; - if let Some((locals, bone_consts, model)) = match body { - Body::Humanoid(_) => character_states - .get(&entity) - .filter(|state| state.visible) - .map(|state| { - ( - state.locals(), - state.bone_consts(), - &model_cache - .get_or_create_model( - renderer, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, - ) - }), - Body::QuadrupedSmall(_) => quadruped_small_states.get(&entity).map(|state| { - ( - state.locals(), - state.bone_consts(), - &quadruped_small_model_cache - .get_or_create_model( - renderer, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, - ) - }), - Body::QuadrupedMedium(_) => quadruped_medium_states.get(&entity).map(|state| { - ( - state.locals(), - state.bone_consts(), - &quadruped_medium_model_cache - .get_or_create_model( - renderer, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, - ) - }), - Body::BirdMedium(_) => bird_medium_states.get(&entity).map(|state| { - ( - state.locals(), - state.bone_consts(), - &bird_medium_model_cache - .get_or_create_model( - renderer, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, - ) - }), - Body::FishMedium(_) => fish_medium_states.get(&entity).map(|state| { - ( - state.locals(), - state.bone_consts(), - &fish_medium_model_cache - .get_or_create_model( - renderer, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, - ) - }), - Body::Critter(_) => critter_states.get(&entity).map(|state| { - ( - state.locals(), - state.bone_consts(), - &critter_model_cache - .get_or_create_model( - renderer, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, - ) - }), - Body::Dragon(_) => dragon_states.get(&entity).map(|state| { - ( - state.locals(), - state.bone_consts(), - &dragon_model_cache - .get_or_create_model( - renderer, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, - ) - }), - Body::BirdSmall(_) => bird_small_states.get(&entity).map(|state| { - ( - state.locals(), - state.bone_consts(), - &bird_small_model_cache - .get_or_create_model( - renderer, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, - ) - }), - Body::FishSmall(_) => fish_small_states.get(&entity).map(|state| { - ( - state.locals(), - state.bone_consts(), - &fish_small_model_cache - .get_or_create_model( - renderer, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, - ) - }), - Body::BipedLarge(_) => biped_large_states.get(&entity).map(|state| { - ( - state.locals(), - state.bone_consts(), - &biped_large_model_cache - .get_or_create_model( - renderer, - *body, - loadout, - tick, - player_camera_mode, - character_state, - ) - .0, - ) - }), - Body::Object(_) => object_states.get(&entity).map(|state| { + if !is_player { + self.render_figure( + renderer, + tick, + globals, + lights, + shadows, + camera, + character_state, + entity, + body, + loadout, + false, + ); + } + } + } + + pub fn render_player( + &mut self, + renderer: &mut Renderer, + state: &State, + player_entity: EcsEntity, + tick: u64, + globals: &Consts, + lights: &Consts, + shadows: &Consts, + camera: &Camera, + ) { + let ecs = state.ecs(); + + let character_state_storage = state.read_storage::(); + let character_state = character_state_storage.get(player_entity); + + if let Some(body) = ecs.read_storage::().get(player_entity) { + let loadout_storage = ecs.read_storage::(); + let loadout = loadout_storage.get(player_entity); + + self.render_figure( + renderer, + tick, + globals, + lights, + shadows, + camera, + character_state, + player_entity, + body, + loadout, + true, + ); + } + } + + fn render_figure( + &mut self, + renderer: &mut Renderer, + tick: u64, + globals: &Consts, + lights: &Consts, + shadows: &Consts, + camera: &Camera, + character_state: Option<&CharacterState>, + entity: EcsEntity, + body: &Body, + loadout: Option<&Loadout>, + is_player: bool, + ) { + let player_camera_mode = if is_player { + camera.get_mode() + } else { + CameraMode::default() + }; + let character_state = if is_player { character_state } else { None }; + + let FigureMgr { + model_cache, + critter_model_cache, + quadruped_small_model_cache, + quadruped_medium_model_cache, + bird_medium_model_cache, + bird_small_model_cache, + dragon_model_cache, + fish_medium_model_cache, + fish_small_model_cache, + biped_large_model_cache, + character_states, + quadruped_small_states, + quadruped_medium_states, + bird_medium_states, + fish_medium_states, + critter_states, + dragon_states, + bird_small_states, + fish_small_states, + biped_large_states, + object_states, + } = self; + if let Some((locals, bone_consts, model)) = match body { + Body::Humanoid(_) => character_states + .get(&entity) + .filter(|state| state.visible) + .map(|state| { ( state.locals(), state.bone_consts(), @@ -1596,11 +1518,175 @@ impl FigureMgr { .0, ) }), - } { - renderer.render_figure(model, globals, locals, bone_consts, lights, shadows); + Body::QuadrupedSmall(_) => quadruped_small_states.get(&entity).map(|state| { + ( + state.locals(), + state.bone_consts(), + &quadruped_small_model_cache + .get_or_create_model( + renderer, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ) + .0, + ) + }), + Body::QuadrupedMedium(_) => quadruped_medium_states.get(&entity).map(|state| { + ( + state.locals(), + state.bone_consts(), + &quadruped_medium_model_cache + .get_or_create_model( + renderer, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ) + .0, + ) + }), + Body::BirdMedium(_) => bird_medium_states.get(&entity).map(|state| { + ( + state.locals(), + state.bone_consts(), + &bird_medium_model_cache + .get_or_create_model( + renderer, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ) + .0, + ) + }), + Body::FishMedium(_) => fish_medium_states.get(&entity).map(|state| { + ( + state.locals(), + state.bone_consts(), + &fish_medium_model_cache + .get_or_create_model( + renderer, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ) + .0, + ) + }), + Body::Critter(_) => critter_states.get(&entity).map(|state| { + ( + state.locals(), + state.bone_consts(), + &critter_model_cache + .get_or_create_model( + renderer, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ) + .0, + ) + }), + Body::Dragon(_) => dragon_states.get(&entity).map(|state| { + ( + state.locals(), + state.bone_consts(), + &dragon_model_cache + .get_or_create_model( + renderer, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ) + .0, + ) + }), + Body::BirdSmall(_) => bird_small_states.get(&entity).map(|state| { + ( + state.locals(), + state.bone_consts(), + &bird_small_model_cache + .get_or_create_model( + renderer, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ) + .0, + ) + }), + Body::FishSmall(_) => fish_small_states.get(&entity).map(|state| { + ( + state.locals(), + state.bone_consts(), + &fish_small_model_cache + .get_or_create_model( + renderer, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ) + .0, + ) + }), + Body::BipedLarge(_) => biped_large_states.get(&entity).map(|state| { + ( + state.locals(), + state.bone_consts(), + &biped_large_model_cache + .get_or_create_model( + renderer, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ) + .0, + ) + }), + Body::Object(_) => object_states.get(&entity).map(|state| { + ( + state.locals(), + state.bone_consts(), + &model_cache + .get_or_create_model( + renderer, + *body, + loadout, + tick, + player_camera_mode, + character_state, + ) + .0, + ) + }), + } { + if is_player { + renderer.render_player(model, globals, locals, bone_consts, lights, shadows); + renderer.render_player_shadow(model, globals, locals, bone_consts, lights, shadows); } else { - trace!("Body has no saved figure"); + renderer.render_figure(model, globals, locals, bone_consts, lights, shadows); } + } else { + trace!("Body has no saved figure"); } } @@ -1705,6 +1791,7 @@ impl FigureState { state_animation_rate: f32, lpindex: u8, visible: bool, + is_player: bool, ) { self.visible = visible; self.lpindex = lpindex; @@ -1720,7 +1807,7 @@ impl FigureState { * Mat4::rotation_x(ori.z.atan2(Vec2::from(ori).magnitude())) * Mat4::scaling_3d(Vec3::from(0.8 * scale)); - let locals = FigureLocals::new(mat, col); + let locals = FigureLocals::new(mat, col, is_player); renderer.update_consts(&mut self.locals, &[locals]).unwrap(); renderer diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index d9d28d6e0f..bbb4efe64d 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -347,6 +347,7 @@ impl Scene { .unwrap_or(BlockKind::Air), self.select_pos, gamma, + self.camera.get_mode(), )]) .expect("Failed to update global constants"); @@ -381,6 +382,13 @@ impl Scene { tick: u64, ) { // Render terrain and figures. + self.terrain.render( + renderer, + &self.globals, + &self.lights, + &self.shadows, + self.camera.get_focus_pos(), + ); self.figure_mgr.render( renderer, state, @@ -391,13 +399,6 @@ impl Scene { &self.shadows, &self.camera, ); - self.terrain.render( - renderer, - &self.globals, - &self.lights, - &self.shadows, - self.camera.get_focus_pos(), - ); // Render the skybox. renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals); @@ -410,6 +411,17 @@ impl Scene { self.camera.get_focus_pos(), ); + self.figure_mgr.render_player( + renderer, + state, + player_entity, + tick, + &self.globals, + &self.lights, + &self.shadows, + &self.camera, + ); + renderer.render_post_process( &self.postprocess.model, &self.globals, diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 34aaec83e4..e663fb841f 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -170,6 +170,7 @@ impl Scene { BlockKind::Air, None, scene_data.gamma, + self.camera.get_mode(), )]) { error!("Renderer failed to update: {:?}", err); } @@ -199,6 +200,7 @@ impl Scene { 1.0, 0, true, + false, ); }