Implement Shadows #24

Merged
SeanOMik merged 28 commits from feat/shadow-maps into main 2024-08-10 03:10:30 +00:00
1 changed files with 79 additions and 48 deletions
Showing only changes of commit 7b2d2424a3 - Show all commits

View File

@ -8,9 +8,12 @@ use tracing::{debug, warn};
use wgpu::util::DeviceExt;
use crate::render::{
graph::{Node, NodeDesc, NodeType},
graph::{Node, NodeDesc, NodeType, SlotAttribute, SlotValue},
light::directional::DirectionalLight,
resource::{FragmentState, PipelineDescriptor, RenderPipeline, RenderPipelineDescriptor, Shader, VertexState},
resource::{
FragmentState, PipelineDescriptor, RenderPipeline, RenderPipelineDescriptor, Shader,
VertexState,
},
transform_buffer_storage::TransformBuffers,
vertex::Vertex,
};
@ -19,14 +22,18 @@ use super::{MeshBufferStorage, RenderAssets, RenderMeshes};
const SHADOW_SIZE: glam::UVec2 = glam::UVec2::new(1024, 1024);
#[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
pub enum ShadowMapsPassSlots {
ShadowAtlasTexture,
ShadowAtlasTextureView,
ShadowAtlasSampler,
}
#[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
pub struct ShadowMapsPassLabel;
struct LightDepthMap {
light_projection_buffer: wgpu::Buffer,
texture: wgpu::Texture,
view: wgpu::TextureView,
sampler: wgpu::Sampler,
bindgroup: wgpu::BindGroup,
}
@ -41,39 +48,37 @@ pub struct ShadowMapsPass {
render_meshes: Option<ResourceData>,
mesh_buffers: Option<ResourceData>,
pipeline: Option<RenderPipeline>,
/// The depth map atlas texture
atlas_texture: Rc<wgpu::Texture>,
/// The depth map atlas texture view
atlas_view: Arc<wgpu::TextureView>,
/// The depth map atlas sampler
atlas_sampler: Rc<wgpu::Sampler>,
}
impl ShadowMapsPass {
pub fn new(device: &wgpu::Device) -> Self {
let bgl = Arc::new(device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("shadows_bgl"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: Some(
NonZeroU64::new(mem::size_of::<glam::Mat4>() as _).unwrap(),
),
},
count: None,
}],
}));
let bgl = Arc::new(
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("bgl_shadows_light_projection"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: Some(
NonZeroU64::new(mem::size_of::<glam::Mat4>() as _).unwrap(),
),
},
count: None,
}],
}),
);
Self {
bgl,
depth_maps: Default::default(),
transform_buffers: None,
render_meshes: None,
mesh_buffers: None,
pipeline: None,
}
}
fn create_depth_map(&mut self, device: &wgpu::Device, entity: Entity, light_pos: Transform) {
let tex = device.create_texture(&wgpu::TextureDescriptor {
label: Some("texture_shadow_map_directional_light"),
label: Some("texture_shadow_map_atlas"),
size: wgpu::Extent3d {
width: SHADOW_SIZE.x,
height: SHADOW_SIZE.y,
@ -93,7 +98,7 @@ impl ShadowMapsPass {
});
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("sampler_light_depth_map"),
label: Some("sampler_shadow_map_atlas"),
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
@ -104,17 +109,29 @@ impl ShadowMapsPass {
..Default::default()
});
Self {
bgl,
depth_maps: Default::default(),
transform_buffers: None,
render_meshes: None,
mesh_buffers: None,
pipeline: None,
atlas_sampler: Rc::new(sampler),
atlas_texture: Rc::new(tex),
atlas_view: Arc::new(view),
}
}
fn create_depth_map(&mut self, device: &wgpu::Device, entity: Entity, light_pos: Transform) {
const NEAR_PLANE: f32 = 0.1;
const FAR_PLANE: f32 = 80.0;
let ortho_proj =
glam::Mat4::orthographic_rh_gl(-20.0, 20.0, -20.0, 20.0, NEAR_PLANE, FAR_PLANE);
let look_view = glam::Mat4::look_to_rh(
light_pos.translation,
light_pos.forward(),
light_pos.up()
);
let look_view =
glam::Mat4::look_to_rh(light_pos.translation, light_pos.forward(), light_pos.up());
let light_proj = OPENGL_TO_WGPU_MATRIX * (ortho_proj * look_view);
@ -142,9 +159,6 @@ impl ShadowMapsPass {
entity,
LightDepthMap {
light_projection_buffer,
texture: tex,
view,
sampler,
bindgroup: bg,
},
);
@ -168,7 +182,27 @@ impl Node for ShadowMapsPass {
&mut self,
graph: &mut crate::render::graph::RenderGraph,
) -> crate::render::graph::NodeDesc {
NodeDesc::new(NodeType::Render, None, vec![])
let mut node = NodeDesc::new(NodeType::Render, None, vec![]);
node.add_texture_slot(
ShadowMapsPassSlots::ShadowAtlasTexture,
SlotAttribute::Output,
Some(SlotValue::Texture(self.atlas_texture.clone())),
);
node.add_texture_view_slot(
ShadowMapsPassSlots::ShadowAtlasTextureView,
SlotAttribute::Output,
Some(SlotValue::TextureView(self.atlas_view.clone())),
);
node.add_sampler_slot(
ShadowMapsPassSlots::ShadowAtlasSampler,
SlotAttribute::Output,
Some(SlotValue::Sampler(self.atlas_sampler.clone())),
);
node
}
fn prepare(
@ -201,10 +235,7 @@ impl Node for ShadowMapsPass {
&graph.device,
&RenderPipelineDescriptor {
label: Some("pipeline_shadows".into()),
layouts: vec![
bgl,
transforms,
],
layouts: vec![bgl, transforms],
push_constant_ranges: vec![],
vertex: VertexState {
module: shader.clone(),
@ -226,7 +257,7 @@ impl Node for ShadowMapsPass {
primitive: wgpu::PrimitiveState::default(),
multisample: wgpu::MultisampleState::default(),
multiview: None,
}
},
));
/* */
}
@ -261,7 +292,7 @@ impl Node for ShadowMapsPass {
label: Some("pass_shadow_map"),
color_attachments: &[],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &dir_depth_map.view,
view: &self.atlas_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: true,