diff --git a/assets/voxygen/shaders/clouds-frag.glsl b/assets/voxygen/shaders/clouds-frag.glsl index 7f70b99c6b..1b9f19edef 100644 --- a/assets/voxygen/shaders/clouds-frag.glsl +++ b/assets/voxygen/shaders/clouds-frag.glsl @@ -22,19 +22,19 @@ #include #include -layout(set = 1, binding = 0) +layout(set = 2, binding = 0) uniform texture2D t_src_color; -layout(set = 1, binding = 1) +layout(set = 2, binding = 1) uniform sampler s_src_color; -layout(set = 1, binding = 2) +layout(set = 2, binding = 2) uniform texture2D t_src_depth; -layout(set = 1, binding = 3) +layout(set = 2, binding = 3) uniform sampler s_src_depth; layout(location = 0) in vec2 uv; -layout (std140, set = 1, binding = 4) +layout (std140, set = 2, binding = 4) uniform u_locals { mat4 proj_mat_inv; mat4 view_mat_inv; diff --git a/assets/voxygen/shaders/figure-frag.glsl b/assets/voxygen/shaders/figure-frag.glsl index 449beb76c4..a91a22ec4c 100644 --- a/assets/voxygen/shaders/figure-frag.glsl +++ b/assets/voxygen/shaders/figure-frag.glsl @@ -37,9 +37,9 @@ layout(location = 1) flat in vec3 f_norm; // const vec4 sun_pos = vec4(0.0); // #endif -layout(set = 2, binding = 0) +layout(set = 3, binding = 0) uniform texture2D t_col_light; -layout(set = 2, binding = 1) +layout(set = 3, binding = 1) uniform sampler s_col_light; //struct ShadowLocals { @@ -52,7 +52,7 @@ uniform sampler s_col_light; // ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192]; //}; -layout (std140, set = 1, binding = 0) +layout (std140, set = 2, binding = 0) uniform u_locals { mat4 model_mat; vec4 highlight_col; @@ -70,7 +70,7 @@ struct BoneData { mat4 normals_mat; }; -layout (std140, set = 1, binding = 1) +layout (std140, set = 2, binding = 1) uniform u_bones { BoneData bones[16]; }; diff --git a/assets/voxygen/shaders/figure-vert.glsl b/assets/voxygen/shaders/figure-vert.glsl index c1457fc3cd..29a83df1dc 100644 --- a/assets/voxygen/shaders/figure-vert.glsl +++ b/assets/voxygen/shaders/figure-vert.glsl @@ -25,7 +25,7 @@ layout(location = 1) in uint v_atlas_pos; // out vec3 light_pos[2]; in uint v_ao_bone; */ -layout (std140, set = 1, binding = 0) +layout (std140, set = 2, binding = 0) uniform u_locals { mat4 model_mat; vec4 highlight_col; @@ -43,7 +43,7 @@ struct BoneData { mat4 normals_mat; }; -layout (std140, set = 1, binding = 1) +layout (std140, set = 2, binding = 1) uniform u_bones { // Warning: might not actually be 16 elements long. Don't index out of bounds! BoneData bones[16]; diff --git a/assets/voxygen/shaders/fluid-frag/cheap.glsl b/assets/voxygen/shaders/fluid-frag/cheap.glsl index 7a1d815c7c..4f138dc0b3 100644 --- a/assets/voxygen/shaders/fluid-frag/cheap.glsl +++ b/assets/voxygen/shaders/fluid-frag/cheap.glsl @@ -37,16 +37,16 @@ layout(location = 1) flat in uint f_pos_norm; // ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192]; // }; -layout(std140, set = 2, binding = 0) +layout(std140, set = 3, binding = 0) uniform u_locals { vec3 model_offs; float load_time; ivec4 atlas_offs; }; -layout(set = 1, binding = 0) +layout(set = 2, binding = 0) uniform texture2D t_waves; -layout(set = 1, binding = 1) +layout(set = 2, binding = 1) uniform sampler s_waves; layout(location = 0) out vec4 tgt_color; diff --git a/assets/voxygen/shaders/fluid-frag/shiny.glsl b/assets/voxygen/shaders/fluid-frag/shiny.glsl index 6893cd7deb..c424dc3d52 100644 --- a/assets/voxygen/shaders/fluid-frag/shiny.glsl +++ b/assets/voxygen/shaders/fluid-frag/shiny.glsl @@ -39,16 +39,16 @@ layout(location = 1) flat in uint f_pos_norm; // ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192]; //}; -layout(std140, set = 2, binding = 0) +layout(std140, set = 3, binding = 0) uniform u_locals { vec3 model_offs; float load_time; ivec4 atlas_offs; }; -layout(set = 1, binding = 0) +layout(set = 2, binding = 0) uniform texture2D t_waves; -layout(set = 1, binding = 1) +layout(set = 2, binding = 1) uniform sampler s_waves; layout(location = 0) out vec4 tgt_color; diff --git a/assets/voxygen/shaders/fluid-vert.glsl b/assets/voxygen/shaders/fluid-vert.glsl index 8b7520c883..fbe16c654c 100644 --- a/assets/voxygen/shaders/fluid-vert.glsl +++ b/assets/voxygen/shaders/fluid-vert.glsl @@ -23,7 +23,7 @@ layout(location = 0) in uint v_pos_norm; // in uint v_col_light; -layout(std140, set = 2, binding = 0) +layout(std140, set = 3, binding = 0) uniform u_locals { vec3 model_offs; float load_time; diff --git a/assets/voxygen/shaders/include/lod.glsl b/assets/voxygen/shaders/include/lod.glsl index 9b472b6074..9b455d004d 100644 --- a/assets/voxygen/shaders/include/lod.glsl +++ b/assets/voxygen/shaders/include/lod.glsl @@ -330,9 +330,9 @@ vec3 lod_pos(vec2 pos, vec2 focus_pos) { } #ifdef HAS_LOD_FULL_INFO -layout(set = 0, binding = 14) +layout(set = 0, binding = 10) uniform texture2D t_map; -layout(set = 0, binding = 15) +layout(set = 0, binding = 11) uniform sampler s_map; vec3 lod_col(vec2 pos) { diff --git a/assets/voxygen/shaders/include/shadows.glsl b/assets/voxygen/shaders/include/shadows.glsl index 517a45db53..3b5157923f 100644 --- a/assets/voxygen/shaders/include/shadows.glsl +++ b/assets/voxygen/shaders/include/shadows.glsl @@ -3,30 +3,26 @@ #ifdef HAS_SHADOW_MAPS - #if (SHADOW_MODE == SHADOW_MODE_MAP) -struct ShadowLocals { +#if (SHADOW_MODE == SHADOW_MODE_MAP) +layout (std140, set = 0, binding = 9) +uniform u_light_shadows { mat4 shadowMatrices; mat4 texture_mat; }; -layout (std140, set = 0, binding = 9) -uniform u_light_shadows { - ShadowLocals shadowMats[/*MAX_LAYER_FACES*//*192*/126]; -}; - // Use with sampler2DShadow -layout(set = 0, binding = 12) +layout(set = 1, binding = 2) uniform texture2D t_directed_shadow_maps; -layout(set = 0, binding = 13) +layout(set = 1, binding = 3) uniform sampler s_directed_shadow_maps; // uniform sampler2DArrayShadow t_directed_shadow_maps; // uniform samplerCubeArrayShadow t_shadow_maps; // uniform samplerCubeArray t_shadow_maps; // Use with samplerCubeShadow -layout(set = 0, binding = 10) +layout(set = 1, binding = 0) uniform textureCube t_point_shadow_maps; -layout(set = 0, binding = 11) +layout(set = 1, binding = 1) uniform sampler s_point_shadow_maps; // uniform samplerCube t_shadow_maps; @@ -165,7 +161,6 @@ float ShadowCalculationDirected(in vec3 fragPos)//in vec4 /*light_pos[2]*/sun_po } */ // vec3 fragPos = sun_pos.xyz;// / sun_pos.w;//light_pos[lightIndex].xyz; // sun_pos.z += sun_pos.w * bias; - mat4 texture_mat = shadowMats[0].texture_mat; vec4 sun_pos = texture_mat * vec4(fragPos, 1.0); // sun_pos.z -= sun_pos.w * bias; float visibility = textureProj(sampler2DShadow(t_directed_shadow_maps, s_directed_shadow_maps), sun_pos); diff --git a/assets/voxygen/shaders/light-shadows-directed-vert.glsl b/assets/voxygen/shaders/light-shadows-directed-vert.glsl index 19633997cf..1e55596c7e 100644 --- a/assets/voxygen/shaders/light-shadows-directed-vert.glsl +++ b/assets/voxygen/shaders/light-shadows-directed-vert.glsl @@ -22,7 +22,13 @@ // Currently, we only need globals for focus_off. #include // For shadow locals. -#include +// #include + +layout (std140, set = 0, binding = 9) +uniform u_light_shadows { + mat4 shadowMatrices; + mat4 texture_mat; +}; /* Accurate packed shadow maps for many lights at once! * @@ -54,7 +60,7 @@ void main() { // vec3 f_pos = f_chunk_pos + model_offs; // gl_Position = v_pos + vec4(model_offs, 0.0); - gl_Position = /*all_mat * */shadowMats[/*layer_face*/0].shadowMatrices * vec4(f_pos/*, 1.0*/, /*float(((f_pos_norm >> 29) & 0x7u) ^ 0x1)*//*uintBitsToFloat(v_pos_norm)*/1.0); + gl_Position = /*all_mat * */shadowMatrices * vec4(f_pos/*, 1.0*/, /*float(((f_pos_norm >> 29) & 0x7u) ^ 0x1)*//*uintBitsToFloat(v_pos_norm)*/1.0); // gl_Position.z = -gl_Position.z; // gl_Position.z = clamp(gl_Position.z, -abs(gl_Position.w), abs(gl_Position.w)); // shadowMapCoord = lights[gl_InstanceID].light_pos * gl_Vertex; diff --git a/assets/voxygen/shaders/light-shadows-figure-vert.glsl b/assets/voxygen/shaders/light-shadows-figure-vert.glsl index 3f561178c6..c5d69bdba6 100644 --- a/assets/voxygen/shaders/light-shadows-figure-vert.glsl +++ b/assets/voxygen/shaders/light-shadows-figure-vert.glsl @@ -24,7 +24,13 @@ // Currently, we only need globals for focus_off. #include // For shadow locals. -#include +// #include + +layout (std140, set = 0, binding = 9) +uniform u_light_shadows { + mat4 shadowMatrices; + mat4 texture_mat; +}; /* Accurate packed shadow maps for many lights at once! * @@ -73,6 +79,6 @@ void main() { vec4(pos, 1.0) ).xyz + (model_pos - focus_off.xyz/* + vec3(0.0, 0.0, 0.0001)*/); - gl_Position = shadowMats[/*layer_face*/0].shadowMatrices * vec4(f_pos, 1.0); + gl_Position = shadowMatrices * vec4(f_pos, 1.0); #endif } diff --git a/assets/voxygen/shaders/point-light-shadows-vert.glsl b/assets/voxygen/shaders/point-light-shadows-vert.glsl new file mode 100644 index 0000000000..50ee0167e7 --- /dev/null +++ b/assets/voxygen/shaders/point-light-shadows-vert.glsl @@ -0,0 +1,60 @@ +#version 330 core +// #extension ARB_texture_storage : enable + +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#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 + +// Currently, we only need globals for focus_off. +#include + +/* Accurate packed shadow maps for many lights at once! + * + * Ideally, we would just write to a bitmask... + * + * */ + +layout(location = 1) in uint v_pos_norm; +// in uint v_col_light; +// in vec4 v_pos; + +// Light projection matrices. +layout (std140, set = 1, binding = 0) +uniform u_locals { + vec3 model_offs; + float load_time; + ivec4 atlas_offs; +}; + +// out vec4 shadowMapCoord; + +const int EXTRA_NEG_Z = 32768; + +layout( push_constant ) uniform PointLightMatrix { + vec4 lightShadowMatrix; +}; + +void main() { + vec3 f_chunk_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)) - ivec3(0, 0, EXTRA_NEG_Z)); + vec3 f_pos = f_chunk_pos + model_offs - focus_off.xyz; + // f_pos = v_pos; + // vec3 f_pos = f_chunk_pos + model_offs; + + // gl_Position = v_pos + vec4(model_offs, 0.0); + // gl_Position = /*all_mat * */vec4(f_pos/*, 1.0*/, /*float(((f_pos_norm >> 29) & 0x7u) ^ 0x1)*//*uintBitsToFloat(v_pos_norm)*/1.0); + // shadowMapCoord = lights[gl_InstanceID].light_pos * gl_Vertex; + // vec4(v_pos, 0.0, 1.0); + gl_Position = lightShadowMatrix * vec4(f_pos, 1.0); +} diff --git a/assets/voxygen/shaders/sprite-frag.glsl b/assets/voxygen/shaders/sprite-frag.glsl index fb46c2d209..193f8e29da 100644 --- a/assets/voxygen/shaders/sprite-frag.glsl +++ b/assets/voxygen/shaders/sprite-frag.glsl @@ -28,9 +28,9 @@ layout(location = 4) in vec2 f_inst_light; // in float f_light; // in vec4 light_pos[2]; -layout(set = 3, binding = 0) +layout(set = 4, binding = 0) uniform texture2D t_col_light; -layout(set = 3, binding = 1) +layout(set = 4, binding = 1) uniform sampler s_col_light; //struct ShadowLocals { diff --git a/assets/voxygen/shaders/sprite-vert.glsl b/assets/voxygen/shaders/sprite-vert.glsl index 5d9a4e2284..8e3c373bdc 100644 --- a/assets/voxygen/shaders/sprite-vert.glsl +++ b/assets/voxygen/shaders/sprite-vert.glsl @@ -34,7 +34,7 @@ struct SpriteLocals { vec4 offs; }; -layout(std140, set = 2, binding = 0) +layout(std140, set = 3, binding = 0) uniform u_locals { mat4 mat; vec4 wind_sway; @@ -63,7 +63,7 @@ uniform u_locals { // ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192]; //}; -layout (std140, set = 1, binding = 0) +layout (std140, set = 2, binding = 0) uniform u_terrain_locals { vec3 model_offs; float load_time; diff --git a/assets/voxygen/shaders/terrain-frag.glsl b/assets/voxygen/shaders/terrain-frag.glsl index 69a549cc88..c799cca426 100644 --- a/assets/voxygen/shaders/terrain-frag.glsl +++ b/assets/voxygen/shaders/terrain-frag.glsl @@ -45,12 +45,12 @@ in vec4 sun_pos; const vec4 sun_pos = vec4(0.0); #endif */ -layout(set = 2, binding = 0) +layout(set = 3, binding = 0) uniform texture2D t_col_light; -layout(set = 2, binding = 1) +layout(set = 3, binding = 1) uniform sampler s_col_light; -layout (std140, set = 1, binding = 0) +layout (std140, set = 2, binding = 0) uniform u_locals { vec3 model_offs; float load_time; diff --git a/assets/voxygen/shaders/terrain-vert.glsl b/assets/voxygen/shaders/terrain-vert.glsl index 1124cd5660..499227e7d0 100644 --- a/assets/voxygen/shaders/terrain-vert.glsl +++ b/assets/voxygen/shaders/terrain-vert.glsl @@ -28,7 +28,7 @@ layout(location = 0) in uint v_pos_norm; // in uint v_col_light; layout(location = 1) in uint v_atlas_pos; -layout (std140, set = 1, binding = 0) +layout (std140, set = 2, binding = 0) uniform u_locals { vec3 model_offs; float load_time; @@ -155,7 +155,7 @@ void main() { #ifdef HAS_SHADOW_MAPS gl_Position = - /*all_mat*/shadowMats[0].shadowMatrices/*texture_mat*/ * + /*all_mat*/shadowMatrices/*texture_mat*/ * vec4(f_pos/*newRay*/, 1); gl_Position.z = clamp(gl_Position.z, -abs(gl_Position.w), abs(gl_Position.w)); #else diff --git a/voxygen/src/menu/main/scene.rs b/voxygen/src/menu/main/scene.rs index 32e8699358..77f5c709d0 100644 --- a/voxygen/src/menu/main/scene.rs +++ b/voxygen/src/menu/main/scene.rs @@ -1,5 +1,6 @@ use crate::render::{ - GlobalModel, Globals, GlobalsBindGroup, Light, LodData, Renderer, Shadow, ShadowLocals, + GlobalModel, Globals, GlobalsBindGroup, Light, LodData, PointLightMatrix, Renderer, Shadow, + ShadowLocals, }; pub struct Scene { @@ -12,7 +13,8 @@ impl Scene { globals: renderer.create_consts(&[Globals::default()]), lights: renderer.create_consts(&[Light::default(); 32]), shadows: renderer.create_consts(&[Shadow::default(); 32]), - shadow_mats: renderer.create_consts(&[ShadowLocals::default(); 6]), + shadow_mats: renderer.create_shadow_bound_locals(&[ShadowLocals::default()]), + point_light_matrices: Box::new([PointLightMatrix::default(); 126]), }; let lod_data = LodData::dummy(renderer); diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 7d4a365e33..7a44fdb843 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -28,7 +28,7 @@ pub use self::{ lod_terrain::{LodData, Vertex as LodTerrainVertex}, particle::{Instance as ParticleInstance, Vertex as ParticleVertex}, postprocess::Locals as PostProcessLocals, - shadow::Locals as ShadowLocals, + shadow::{Locals as ShadowLocals, PointLightMatrix}, skybox::{create_mesh as create_skybox_mesh, Vertex as SkyboxVertex}, sprite::{Instance as SpriteInstance, Locals as SpriteLocals, Vertex as SpriteVertex}, terrain::{Locals as TerrainLocals, TerrainLayout, Vertex as TerrainVertex}, @@ -43,7 +43,7 @@ pub use self::{ renderer::{ drawer::{ Drawer, FirstPassDrawer, ParticleDrawer, PreparedUiDrawer, SecondPassDrawer, - ThirdPassDrawer, UiDrawer, + ShadowDrawer, ThirdPassDrawer, UiDrawer, }, ColLightInfo, Renderer, }, diff --git a/voxygen/src/render/pipelines/clouds.rs b/voxygen/src/render/pipelines/clouds.rs index 1ef62d6fa0..eef0f226be 100644 --- a/voxygen/src/render/pipelines/clouds.rs +++ b/voxygen/src/render/pipelines/clouds.rs @@ -153,7 +153,11 @@ impl CloudsPipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Clouds pipeline layout"), push_constant_ranges: &[], - bind_group_layouts: &[&global_layout.globals, &layout.layout], + bind_group_layouts: &[ + &global_layout.globals, + &global_layout.shadow_textures, + &layout.layout, + ], }); let samples = match aa_mode { diff --git a/voxygen/src/render/pipelines/figure.rs b/voxygen/src/render/pipelines/figure.rs index e5b2db70d5..a3de025b93 100644 --- a/voxygen/src/render/pipelines/figure.rs +++ b/voxygen/src/render/pipelines/figure.rs @@ -185,6 +185,7 @@ impl FigurePipeline { push_constant_ranges: &[], bind_group_layouts: &[ &global_layout.globals, + &global_layout.shadow_textures, &layout.locals, &global_layout.col_light, ], diff --git a/voxygen/src/render/pipelines/fluid.rs b/voxygen/src/render/pipelines/fluid.rs index c90214acd6..97176157a5 100644 --- a/voxygen/src/render/pipelines/fluid.rs +++ b/voxygen/src/render/pipelines/fluid.rs @@ -128,6 +128,7 @@ impl FluidPipeline { push_constant_ranges: &[], bind_group_layouts: &[ &global_layout.globals, + &global_layout.shadow_textures, &layout.waves, &terrain_layout.locals, ], diff --git a/voxygen/src/render/pipelines/lod_terrain.rs b/voxygen/src/render/pipelines/lod_terrain.rs index 7953f472b8..bd40198b7d 100644 --- a/voxygen/src/render/pipelines/lod_terrain.rs +++ b/voxygen/src/render/pipelines/lod_terrain.rs @@ -148,7 +148,7 @@ impl LodTerrainPipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Lod terrain pipeline layout"), push_constant_ranges: &[], - bind_group_layouts: &[&global_layout.globals], + bind_group_layouts: &[&global_layout.globals, &global_layout.shadow_textures], }); let samples = match aa_mode { diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index 5fcc628103..b0d24b9882 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -229,16 +229,19 @@ pub struct GlobalModel { pub globals: Consts, pub lights: Consts, pub shadows: Consts, - pub shadow_mats: Consts, + pub shadow_mats: shadow::BoundLocals, + pub point_light_matrices: Box<[shadow::PointLightMatrix; 126]>, } pub struct GlobalsBindGroup { pub(super) bind_group: wgpu::BindGroup, + pub(super) shadow_textures: wgpu::BindGroup, } pub struct GlobalsLayouts { pub globals: wgpu::BindGroupLayout, pub col_light: wgpu::BindGroupLayout, + pub shadow_textures: wgpu::BindGroupLayout, } pub struct ColLights { @@ -357,13 +360,13 @@ impl GlobalsLayouts { }, count: None, }, - // point shadow_maps + // lod map (t_map) wgpu::BindGroupLayoutEntry { binding: 10, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Texture { sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::Cube, + view_dimension: wgpu::TextureViewDimension::D2, multisampled: false, }, count: None, @@ -371,46 +374,6 @@ impl GlobalsLayouts { wgpu::BindGroupLayoutEntry { binding: 11, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler { - filtering: true, - comparison: true, - }, - count: None, - }, - // directed shadow maps - wgpu::BindGroupLayoutEntry { - binding: 12, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 13, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler { - filtering: true, - comparison: true, - }, - count: None, - }, - // lod map (t_map) - wgpu::BindGroupLayoutEntry { - binding: 14, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 15, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Sampler { filtering: true, comparison: false, @@ -446,7 +409,57 @@ impl GlobalsLayouts { ], }); - Self { globals, col_light } + let shadow_textures = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[ + // point shadow_maps + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::Cube, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler { + filtering: true, + comparison: true, + }, + count: None, + }, + // directed shadow maps + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 3, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler { + filtering: true, + comparison: true, + }, + count: None, + }, + ], + }); + + Self { + globals, + col_light, + shadow_textures, + } } pub fn bind( @@ -509,36 +522,45 @@ impl GlobalsLayouts { binding: 9, resource: global_model.shadow_mats.buf().as_entire_binding(), }, - wgpu::BindGroupEntry { - binding: 10, - resource: wgpu::BindingResource::TextureView(&point_shadow_map.view), - }, - wgpu::BindGroupEntry { - binding: 11, - resource: wgpu::BindingResource::Sampler(&point_shadow_map.sampler), - }, - // directed shadow maps - wgpu::BindGroupEntry { - binding: 12, - resource: wgpu::BindingResource::TextureView(&directed_shadow_map.view), - }, - wgpu::BindGroupEntry { - binding: 13, - resource: wgpu::BindingResource::Sampler(&directed_shadow_map.sampler), - }, // lod map (t_map) wgpu::BindGroupEntry { - binding: 14, + binding: 10, resource: wgpu::BindingResource::TextureView(&lod_data.map.view), }, wgpu::BindGroupEntry { - binding: 15, + binding: 11, resource: wgpu::BindingResource::Sampler(&lod_data.map.sampler), }, ], }); - GlobalsBindGroup { bind_group } + let shadow_textures = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &self.shadow_textures, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&point_shadow_map.view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&point_shadow_map.sampler), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::TextureView(&directed_shadow_map.view), + }, + wgpu::BindGroupEntry { + binding: 3, + resource: wgpu::BindingResource::Sampler(&directed_shadow_map.sampler), + }, + ], + }); + + GlobalsBindGroup { + bind_group, + shadow_textures, + } } pub fn bind_col_light( diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index f1c0588c99..5487d4b53d 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -186,7 +186,7 @@ impl ParticlePipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Particle pipeline layout"), push_constant_ranges: &[], - bind_group_layouts: &[&global_layout.globals], + bind_group_layouts: &[&global_layout.globals, &global_layout.shadow_textures], }); let samples = match aa_mode { diff --git a/voxygen/src/render/pipelines/shadow.rs b/voxygen/src/render/pipelines/shadow.rs index b39f2bb950..6f5597f738 100644 --- a/voxygen/src/render/pipelines/shadow.rs +++ b/voxygen/src/render/pipelines/shadow.rs @@ -1,6 +1,6 @@ use super::super::{ - AaMode, ColLightInfo, FigureLayout, GlobalsLayouts, Renderer, TerrainLayout, TerrainVertex, - Texture, + AaMode, Bound, ColLightInfo, Consts, FigureLayout, GlobalsLayouts, Renderer, TerrainLayout, + TerrainVertex, Texture, }; use bytemuck::{Pod, Zeroable}; use vek::*; @@ -21,24 +21,10 @@ impl Locals { } pub fn default() -> Self { Self::new(Mat4::identity(), Mat4::identity()) } - - fn layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: None, - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - }) - } } +pub type BoundLocals = Bound>; + pub struct ShadowLayout { pub locals: wgpu::BindGroupLayout, } @@ -46,9 +32,47 @@ pub struct ShadowLayout { impl ShadowLayout { pub fn new(device: &wgpu::Device) -> Self { Self { - locals: Locals::layout(device), + locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }), } } + + pub fn bind_locals(&self, device: &wgpu::Device, locals: Consts) -> BoundLocals { + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &self.locals, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: locals.buf().as_entire_binding(), + }], + }); + + BoundLocals { + bind_group, + with: locals, + } + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] +pub struct PointLightMatrix([[f32; 4]; 4]); + +impl PointLightMatrix { + pub fn new(shadow_mat: Mat4) -> Self { Self(shadow_mat.into_col_arrays()) } + + pub fn default() -> Self { Self::new(Mat4::identity()) } } pub fn create_col_lights( @@ -109,23 +133,17 @@ impl ShadowFigurePipeline { device: &wgpu::Device, vs_module: &wgpu::ShaderModule, fs_module: &wgpu::ShaderModule, - sc_desc: &wgpu::SwapChainDescriptor, global_layout: &GlobalsLayouts, figure_layout: &FigureLayout, - layout: &ShadowLayout, aa_mode: AaMode, ) -> Self { common::span!(_guard, "new"); - tracing::error!("test"); + let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Shadow figure pipeline layout"), push_constant_ranges: &[], - bind_group_layouts: &[ - &global_layout.globals, - &figure_layout.locals, - &layout.locals, - ], + bind_group_layouts: &[&global_layout.globals, &figure_layout.locals], }); let samples = match aa_mode { @@ -151,7 +169,7 @@ impl ShadowFigurePipeline { front_face: wgpu::FrontFace::Ccw, cull_mode: wgpu::CullMode::Back, polygon_mode: wgpu::PolygonMode::Fill, - clamp_depth: false, + clamp_depth: true, depth_bias: 0, depth_bias_slope_scale: 0.0, depth_bias_clamp: 0.0, @@ -193,21 +211,15 @@ impl ShadowPipeline { device: &wgpu::Device, vs_module: &wgpu::ShaderModule, fs_module: &wgpu::ShaderModule, - sc_desc: &wgpu::SwapChainDescriptor, global_layout: &GlobalsLayouts, terrain_layout: &TerrainLayout, - layout: &ShadowLayout, aa_mode: AaMode, ) -> Self { let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Shadow pipeline layout"), push_constant_ranges: &[], - bind_group_layouts: &[ - &global_layout.globals, - &terrain_layout.locals, - &layout.locals, - ], + bind_group_layouts: &[&global_layout.globals, &terrain_layout.locals], }); let samples = match aa_mode { @@ -233,7 +245,85 @@ impl ShadowPipeline { front_face: wgpu::FrontFace::Ccw, cull_mode: wgpu::CullMode::Back, polygon_mode: wgpu::PolygonMode::Fill, - clamp_depth: false, + clamp_depth: true, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + }), + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: &[], + depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { + format: wgpu::TextureFormat::Depth24Plus, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilStateDescriptor { + front: wgpu::StencilStateFaceDescriptor::IGNORE, + back: wgpu::StencilStateFaceDescriptor::IGNORE, + read_mask: !0, + write_mask: !0, + }, + }), + vertex_state: wgpu::VertexStateDescriptor { + index_format: None, + vertex_buffers: &[TerrainVertex::desc()], + }, + sample_count: samples, + sample_mask: !0, + alpha_to_coverage_enabled: false, + }); + + Self { + pipeline: render_pipeline, + } + } +} +pub struct PointShadowPipeline { + pub pipeline: wgpu::RenderPipeline, +} + +impl PointShadowPipeline { + pub fn new( + device: &wgpu::Device, + vs_module: &wgpu::ShaderModule, + fs_module: &wgpu::ShaderModule, + global_layout: &GlobalsLayouts, + terrain_layout: &TerrainLayout, + aa_mode: AaMode, + ) -> Self { + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Shadow pipeline layout"), + push_constant_ranges: &[wgpu::PushConstantRange { + stages: wgpu::ShaderStage::all(), + range: 0..64, + }], + bind_group_layouts: &[&global_layout.globals, &terrain_layout.locals], + }); + + let samples = match aa_mode { + AaMode::None | AaMode::Fxaa => 1, + // TODO: Ensure sampling in the shader is exactly between the 4 texels + AaMode::MsaaX4 => 4, + AaMode::MsaaX8 => 8, + AaMode::MsaaX16 => 16, + }; + + let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Shadow pipeline"), + layout: Some(&render_pipeline_layout), + vertex_stage: wgpu::ProgrammableStageDescriptor { + module: vs_module, + entry_point: "main", + }, + fragment_stage: Some(wgpu::ProgrammableStageDescriptor { + module: fs_module, + entry_point: "main", + }), + rasterization_state: Some(wgpu::RasterizationStateDescriptor { + front_face: wgpu::FrontFace::Ccw, + cull_mode: wgpu::CullMode::Back, + polygon_mode: wgpu::PolygonMode::Fill, + clamp_depth: true, depth_bias: 0, depth_bias_slope_scale: 0.0, depth_bias_clamp: 0.0, diff --git a/voxygen/src/render/pipelines/skybox.rs b/voxygen/src/render/pipelines/skybox.rs index 0d4415e71b..2369191ccc 100644 --- a/voxygen/src/render/pipelines/skybox.rs +++ b/voxygen/src/render/pipelines/skybox.rs @@ -44,7 +44,7 @@ impl SkyboxPipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Skybox pipeline layout"), push_constant_ranges: &[], - bind_group_layouts: &[&layouts.globals], + bind_group_layouts: &[&layouts.globals, &layouts.shadow_textures], }); let samples = match aa_mode { diff --git a/voxygen/src/render/pipelines/sprite.rs b/voxygen/src/render/pipelines/sprite.rs index 811c13d1b5..01823355d3 100644 --- a/voxygen/src/render/pipelines/sprite.rs +++ b/voxygen/src/render/pipelines/sprite.rs @@ -219,6 +219,7 @@ impl SpritePipeline { push_constant_ranges: &[], bind_group_layouts: &[ &global_layout.globals, + &global_layout.shadow_textures, &terrain_layout.locals, &layout.locals, &global_layout.col_light, diff --git a/voxygen/src/render/pipelines/terrain.rs b/voxygen/src/render/pipelines/terrain.rs index 6061e03db3..752118ac24 100644 --- a/voxygen/src/render/pipelines/terrain.rs +++ b/voxygen/src/render/pipelines/terrain.rs @@ -219,6 +219,7 @@ impl TerrainPipeline { push_constant_ranges: &[], bind_group_layouts: &[ &global_layout.globals, + &global_layout.shadow_textures, &layout.locals, &global_layout.col_light, ], diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index e4019e5b72..654c4b3edb 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -124,7 +124,7 @@ pub struct ShadowMapRenderer { point_depth: Texture, - point_pipeline: shadow::ShadowPipeline, + point_pipeline: shadow::PointShadowPipeline, terrain_directed_pipeline: shadow::ShadowPipeline, figure_directed_pipeline: shadow::ShadowFigurePipeline, layout: shadow::ShadowLayout, @@ -292,12 +292,18 @@ impl Renderer { use wgpu::{Features, Limits}; + let mut limits = Limits::default(); + limits.max_bind_groups = 5; + limits.max_push_constant_size = 64; + let (device, queue) = futures::executor::block_on(adapter.request_device( &wgpu::DeviceDescriptor { // TODO label: None, - features: Features::DEPTH_CLAMPING | Features::ADDRESS_MODE_CLAMP_TO_BORDER, - limits: Limits::default(), + features: Features::DEPTH_CLAMPING + | Features::ADDRESS_MODE_CLAMP_TO_BORDER + | Features::PUSH_CONSTANTS, + limits, shader_validation: true, }, None, @@ -956,33 +962,6 @@ impl Renderer { // } } - // /// Set up shadow rendering. - // pub fn start_shadows(&mut self) { - // if !self.mode.shadow.is_map() { - // return; - // } - // if let Some(_shadow_map) = self.shadow_map.as_mut() { - // self.encoder.flush(&mut self.device); - // Self::set_depth_clamp(&mut self.device, true); - // } - // } - - // /// Perform all queued draw calls for global.shadows. - // pub fn flush_shadows(&mut self) { - // if !self.mode.shadow.is_map() { - // return; - // } - // if let Some(_shadow_map) = self.shadow_map.as_mut() { - // let point_encoder = &mut self.encoder; - // // let point_encoder = &mut shadow_map.point_encoder; - // point_encoder.flush(&mut self.device); - // // let directed_encoder = &mut shadow_map.directed_encoder; - // // directed_encoder.flush(&mut self.device); - // // Reset depth clamping. - // Self::set_depth_clamp(&mut self.device, false); - // } - // } - /// Start recording the frame /// When the returned `Drawer` is dropped the recorded draw calls will be /// submitted to the queue @@ -2023,7 +2002,7 @@ fn create_pipelines( clouds::CloudsPipeline, postprocess::PostProcessPipeline, //figure::FigurePipeline, - Option, + Option, Option, Option, ), @@ -2278,77 +2257,35 @@ fn create_pipelines( // gfx::state::CullFace::Back, // )?; - // Sharp can fix it later ;) - // - // // Construct a pipeline for rendering point light terrain shadow maps. - // let point_shadow_pipeline = match create_shadow_pipeline( - // factory, - // shadow::pipe::new(), - // &terrain_point_shadow_vert, - // Some( - // &Glsl::load_watched( - // "voxygen.shaders.light-shadows-geom", - // shader_reload_indicator, - // ) - // .unwrap(), - // ), - // &Glsl::load_watched( - // "voxygen.shaders.light-shadows-frag", - // shader_reload_indicator, - // ) - // .unwrap(), - // &include_ctx, - // gfx::state::CullFace::Back, - // None, // Some(gfx::state::Offset(2, 0)) - // ) { - // Ok(pipe) => Some(pipe), - // Err(err) => { - // warn!("Could not load point shadow map pipeline: {:?}", err); - // None - // }, - // }; + // Construct a pipeline for rendering point light terrain shadow maps. + let point_shadow_pipeline = shadow::PointShadowPipeline::new( + device, + &create_shader("point-light-shadows-vert", ShaderKind::Vertex)?, + &create_shader("light-shadows-frag", ShaderKind::Fragment)?, + &layouts.global, + &layouts.terrain, + mode.aa, + ); - // // Construct a pipeline for rendering directional light terrain shadow maps. - // let terrain_directed_shadow_pipeline = match create_shadow_pipeline( - // factory, - // shadow::pipe::new(), - // &terrain_directed_shadow_vert, - // None, - // &directed_shadow_frag, - // &include_ctx, - // gfx::state::CullFace::Back, - // None, // Some(gfx::state::Offset(2, 1)) - // ) { - // Ok(pipe) => Some(pipe), - // Err(err) => { - // warn!( - // "Could not load directed terrain shadow map pipeline: {:?}", - // err - // ); - // None - // }, - // }; + // Construct a pipeline for rendering directional light terrain shadow maps. + let terrain_directed_shadow_pipeline = shadow::ShadowPipeline::new( + device, + &terrain_directed_shadow_vert_mod, + &directed_shadow_frag_mod, + &layouts.global, + &layouts.terrain, + mode.aa, + ); - // // Construct a pipeline for rendering directional light figure shadow maps. - // let figure_directed_shadow_pipeline = match create_shadow_pipeline( - // factory, - // shadow::figure_pipe::new(), - // &figure_directed_shadow_vert, - // None, - // &directed_shadow_frag, - // &include_ctx, - // gfx::state::CullFace::Back, - // None, // Some(gfx::state::Offset(2, 1)) - // ) { - // Ok(pipe) => Some(pipe), - // Err(err) => { - // warn!( - // "Could not load directed figure shadow map pipeline: {:?}", - // err - // ); - // None - // }, - // }; + // Construct a pipeline for rendering directional light figure shadow maps. + let figure_directed_shadow_pipeline = shadow::ShadowFigurePipeline::new( + device, + &figure_directed_shadow_vert_mod, + &directed_shadow_frag_mod, + &layouts.global, + &layouts.figure, + mode.aa, + ); Ok(( skybox_pipeline, @@ -2362,9 +2299,9 @@ fn create_pipelines( clouds_pipeline, postprocess_pipeline, // player_shadow_pipeline, - None, - None, - None, + Some(point_shadow_pipeline), + Some(terrain_directed_shadow_pipeline), + Some(figure_directed_shadow_pipeline), )) } diff --git a/voxygen/src/render/renderer/binding.rs b/voxygen/src/render/renderer/binding.rs index 2ae1ffa8c0..33f4d61cb1 100644 --- a/voxygen/src/render/renderer/binding.rs +++ b/voxygen/src/render/renderer/binding.rs @@ -1,7 +1,7 @@ use super::{ super::{ pipelines::{ - figure, fluid, lod_terrain, sprite, terrain, ui, ColLights, GlobalModel, + figure, fluid, lod_terrain, shadow, sprite, terrain, ui, ColLights, GlobalModel, GlobalsBindGroup, }, texture::Texture, @@ -59,6 +59,11 @@ impl Renderer { self.layouts.terrain.bind_locals(&self.device, locals) } + pub fn create_shadow_bound_locals(&mut self, locals: &[shadow::Locals]) -> shadow::BoundLocals { + let locals = self.create_consts(locals); + self.layouts.shadow.bind_locals(&self.device, locals) + } + pub fn create_sprite_bound_locals(&mut self, locals: &[sprite::Locals]) -> sprite::BoundLocals { let locals = self.create_consts(locals); self.layouts.sprite.bind_locals(&self.device, locals) diff --git a/voxygen/src/render/renderer/drawer.rs b/voxygen/src/render/renderer/drawer.rs index ab758410de..b164430dc1 100644 --- a/voxygen/src/render/renderer/drawer.rs +++ b/voxygen/src/render/renderer/drawer.rs @@ -5,18 +5,18 @@ use super::{ instances::Instances, model::{DynamicModel, Model, SubModel}, pipelines::{ - clouds, figure, fluid, lod_terrain, particle, postprocess, skybox, sprite, terrain, ui, - ColLights, GlobalsBindGroup, Light, Shadow, + clouds, figure, fluid, lod_terrain, particle, postprocess, shadow, skybox, sprite, + terrain, ui, ColLights, GlobalsBindGroup, Light, Shadow, }, }, - Renderer, + Renderer, ShadowMapRenderer, }; -use std::ops::Range; +use std::{ops::Range}; use vek::Aabr; pub struct Drawer<'a> { encoder: Option, - renderer: &'a mut Renderer, + pub renderer: &'a mut Renderer, tex: wgpu::SwapChainTexture, globals: &'a GlobalsBindGroup, } @@ -63,6 +63,7 @@ impl<'a> Drawer<'a> { }); render_pass.set_bind_group(0, &self.globals.bind_group, &[]); + render_pass.set_bind_group(1, &self.globals.shadow_textures, &[]); FirstPassDrawer { render_pass, @@ -70,6 +71,38 @@ impl<'a> Drawer<'a> { } } + pub fn shadow_pass(&mut self) -> Option { + if let Some(ref shadow_renderer) = self.renderer.shadow_map { + let mut render_pass = + self.encoder + .as_mut() + .unwrap() + .begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[], + depth_stencil_attachment: Some( + wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &shadow_renderer.directed_depth.view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: true, + }), + stencil_ops: None, + }, + ), + }); + + render_pass.set_bind_group(0, &self.globals.bind_group, &[]); + + Some(ShadowDrawer { + render_pass, + renderer: &self.renderer, + shadow_renderer, + }) + } else { + None + } + } + pub fn second_pass(&mut self) -> SecondPassDrawer { let mut render_pass = self.encoder @@ -88,6 +121,7 @@ impl<'a> Drawer<'a> { }); render_pass.set_bind_group(0, &self.globals.bind_group, &[]); + render_pass.set_bind_group(1, &self.globals.shadow_textures, &[]); SecondPassDrawer { render_pass, @@ -119,6 +153,68 @@ impl<'a> Drawer<'a> { renderer: &self.renderer, } } + + pub fn draw_point_shadow<'b: 'a>( + &mut self, + model: &'b Model, + locals: &'b terrain::BoundLocals, + matrices: &[shadow::PointLightMatrix; 126], + ) { + if let Some(ref shadow_renderer) = self.renderer.shadow_map { + const STRIDE: usize = std::mem::size_of::(); + let data = bytemuck::cast_slice(matrices); + + for face in 0..6 { + let view = + shadow_renderer + .point_depth + .tex + .create_view(&wgpu::TextureViewDescriptor { + label: Some("Point shadow cubemap face"), + format: None, + dimension: Some(wgpu::TextureViewDimension::D2Array), + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + level_count: None, + base_array_layer: face, + array_layer_count: None, + }); + + let mut render_pass = + self.encoder + .as_mut() + .unwrap() + .begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[], + depth_stencil_attachment: Some( + wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: true, + }), + stencil_ops: None, + }, + ), + }); + + render_pass.set_pipeline(&shadow_renderer.point_pipeline.pipeline); + render_pass.set_bind_group(0, &self.globals.bind_group, &[]); + render_pass.set_bind_group(1, &locals.bind_group, &[]); + render_pass.set_vertex_buffer(0, model.buf().slice(..)); + + for point_light in 0..20 { + render_pass.set_push_constants( + wgpu::ShaderStage::all(), + 0, + &data[(6 * point_light * STRIDE + face as usize * STRIDE) + ..(6 * point_light * STRIDE + (face + 1) as usize * STRIDE)], + ); + render_pass.draw(0..model.len() as u32, 0..1); + } + } + } + } } impl<'a> Drop for Drawer<'a> { @@ -159,9 +255,9 @@ impl<'a> FirstPassDrawer<'a> { ) { self.render_pass .set_pipeline(&self.renderer.figure_pipeline.pipeline); - self.render_pass.set_bind_group(1, &locals.bind_group, &[]); + self.render_pass.set_bind_group(2, &locals.bind_group, &[]); self.render_pass - .set_bind_group(2, &col_lights.bind_group, &[]); + .set_bind_group(3, &col_lights.bind_group, &[]); self.render_pass.set_vertex_buffer(0, model.buf()); self.render_pass.draw(0..model.len(), 0..1); } @@ -174,9 +270,9 @@ impl<'a> FirstPassDrawer<'a> { ) { self.render_pass .set_pipeline(&self.renderer.terrain_pipeline.pipeline); - self.render_pass.set_bind_group(1, &locals.bind_group, &[]); + self.render_pass.set_bind_group(2, &locals.bind_group, &[]); self.render_pass - .set_bind_group(2, &col_lights.bind_group, &[]); + .set_bind_group(3, &col_lights.bind_group, &[]); self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); self.render_pass.draw(0..model.len() as u32, 0..1) } @@ -201,10 +297,10 @@ impl<'a> FirstPassDrawer<'a> { self.render_pass .set_pipeline(&self.renderer.sprite_pipeline.pipeline); self.render_pass - .set_bind_group(1, &terrain_locals.bind_group, &[]); - self.render_pass.set_bind_group(2, &locals.bind_group, &[]); + .set_bind_group(2, &terrain_locals.bind_group, &[]); + self.render_pass.set_bind_group(3, &locals.bind_group, &[]); self.render_pass - .set_bind_group(3, &col_lights.bind_group, &[]); + .set_bind_group(4, &col_lights.bind_group, &[]); self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); self.render_pass .set_vertex_buffer(1, instances.buf().slice(..)); @@ -215,7 +311,7 @@ impl<'a> FirstPassDrawer<'a> { pub fn draw_fluid<'b: 'a>(&mut self, waves: &'b fluid::BindGroup) -> FluidDrawer<'_, 'a> { self.render_pass .set_pipeline(&self.renderer.fluid_pipeline.pipeline); - self.render_pass.set_bind_group(1, &waves.bind_group, &[]); + self.render_pass.set_bind_group(2, &waves.bind_group, &[]); FluidDrawer { render_pass: &mut self.render_pass, @@ -244,6 +340,38 @@ impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> { } } +pub struct ShadowDrawer<'pass> { + render_pass: wgpu::RenderPass<'pass>, + pub renderer: &'pass Renderer, + shadow_renderer: &'pass ShadowMapRenderer, +} + +impl<'pass> ShadowDrawer<'pass> { + pub fn draw_figure_shadow<'b: 'pass>( + &mut self, + model: SubModel<'b, terrain::Vertex>, + locals: &'b figure::BoundLocals, + ) { + self.render_pass + .set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline); + self.render_pass.set_bind_group(1, &locals.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, model.buf()); + self.render_pass.draw(0..model.len(), 0..1); + } + + pub fn draw_terrain_shadow<'b: 'pass>( + &mut self, + model: &'b Model, + locals: &'b terrain::BoundLocals, + ) { + self.render_pass + .set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline); + self.render_pass.set_bind_group(1, &locals.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); + self.render_pass.draw(0..model.len() as u32, 0..1); + } +} + pub struct FluidDrawer<'pass_ref, 'pass: 'pass_ref> { render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, } @@ -255,7 +383,7 @@ impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> { locals: &'data terrain::BoundLocals, ) { self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); - self.render_pass.set_bind_group(2, &locals.bind_group, &[]); + self.render_pass.set_bind_group(3, &locals.bind_group, &[]); self.render_pass.draw(0..model.len() as u32, 0..1); } } @@ -270,7 +398,7 @@ impl<'a> SecondPassDrawer<'a> { self.render_pass .set_pipeline(&self.renderer.clouds_pipeline.pipeline); self.render_pass - .set_bind_group(1, &self.renderer.locals.clouds_bind.bind_group, &[]); + .set_bind_group(2, &self.renderer.locals.clouds_bind.bind_group, &[]); self.render_pass.draw(0..3, 0..1); } } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 95d7633f68..009d9d52b5 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -9,7 +9,7 @@ use crate::{ render::{ pipelines::{self, ColLights}, ColLightInfo, FigureBoneData, FigureLocals, FigureModel, FirstPassDrawer, GlobalModel, - LodData, Mesh, RenderError, Renderer, SubModel, TerrainVertex, + LodData, Mesh, RenderError, Renderer, ShadowDrawer, SubModel, TerrainVertex, }, scene::{ camera::{Camera, CameraMode, Dependents}, @@ -4706,20 +4706,17 @@ impl FigureMgr { visible_aabb } - pub fn render_shadows( - &self, - renderer: &mut Renderer, + pub fn render_shadows<'a>( + &'a self, + drawer: &mut ShadowDrawer<'a>, state: &State, tick: u64, - global: &GlobalModel, - (is_daylight, _light_data): super::LightData, (camera, figure_lod_render_distance): CameraData, ) { span!(_guard, "render_shadows", "FigureManager::render_shadows"); let ecs = state.ecs(); - if is_daylight && renderer.render_mode().shadow.is_map() { - ( + ( &ecs.entities(), &ecs.read_storage::(), ecs.read_storage::().maybe(), @@ -4744,17 +4741,9 @@ impl FigureMgr { figure_lod_render_distance * scale.map_or(1.0, |s| s.0), |state| state.can_shadow_sun(), ) { - // TODO - //renderer.render_figure_shadow_directed( - // model, - // global, - // locals, - // bone_consts, - // &global.shadow_mats, - //); + drawer.draw_figure_shadow(model, bound); } }); - } } #[allow(clippy::too_many_arguments)] // TODO: Pending review in #587 diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 080243eb1b..f4a28084c3 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -16,9 +16,9 @@ pub use self::{ use crate::{ audio::{ambient::AmbientMgr, music::MusicMgr, sfx::SfxMgr, AudioFrontend}, render::{ - create_skybox_mesh, CloudsLocals, Consts, FirstPassDrawer, GlobalModel, Globals, - GlobalsBindGroup, Light, Model, PostProcessLocals, Renderer, Shadow, ShadowLocals, - SkyboxVertex, + create_skybox_mesh, CloudsLocals, Consts, Drawer, FirstPassDrawer, GlobalModel, Globals, + GlobalsBindGroup, Light, Model, PointLightMatrix, PostProcessLocals, Renderer, Shadow, + ShadowDrawer, ShadowLocals, SkyboxVertex, }, settings::Settings, window::{AnalogGameInput, Event}, @@ -268,8 +268,8 @@ impl Scene { globals: renderer.create_consts(&[Globals::default()]), lights: renderer.create_consts(&[Light::default(); MAX_LIGHT_COUNT]), shadows: renderer.create_consts(&[Shadow::default(); MAX_SHADOW_COUNT]), - shadow_mats: renderer - .create_consts(&[ShadowLocals::default(); MAX_LIGHT_COUNT * 6 + 6]), + shadow_mats: renderer.create_shadow_bound_locals(&[ShadowLocals::default()]), + point_light_matrices: Box::new([PointLightMatrix::default(); MAX_LIGHT_COUNT * 6 + 6]), }; let lod = Lod::new(renderer, client, settings); @@ -707,11 +707,200 @@ impl Scene { let new_dir = math::Vec3::from(view_dir); let new_dir = new_dir.normalized(); let up: math::Vec3 = math::Vec3::unit_y(); - directed_shadow_mats.push(math::Mat4::look_at_rh( - look_at, - look_at + directed_light_dir, - up, - )); + let light_view_mat = math::Mat4::look_at_rh(look_at, look_at + directed_light_dir, up); + { + let v_p_orig = + math::Vec3::from(light_view_mat * math::Vec4::from_direction(new_dir)); + let mut v_p = v_p_orig.normalized(); + let cos_gamma = new_dir + .map(f64::from) + .dot(directed_light_dir.map(f64::from)); + let sin_gamma = (1.0 - cos_gamma * cos_gamma).sqrt(); + let gamma = sin_gamma.asin(); + let view_mat = math::Mat4::from_col_array(view_mat.into_col_array()); + let bounds1 = math::fit_psr( + view_mat.map_cols(math::Vec4::from), + visible_light_volume.iter().copied(), + math::Vec4::homogenized, + ); + let n_e = f64::from(-bounds1.max.z); + let factor = compute_warping_parameter_perspective( + gamma, + n_e, + f64::from(fov), + f64::from(aspect_ratio), + ); + + v_p.z = 0.0; + v_p.normalize(); + let l_r: math::Mat4 = if factor > EPSILON_UPSILON { + math::Mat4::look_at_rh(math::Vec3::zero(), -math::Vec3::unit_z(), v_p) + } else { + math::Mat4::identity() + }; + let directed_proj_mat = math::Mat4::new( + 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, + ); + + let light_all_mat = l_r * directed_proj_mat * light_view_mat; + let bounds0 = math::fit_psr( + light_all_mat, + visible_light_volume.iter().copied(), + math::Vec4::homogenized, + ); + // Vague idea: project z_n from the camera view to the light view (where it's + // tilted by γ). + let (z_0, z_1) = { + let p_z = bounds1.max.z; + let p_y = bounds0.min.y; + let p_x = bounds0.center().x; + let view_inv = view_mat.inverted(); + let light_all_inv = light_all_mat.inverted(); + + let view_point = view_inv * math::Vec4::new(0.0, 0.0, p_z, 1.0); + let view_plane = view_inv * math::Vec4::from_direction(math::Vec3::unit_z()); + + let light_point = light_all_inv * math::Vec4::new(0.0, p_y, 0.0, 1.0); + let light_plane = + light_all_inv * math::Vec4::from_direction(math::Vec3::unit_y()); + + let shadow_point = light_all_inv * math::Vec4::new(p_x, 0.0, 0.0, 1.0); + let shadow_plane = + light_all_inv * math::Vec4::from_direction(math::Vec3::unit_x()); + + let solve_p0 = math::Mat4::new( + view_plane.x, + view_plane.y, + view_plane.z, + -view_plane.dot(view_point), + light_plane.x, + light_plane.y, + light_plane.z, + -light_plane.dot(light_point), + shadow_plane.x, + shadow_plane.y, + shadow_plane.z, + -shadow_plane.dot(shadow_point), + 0.0, + 0.0, + 0.0, + 1.0, + ); + + let p0_world = solve_p0.inverted() * math::Vec4::unit_w(); + let p0 = light_all_mat * p0_world; + let mut p1 = p0; + p1.y = bounds0.max.y; + + let view_from_light_mat = view_mat * light_all_inv; + let z0 = view_from_light_mat * p0; + let z1 = view_from_light_mat * p1; + + (f64::from(z0.z), f64::from(z1.z)) + }; + + let mut light_focus_pos: math::Vec3 = math::Vec3::zero(); + light_focus_pos.x = bounds0.center().x; + light_focus_pos.y = bounds0.min.y; + light_focus_pos.z = bounds0.center().z; + + let d = f64::from(bounds0.max.y - bounds0.min.y).abs(); + + let w_l_y = d; + + // NOTE: See section 5.1.2.2 of Lloyd's thesis. + let alpha = z_1 / z_0; + let alpha_sqrt = alpha.sqrt(); + let directed_near_normal = if factor < 0.0 { + // Standard shadow map to LiSPSM + (1.0 + alpha_sqrt - factor * (alpha - 1.0)) / ((alpha - 1.0) * (factor + 1.0)) + } else { + // LiSPSM to PSM + ((alpha_sqrt - 1.0) * (factor * alpha_sqrt + 1.0)).recip() + }; + + // Equation 5.14 - 5.16 + let y_ = |v: f64| w_l_y * (v + directed_near_normal).abs(); + let directed_near = y_(0.0) as f32; + let directed_far = y_(1.0) as f32; + light_focus_pos.y = if factor > EPSILON_UPSILON { + light_focus_pos.y - directed_near + } else { + light_focus_pos.y + }; + let w_v: math::Mat4 = math::Mat4::translation_3d(-math::Vec3::new( + light_focus_pos.x, + light_focus_pos.y, + light_focus_pos.z, + )); + let shadow_view_mat: math::Mat4 = w_v * light_all_mat; + let w_p: math::Mat4 = { + if factor > EPSILON_UPSILON { + // Projection for y + let near = directed_near; + let far = directed_far; + let left = -1.0; + let right = 1.0; + let bottom = -1.0; + let top = 1.0; + let s_x = 2.0 * near / (right - left); + let o_x = (right + left) / (right - left); + let s_z = 2.0 * near / (top - bottom); + let o_z = (top + bottom) / (top - bottom); + + let s_y = (far + near) / (far - near); + let o_y = -2.0 * far * near / (far - near); + + math::Mat4::new( + s_x, o_x, 0.0, 0.0, 0.0, s_y, 0.0, o_y, 0.0, o_z, s_z, 0.0, 0.0, 1.0, + 0.0, 0.0, + ) + } else { + math::Mat4::identity() + } + }; + + let shadow_all_mat: math::Mat4 = w_p * shadow_view_mat; + let math::Aabb:: { + min: + math::Vec3 { + x: xmin, + y: ymin, + z: zmin, + }, + max: + math::Vec3 { + x: xmax, + y: ymax, + z: zmax, + }, + } = math::fit_psr( + shadow_all_mat, + visible_light_volume.iter().copied(), + math::Vec4::homogenized, + ); + let s_x = 2.0 / (xmax - xmin); + let s_y = 2.0 / (ymax - ymin); + let s_z = 2.0 / (zmax - zmin); + let o_x = -(xmax + xmin) / (xmax - xmin); + let o_y = -(ymax + ymin) / (ymax - ymin); + let o_z = -(zmax + zmin) / (zmax - zmin); + let directed_proj_mat = Mat4::new( + s_x, 0.0, 0.0, o_x, 0.0, s_y, 0.0, o_y, 0.0, 0.0, s_z, o_z, 0.0, 0.0, 0.0, 1.0, + ); + + let shadow_all_mat: Mat4 = + Mat4::from_col_arrays(shadow_all_mat.into_col_arrays()); + + let directed_texture_proj_mat = texture_mat * directed_proj_mat; + let shadow_locals = ShadowLocals::new( + directed_proj_mat * shadow_all_mat, + directed_texture_proj_mat * shadow_all_mat, + ); + + renderer.update_consts(&mut self.data.shadow_mats, &[shadow_locals]); + } + directed_shadow_mats.push(light_view_mat); // This leaves us with five dummy slots, which we push as defaults. directed_shadow_mats .extend_from_slice(&[math::Mat4::default(); 6 - NUM_DIRECTED_LIGHTS] as _); @@ -721,7 +910,7 @@ impl Scene { shadow_mats.extend(directed_shadow_mats.iter().enumerate().map( move |(idx, &light_view_mat)| { if idx >= NUM_DIRECTED_LIGHTS { - return ShadowLocals::new(Mat4::identity(), Mat4::identity()); + return PointLightMatrix::new(Mat4::identity()); } let v_p_orig = @@ -911,17 +1100,13 @@ impl Scene { let shadow_all_mat: Mat4 = Mat4::from_col_arrays(shadow_all_mat.into_col_arrays()); - let directed_texture_proj_mat = texture_mat * directed_proj_mat; - ShadowLocals::new( - directed_proj_mat * shadow_all_mat, - directed_texture_proj_mat * shadow_all_mat, - ) + PointLightMatrix::new(directed_proj_mat * shadow_all_mat) }, )); // Now, we tackle point lights. // First, create a perspective projection matrix at 90 degrees (to cover a whole // face of the cube map we're using). - let shadow_proj = Mat4::perspective_rh_no( + let shadow_proj = Mat4::perspective_rh_zo( 90.0f32.to_radians(), point_shadow_aspect, SHADOW_NEAR, @@ -947,14 +1132,13 @@ impl Scene { orientations.iter().map(move |&(forward, up)| { // NOTE: We don't currently try to linearize point lights or need a separate // transform for them. - ShadowLocals::new( - shadow_proj * Mat4::look_at_rh(eye, eye + forward, up), - Mat4::identity(), - ) + PointLightMatrix::new(shadow_proj * Mat4::look_at_rh(eye, eye + forward, up)) }) })); - renderer.update_consts(&mut self.data.shadow_mats, &shadow_mats); + for (i, val) in shadow_mats.into_iter().enumerate() { + self.data.point_light_matrices[i] = val + } } // Remove unused figures. @@ -976,7 +1160,87 @@ impl Scene { pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.globals_bind_group } - /// Render the scene using the provided `Renderer`. + pub fn render_terrain_shadows<'a>( + &'a self, + drawer: &mut ShadowDrawer<'a>, + state: &State, + player_entity: EcsEntity, + tick: u64, + scene_data: &SceneData, + ) { + let sun_dir = scene_data.get_sun_dir(); + let is_daylight = sun_dir.z < 0.0; + let focus_pos = self.camera.get_focus_pos(); + let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc()); + + let global = &self.data; + let light_data = (is_daylight, &*self.light_data); + let camera_data = (&self.camera, scene_data.figure_lod_render_distance); + + // would instead have this as an extension. + if drawer.renderer.render_mode().shadow.is_map() + && (is_daylight || !light_data.1.is_empty()) + { + // Render terrain shadows. + self.terrain + .render_shadows(drawer, global, light_data, focus_pos); + } + } + + pub fn render_point_shadows<'a>( + &'a self, + drawer: &mut Drawer<'a>, + state: &State, + player_entity: EcsEntity, + tick: u64, + scene_data: &SceneData, + ) { + let sun_dir = scene_data.get_sun_dir(); + let is_daylight = sun_dir.z < 0.0; + let focus_pos = self.camera.get_focus_pos(); + let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc()); + + let global = &self.data; + let light_data = (is_daylight, &*self.light_data); + let camera_data = (&self.camera, scene_data.figure_lod_render_distance); + + if drawer.renderer.render_mode().shadow.is_map() + && (is_daylight || !light_data.1.is_empty()) + { + // Render terrain shadows. + self.terrain + .render_point_shadows(drawer, global, light_data, focus_pos); + } + } + + pub fn render_figure_shadows<'a>( + &'a self, + drawer: &mut ShadowDrawer<'a>, + state: &State, + player_entity: EcsEntity, + tick: u64, + scene_data: &SceneData, + ) { + let sun_dir = scene_data.get_sun_dir(); + let is_daylight = sun_dir.z < 0.0; + let focus_pos = self.camera.get_focus_pos(); + let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc()); + + let global = &self.data; + let light_data = (is_daylight, &*self.light_data); + let camera_data = (&self.camera, scene_data.figure_lod_render_distance); + + // would instead have this as an extension. + if drawer.renderer.render_mode().shadow.is_map() + && (is_daylight || !light_data.1.is_empty()) + { + // Render figure shadows. + self.figure_mgr + .render_shadows(drawer, state, tick, camera_data); + } + } + + /// Render the scene using the provided `FirstPassDrawer`. pub fn render<'a>( &'a self, drawer: &mut FirstPassDrawer<'a>, @@ -992,29 +1256,8 @@ impl Scene { let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc()); let global = &self.data; - let light_data = (is_daylight, &*self.light_data); let camera_data = (&self.camera, scene_data.figure_lod_render_distance); - // would instead have this as an extension. - /*if renderer.render_mode().shadow.is_map() && (is_daylight || !light_data.1.is_empty()) { - // if is_daylight { - // // Set up shadow mapping. - // renderer.start_shadows(); - // } - - // Render terrain shadows. - self.terrain - .render_shadows(renderer, global, light_data, focus_pos); - - // Render figure shadows. - self.figure_mgr - .render_shadows(renderer, state, tick, global, light_data, camera_data); - - // if is_daylight { - // // Flush shadows. - // renderer.flush_shadows(); - // } - }*/ let lod = self.lod.get_data(); self.figure_mgr diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 7859a64c8b..2bcf5d893e 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -2,8 +2,8 @@ use crate::{ mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_terrain}, render::{ create_skybox_mesh, BoneMeshes, Consts, FigureModel, FirstPassDrawer, GlobalModel, Globals, - GlobalsBindGroup, Light, LodData, Mesh, Model, Renderer, Shadow, ShadowLocals, - SkyboxVertex, TerrainVertex, + GlobalsBindGroup, Light, LodData, Mesh, Model, PointLightMatrix, Renderer, Shadow, + ShadowLocals, SkyboxVertex, TerrainVertex, }, scene::{ camera::{self, Camera, CameraMode}, @@ -109,7 +109,8 @@ impl Scene { globals: renderer.create_consts(&[Globals::default()]), lights: renderer.create_consts(&[Light::default(); 20]), shadows: renderer.create_consts(&[Shadow::default(); 24]), - shadow_mats: renderer.create_consts(&[ShadowLocals::default(); 6]), + shadow_mats: renderer.create_shadow_bound_locals(&[ShadowLocals::default()]), + point_light_matrices: Box::new([PointLightMatrix::default(); 126]), }; let lod = LodData::dummy(renderer); diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 07e8fb4b7a..017c9c2d5c 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -9,9 +9,9 @@ use crate::{ }, render::{ pipelines::{self, ColLights}, - ColLightInfo, Consts, FirstPassDrawer, FluidVertex, FluidWaves, GlobalModel, Instances, - LodData, Mesh, Model, RenderError, Renderer, SpriteInstance, SpriteLocals, SpriteVertex, - TerrainLocals, TerrainVertex, Texture, + ColLightInfo, Consts, Drawer, FirstPassDrawer, FluidVertex, FluidWaves, GlobalModel, + Instances, LodData, Mesh, Model, RenderError, Renderer, ShadowDrawer, SpriteInstance, + SpriteLocals, SpriteVertex, TerrainLocals, TerrainVertex, Texture, }, }; @@ -1397,18 +1397,14 @@ impl Terrain { pub fn shadow_chunk_count(&self) -> usize { self.shadow_chunks.len() } - pub fn render_shadows( - &self, - renderer: &mut Renderer, + pub fn render_shadows<'a>( + &'a self, + drawer: &mut ShadowDrawer<'a>, global: &GlobalModel, (is_daylight, light_data): super::LightData, focus_pos: Vec3, ) { span!(_guard, "render_shadows", "Terrain::render_shadows"); - if !renderer.render_mode().shadow.is_map() { - return; - }; - let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| { (e as i32).div_euclid(sz as i32) }); @@ -1430,16 +1426,27 @@ impl Terrain { .clone() .filter(|chunk| chunk.can_shadow_sun()) .chain(self.shadow_chunks.iter().map(|(_, chunk)| chunk)) - .for_each(|chunk| { - // Directed light shadows. - /*renderer.render_terrain_shadow_directed( - &chunk.opaque_model, - global, - &chunk.locals, - &global.shadow_mats, - );*/ - }); + .for_each(|chunk| drawer.draw_terrain_shadow(&chunk.opaque_model, &chunk.locals)); } + } + + pub fn render_point_shadows<'a>( + &'a self, + drawer: &mut Drawer<'a>, + global: &GlobalModel, + (is_daylight, light_data): super::LightData, + focus_pos: Vec3, + ) { + let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| { + (e as i32).div_euclid(sz as i32) + }); + + let chunk_iter = Spiral2d::new() + .filter_map(|rpos| { + let pos = focus_chunk + rpos; + self.chunks.get(&pos) + }) + .take(self.chunks.len()); // Point shadows // @@ -1448,12 +1455,11 @@ impl Terrain { light_data.iter().take(1).for_each(|_light| { chunk_iter.clone().for_each(|chunk| { if chunk.can_shadow_point { - /*renderer.render_shadow_point( + drawer.draw_point_shadow( &chunk.opaque_model, - global, &chunk.locals, - &global.shadow_mats, - );*/ + &global.point_light_matrices, + ); } }); }); diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index b3dcdd5a0a..95651f3770 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -1418,6 +1418,33 @@ impl PlayState for SessionState { particles_enabled: settings.graphics.particles_enabled, is_aiming: self.is_aiming, }; + drawer.shadow_pass().map(|mut drawer| { + self.scene.render_terrain_shadows( + &mut drawer, + client.state(), + client.entity(), + client.get_tick(), + &scene_data, + ); + }); + + self.scene.render_point_shadows( + &mut drawer, + client.state(), + client.entity(), + client.get_tick(), + &scene_data, + ); + + drawer.shadow_pass().map(|mut drawer| { + self.scene.render_figure_shadows( + &mut drawer, + client.state(), + client.entity(), + client.get_tick(), + &scene_data, + ); + }); self.scene.render( &mut drawer.first_pass(), client.state(),