diff --git a/res/shaders/depth.wgsl b/res/shaders/depth.wgsl index d990c4a..6e9bd66 100644 --- a/res/shaders/depth.wgsl +++ b/res/shaders/depth.wgsl @@ -13,5 +13,5 @@ fn vs_main( ); let world_position = model_matrix * vec4(model.position, 1.0); - return light.matrices[light_matrix_index] * world_position; + return light.matrices[light_matrix_index] * (world_position - vec4(light.position, 0.0)); } diff --git a/res/shaders/globals.wgsl b/res/shaders/globals.wgsl index 7f42142..556d442 100644 --- a/res/shaders/globals.wgsl +++ b/res/shaders/globals.wgsl @@ -45,10 +45,3 @@ struct VertexOutput { @location(3) tangent_view_position: vec3, @location(4) world_position: vec4, } - -// Fragment shader - -@group(1)@binding(2) -var t_light_depth: binding_array; -@group(1) @binding(3) -var s_light_depth: binding_array; diff --git a/res/shaders/pbr.wgsl b/res/shaders/pbr.wgsl index 950c7e4..7a6eece 100644 --- a/res/shaders/pbr.wgsl +++ b/res/shaders/pbr.wgsl @@ -46,24 +46,29 @@ fn vs_main( // Fragment shader -@group(2) @binding(0) +@group(2)@binding(0) +var t_light_depth: binding_array; +@group(2) @binding(1) +var s_light_depth: binding_array; + +@group(3) @binding(0) var t_diffuse: texture_2d; -@group(2)@binding(1) +@group(3)@binding(1) var s_diffuse: sampler; -@group(2)@binding(2) +@group(3)@binding(2) var t_normal: texture_2d; -@group(2) @binding(3) +@group(3) @binding(3) var s_normal: sampler; -@group(2)@binding(4) +@group(3)@binding(4) var t_roughness_metalness: texture_2d; -@group(2) @binding(5) +@group(3) @binding(5) var s_roughness_metalness: sampler; fn sample_direct_light(index: i32, light_coords: vec4) -> f32 { if (light_coords.w <= 0.0) { - return 1.0; + return 0.0; } let flip_correction = vec2(0.5, -0.5); diff --git a/src/core/model.rs b/src/core/model.rs index bac5817..7288c64 100644 --- a/src/core/model.rs +++ b/src/core/model.rs @@ -143,30 +143,26 @@ pub trait DrawModel<'a> { &mut self, mesh: &'a Mesh, material: &'a Material, - camera_bind_group: &'a wgpu::BindGroup, - light_bind_group: &'a wgpu::BindGroup, + bind_groups: Vec<&'a wgpu::BindGroup>, ); fn draw_mesh_instanced( &mut self, mesh: &'a Mesh, material: &'a Material, instances: Range, - camera_bind_group: &'a wgpu::BindGroup, - light_bind_group: &'a wgpu::BindGroup, + bind_groups: Vec<&'a wgpu::BindGroup>, ); fn draw_model( &mut self, model: &'a Model, - camera_bind_group: &'a wgpu::BindGroup, - light_bind_group: &'a wgpu::BindGroup, + bind_groups: Vec<&'a wgpu::BindGroup>, ); fn draw_model_instanced( &mut self, model: &'a Model, instances: Range, - camera_bind_group: &'a wgpu::BindGroup, - light_bind_group: &'a wgpu::BindGroup, + bind_groups: Vec<&'a wgpu::BindGroup>, ); } @@ -178,10 +174,9 @@ where &mut self, mesh: &'b Mesh, material: &'b Material, - camera_bind_group: &'b wgpu::BindGroup, - light_bind_group: &'b wgpu::BindGroup, + bind_groups: Vec<&'a wgpu::BindGroup>, ) { - self.draw_mesh_instanced(mesh, material, 0..1, camera_bind_group, light_bind_group); + self.draw_mesh_instanced(mesh, material, 0..1, bind_groups); } fn draw_mesh_instanced( @@ -189,32 +184,30 @@ where mesh: &'b Mesh, material: &'b Material, instances: Range, - camera_bind_group: &'b wgpu::BindGroup, - light_bind_group: &'b wgpu::BindGroup, + bind_groups: Vec<&'a wgpu::BindGroup>, ) { self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32); - self.set_bind_group(0, camera_bind_group, &[]); - self.set_bind_group(1, light_bind_group, &[]); - self.set_bind_group(2, &material.bind_group, &[]); + for i in 0..bind_groups.len() { + self.set_bind_group(i as u32, bind_groups[i], &[]); + } + self.set_bind_group(bind_groups.len() as u32, &material.bind_group, &[]); self.draw_indexed(0..mesh.num_elements, 0, instances); } fn draw_model( &mut self, model: &'b Model, - camera_bind_group: &'b wgpu::BindGroup, - light_bind_group: &'b wgpu::BindGroup, + bind_groups: Vec<&'a wgpu::BindGroup>, ) { - self.draw_model_instanced(model, 0..1, camera_bind_group, light_bind_group); + self.draw_model_instanced(model, 0..1, bind_groups); } fn draw_model_instanced( &mut self, model: &'b Model, instances: Range, - camera_bind_group: &'b wgpu::BindGroup, - light_bind_group: &'b wgpu::BindGroup, + bind_groups: Vec<&'a wgpu::BindGroup>, ) { for mesh in &model.meshes { let material = &model.materials[mesh.material]; @@ -222,8 +215,7 @@ where mesh, material, instances.clone(), - camera_bind_group, - light_bind_group, + bind_groups.clone(), ); } } diff --git a/src/core/state.rs b/src/core/state.rs index d010bee..fb98f43 100644 --- a/src/core/state.rs +++ b/src/core/state.rs @@ -1,5 +1,5 @@ use cgmath::prelude::*; -use wgpu::InstanceDescriptor; +use wgpu::{InstanceDescriptor, Backends}; use std::default::Default; use std::num::NonZeroU32; use std::time::Duration; @@ -37,6 +37,10 @@ pub struct State { light_buffer: wgpu::Buffer, light_debug_pass: RenderPass, light_bind_group: wgpu::BindGroup, + #[allow(dead_code)] + light_bind_group_layout: wgpu::BindGroupLayout, + light_depth_bind_group: wgpu::BindGroup, + light_depth_bind_group_layout: wgpu::BindGroupLayout, light_depth_pass: RenderPass, light_depth_textures: [Texture; 6], light_matrix_uniform: u32, @@ -47,7 +51,7 @@ impl State { // Creating some of the wgpu types requires async code pub async fn new(window: &Window) -> Self { let size = window.inner_size(); - let instance = wgpu::Instance::new(InstanceDescriptor::default()); + let instance = wgpu::Instance::new(InstanceDescriptor { backends: Backends::all(), ..Default::default() }); let surface = unsafe { instance.create_surface(window).unwrap() }; let adapter = instance @@ -137,6 +141,7 @@ impl State { "depth_texture", Some(wgpu::CompareFunction::Less), 1, + wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC, ); let light_depth_textures: [Texture; 6] = (0..6) @@ -147,6 +152,7 @@ impl State { format!("light_depth_texture_{}", i).as_str(), Some(wgpu::CompareFunction::Less), 1, + wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, ) }) .collect::>() @@ -206,23 +212,6 @@ impl State { }, count: None, }, - // depth textures - wgpu::BindGroupLayoutEntry { - binding: 2, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Depth, - }, - count: NonZeroU32::new(6), - }, - wgpu::BindGroupLayoutEntry { - binding: 3, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Comparison), - count: NonZeroU32::new(6), - }, ], label: Some("Light Bind Group Layout"), }); @@ -240,17 +229,48 @@ impl State { binding: 1, resource: light_matrix_buffer.as_entire_binding(), }, + ], + label: Some("Light Bind Group"), + }); + + let light_depth_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[ + // depth textures + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + view_dimension: wgpu::TextureViewDimension::D2, + sample_type: wgpu::TextureSampleType::Depth, + }, + count: NonZeroU32::new(6), + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Comparison), + count: NonZeroU32::new(6), + }, + ], + label: Some("Light Bind Group Layout"), + }); + + let light_depth_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &light_depth_bind_group_layout, + entries: &[ // depth textures wgpu::BindGroupEntry { - binding: 2, + binding: 0, resource: wgpu::BindingResource::TextureViewArray(&light_depth_texture_views), }, wgpu::BindGroupEntry { - binding: 3, + binding: 1, resource: wgpu::BindingResource::SamplerArray(&light_depth_texture_samplers), }, ], - label: Some("Light Bind Group"), + label: Some("Light Depth Bind Group"), }); surface.configure(&device, &config); @@ -343,11 +363,26 @@ impl State { usage: wgpu::BufferUsages::VERTEX, }); + let light_depth_pass = RenderPass::new( + &device, + &[ + &camera_bind_group_layout, + &light_bind_group_layout, + ], + &[], + "depth.wgsl", + None, + Some(Texture::DEPTH_FORMAT), + &[ModelVertex::desc(), InstanceRaw::desc()], + "light depth pass", + ); + let geometry_pass = RenderPass::new( &device, &[ &camera_bind_group_layout, &light_bind_group_layout, + &light_depth_bind_group_layout, &texture_bind_group_layout, ], &[], @@ -369,21 +404,6 @@ impl State { "light debug pass", ); - let light_depth_pass = RenderPass::new( - &device, - &[ - &camera_bind_group_layout, - &light_bind_group_layout, - &texture_bind_group_layout, - ], - &[], - "depth.wgsl", - None, - Some(Texture::DEPTH_FORMAT), - &[ModelVertex::desc(), InstanceRaw::desc()], - "light depth pass", - ); - Self { size, surface, @@ -405,6 +425,9 @@ impl State { light_buffer, light_debug_pass, light_bind_group, + light_bind_group_layout, + light_depth_bind_group, + light_depth_bind_group_layout, light_depth_pass, light_depth_textures, light_matrix_uniform, @@ -427,7 +450,10 @@ impl State { "depth_texture", Some(wgpu::CompareFunction::Less), 1, + wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC, ); + + // recreate light depth textures for i in 0..6 { self.light_depth_textures[i] = Texture::create_depth_texture( &self.device, @@ -435,8 +461,37 @@ impl State { format!("light_depth_texture_{}", i).as_str(), Some(wgpu::CompareFunction::Less), 1, + wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, ); } + + let light_depth_texture_views: [&wgpu::TextureView; 6] = (0..6) + .map(|i| &self.light_depth_textures[i].view) + .collect::>() + .try_into() + .expect("failed to create light depth texture views"); + + let light_depth_texture_samplers: [&wgpu::Sampler; 6] = (0..6) + .map(|i| &self.light_depth_textures[i].sampler) + .collect::>() + .try_into() + .expect("failed to create light depth texture samplers"); + + self.light_depth_bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &self.light_depth_bind_group_layout, + entries: &[ + // depth textures + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureViewArray(&light_depth_texture_views), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::SamplerArray(&light_depth_texture_samplers), + }, + ], + label: Some("Light Depth Bind Group"), + }); } } @@ -495,7 +550,7 @@ impl State { label: Some("Light Depth Render Pass"), color_attachments: &[], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.light_depth_textures[i].view, + view: &self.depth_texture.view, depth_ops: Some(wgpu::Operations { load: wgpu::LoadOp::Clear(1.0), store: true, @@ -510,11 +565,16 @@ impl State { light_depth_render_pass.draw_model_instanced( &self.model, 0..self.instances.len() as u32, - &self.camera_bind_group, - &self.light_bind_group, + [&self.camera_bind_group, &self.light_bind_group].into(), ); } + depth_encoder.copy_texture_to_texture( + self.depth_texture.texture.as_image_copy(), + self.light_depth_textures[i].texture.as_image_copy(), + self.depth_texture.texture.size() + ); + self.queue.submit(std::iter::once(depth_encoder.finish())); } @@ -561,8 +621,7 @@ impl State { geom_render_pass.draw_model_instanced( &self.model, 0..self.instances.len() as u32, - &self.camera_bind_group, - &self.light_bind_group, + [&self.camera_bind_group, &self.light_bind_group, &self.light_depth_bind_group].into(), ); } encoder.pop_debug_group(); @@ -599,7 +658,6 @@ impl State { } encoder.pop_debug_group(); - // submit will accept anything that implements IntoIter self.queue.submit(std::iter::once(encoder.finish())); surface_texture.present(); diff --git a/src/core/texture.rs b/src/core/texture.rs index e6d4b6b..86a040c 100644 --- a/src/core/texture.rs +++ b/src/core/texture.rs @@ -16,6 +16,7 @@ impl Texture { label: &str, compare: Option, layers: u32, + usage: wgpu::TextureUsages, ) -> Self { let size = wgpu::Extent3d { width: config.width, @@ -29,7 +30,7 @@ impl Texture { sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::DEPTH_FORMAT, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, + usage, view_formats: &[], }; let texture = device.create_texture(&desc);