diff --git a/lyra-game/src/render/graph/passes/shadows.rs b/lyra-game/src/render/graph/passes/shadows.rs index c3578df..dbbfe36 100644 --- a/lyra-game/src/render/graph/passes/shadows.rs +++ b/lyra-game/src/render/graph/passes/shadows.rs @@ -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, mesh_buffers: Option, pipeline: Option, + + /// The depth map atlas texture + atlas_texture: Rc, + /// The depth map atlas texture view + atlas_view: Arc, + /// The depth map atlas sampler + atlas_sampler: Rc, } 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::() 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::() 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,