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