Fix the shadow drawing code

Very poorly optimized
This commit is contained in:
Capucho 2020-12-08 18:02:08 +00:00 committed by Avi Weinstock
parent 4941736cec
commit bbbe4ea368
35 changed files with 884 additions and 359 deletions

View File

@ -22,19 +22,19 @@
#include <srgb.glsl>
#include <cloud.glsl>
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;

View File

@ -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];
};

View File

@ -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];

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -22,7 +22,13 @@
// Currently, we only need globals for focus_off.
#include <globals.glsl>
// For shadow locals.
#include <shadows.glsl>
// #include <shadows.glsl>
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;

View File

@ -24,7 +24,13 @@
// Currently, we only need globals for focus_off.
#include <globals.glsl>
// For shadow locals.
#include <shadows.glsl>
// #include <shadows.glsl>
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
}

View File

@ -0,0 +1,60 @@
#version 330 core
// #extension ARB_texture_storage : enable
#include <constants.glsl>
#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 <globals.glsl>
/* 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);
}

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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,
},

View File

@ -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 {

View File

@ -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,
],

View File

@ -128,6 +128,7 @@ impl FluidPipeline {
push_constant_ranges: &[],
bind_group_layouts: &[
&global_layout.globals,
&global_layout.shadow_textures,
&layout.waves,
&terrain_layout.locals,
],

View File

@ -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 {

View File

@ -229,16 +229,19 @@ pub struct GlobalModel {
pub globals: Consts<Globals>,
pub lights: Consts<Light>,
pub shadows: Consts<Shadow>,
pub shadow_mats: Consts<shadow::Locals>,
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<Locals> {
@ -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<Locals>(

View File

@ -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 {

View File

@ -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,9 +21,18 @@ 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 {
pub type BoundLocals = Bound<Consts<Locals>>;
pub struct ShadowLayout {
pub locals: wgpu::BindGroupLayout,
}
impl ShadowLayout {
pub fn new(device: &wgpu::Device) -> Self {
Self {
locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None,
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
@ -35,20 +44,35 @@ impl Locals {
},
count: None,
}],
})
}),
}
}
pub fn bind_locals(&self, device: &wgpu::Device, locals: Consts<Locals>) -> 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,
}
}
}
pub struct ShadowLayout {
pub locals: wgpu::BindGroupLayout,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
pub struct PointLightMatrix([[f32; 4]; 4]);
impl ShadowLayout {
pub fn new(device: &wgpu::Device) -> Self {
Self {
locals: Locals::layout(device),
}
}
impl PointLightMatrix {
pub fn new(shadow_mat: Mat4<f32>) -> 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,

View File

@ -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 {

View File

@ -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,

View File

@ -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,
],

View File

@ -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<shadow::ShadowPipeline>,
Option<shadow::PointShadowPipeline>,
Option<shadow::ShadowPipeline>,
Option<shadow::ShadowFigurePipeline>,
),
@ -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),
))
}

View File

@ -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)

View File

@ -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<wgpu::CommandEncoder>,
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<ShadowDrawer> {
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<terrain::Vertex>,
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::<shadow::PointLightMatrix>();
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<terrain::Vertex>,
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);
}
}

View File

@ -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,19 +4706,16 @@ 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::<Pos>(),
@ -4744,18 +4741,10 @@ 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
pub fn render<'a>(

View File

@ -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<f32> = 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<f32> = 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<f32> = 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<f32> = 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<f32> = w_v * light_all_mat;
let w_p: math::Mat4<f32> = {
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<f32> = w_p * shadow_view_mat;
let math::Aabb::<f32> {
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<f32> =
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<f32> =
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

View File

@ -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);

View File

@ -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<V: RectRasterableVol> Terrain<V> {
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<f32>,
) {
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<V: RectRasterableVol> Terrain<V> {
.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<f32>,
) {
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<V: RectRasterableVol> Terrain<V> {
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,
);
}
});
});

View File

@ -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(),