diff --git a/src/application.rs b/src/application.rs index 40aedde53c..5cb4f5ed2c 100644 --- a/src/application.rs +++ b/src/application.rs @@ -7,7 +7,7 @@ use winit::{ use legion::prelude::*; -use crate::{render::*, ApplicationStage, Time}; +use crate::{render::*, render::passes::*, ApplicationStage, Time}; pub struct Application { @@ -37,7 +37,7 @@ impl Application { let depth_format = wgpu::TextureFormat::Depth32Float; self.render_graph.set_pass("forward", Box::new(ForwardPass::new(depth_format))); - self.render_graph.set_pipeline("forward", "forward", Box::new(ForwardPipelineNew::new())); + self.render_graph.set_pipeline("forward", "forward", Box::new(ForwardPipeline::new())); self.render_graph.set_pipeline("forward", "forward_instanced", Box::new(ForwardInstancedPipeline::new(depth_format))); } diff --git a/src/asset/gltf.rs b/src/asset/gltf.rs new file mode 100644 index 0000000000..5341eca8c4 --- /dev/null +++ b/src/asset/gltf.rs @@ -0,0 +1,18 @@ +use std::{fs, io}; +use std::boxed::Box; +use std::error::Error; + + +// use crate::render::Mesh; + +pub fn load_gltf(path: &str) -> Result<(), Box> { + let file = fs::File::open(&path)?; + let reader = io::BufReader::new(file); + let gltf = gltf::Gltf::from_reader(reader)?; + for scene in gltf.scenes() { + for mesh in scene.nodes() { + } + } + + Ok(()) +} diff --git a/src/render/forward_shadow/mod.rs b/src/render/forward_shadow/mod.rs deleted file mode 100644 index 4a79f12bc7..0000000000 --- a/src/render/forward_shadow/mod.rs +++ /dev/null @@ -1,230 +0,0 @@ -use crate::{render::*, asset::*, render::mesh::*, math}; -use legion::prelude::*; -use std::mem; -use zerocopy::{AsBytes, FromBytes}; -use wgpu::{Buffer, CommandEncoder, Device, VertexBufferDescriptor, SwapChainDescriptor, SwapChainOutput}; - -#[repr(C)] -#[derive(Clone, Copy, AsBytes, FromBytes)] -pub struct ForwardUniforms { - pub proj: [[f32; 4]; 4], - pub num_lights: [u32; 4], -} - -pub struct ForwardShadowPass { - pub pipeline: wgpu::RenderPipeline, - pub bind_group: wgpu::BindGroup, - pub forward_uniform_buffer: wgpu::Buffer, - pub depth_texture: wgpu::TextureView, -} - -impl Pipeline for ForwardShadowPass { - fn render(&mut self, device: &Device, frame: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World, _: &RenderResources) { - let mut mesh_query = <(Read, Read>)>::query(); - let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.view, - resolve_target: None, - load_op: wgpu::LoadOp::Clear, - store_op: wgpu::StoreOp::Store, - clear_color: wgpu::Color { - r: 0.3, - g: 0.4, - b: 0.5, - a: 1.0, - }, - }], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: &self.depth_texture, - depth_load_op: wgpu::LoadOp::Clear, - depth_store_op: wgpu::StoreOp::Store, - stencil_load_op: wgpu::LoadOp::Clear, - stencil_store_op: wgpu::StoreOp::Store, - clear_depth: 1.0, - clear_stencil: 0, - }), - }); - pass.set_pipeline(&self.pipeline); - pass.set_bind_group(0, &self.bind_group, &[]); - - let mut mesh_storage = world.resources.get_mut::>().unwrap(); - for (entity, mesh) in mesh_query.iter_immutable(world) { - if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { - mesh_asset.setup_buffers(device); - pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]); - pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0); - pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); - pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. 1); - }; - } - } - - fn resize(&mut self, device: &Device, frame: &SwapChainDescriptor) { - self.depth_texture = Self::get_depth_texture(device, frame); - } - - fn get_camera_uniform_buffer(&self) -> Option<&Buffer> { - Some(&self.forward_uniform_buffer) - } -} - -impl ForwardShadowPass { - pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; - - pub fn new(device: &Device, world: &World, render_resources: &RenderResources, shadow_pass: &shadow::ShadowPassOld, vertex_buffer_descriptor: VertexBufferDescriptor, swap_chain_descriptor: &SwapChainDescriptor) -> Self { - let vs_bytes = shader::load_glsl( - include_str!("forward_shadow.vert"), - shader::ShaderStage::Vertex, - ); - let fs_bytes = shader::load_glsl( - include_str!("forward_shadow.frag"), - shader::ShaderStage::Fragment, - ); - - let bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - bindings: &[ - wgpu::BindGroupLayoutBinding { - binding: 0, // global - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::UniformBuffer { dynamic: false }, - }, - wgpu::BindGroupLayoutBinding { - binding: 1, // lights - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::UniformBuffer { dynamic: false }, - }, - wgpu::BindGroupLayoutBinding { - binding: 2, - visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::SampledTexture { - multisampled: false, - dimension: wgpu::TextureViewDimension::D2Array, - }, - }, - wgpu::BindGroupLayoutBinding { - binding: 3, - visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler, - }, - ], - }); - - let light_count = >::query().iter_immutable(world).count(); - let forward_uniforms = ForwardUniforms { - proj: math::Mat4::identity().to_cols_array_2d(), - num_lights: [light_count as u32, 0, 0, 0], - }; - - let uniform_size = mem::size_of::() as wgpu::BufferAddress; - let forward_uniform_buffer = device.create_buffer_with_data( - forward_uniforms.as_bytes(), - wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, - ); - - // Create bind group - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_group_layout, - bindings: &[ - wgpu::Binding { - binding: 0, - resource: wgpu::BindingResource::Buffer { - buffer: &forward_uniform_buffer, - range: 0 .. uniform_size, - }, - }, - wgpu::Binding { - binding: 1, - resource: wgpu::BindingResource::Buffer { - buffer: &render_resources.light_uniform_buffer.buffer, - range: 0 .. render_resources.light_uniform_buffer.size, - }, - }, - wgpu::Binding { - binding: 2, - resource: wgpu::BindingResource::TextureView(&shadow_pass.shadow_view), - }, - wgpu::Binding { - binding: 3, - resource: wgpu::BindingResource::Sampler(&shadow_pass.shadow_sampler), - }, - ], - }); - - - let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[&bind_group_layout, &render_resources.local_bind_group_layout], - }); - - let vs_module = device.create_shader_module(&vs_bytes); - let fs_module = device.create_shader_module(&fs_bytes); - - let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - layout: &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, - depth_bias: 0, - depth_bias_slope_scale: 0.0, - depth_bias_clamp: 0.0, - }), - primitive_topology: wgpu::PrimitiveTopology::TriangleList, - color_states: &[ - wgpu::ColorStateDescriptor { - format: swap_chain_descriptor.format, - color_blend: wgpu::BlendDescriptor::REPLACE, - alpha_blend: wgpu::BlendDescriptor::REPLACE, - write_mask: wgpu::ColorWrite::ALL, - }, - ], - depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { - format: Self::DEPTH_FORMAT, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::Less, - stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, - stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE, - stencil_read_mask: 0, - stencil_write_mask: 0, - }), - index_format: wgpu::IndexFormat::Uint16, - vertex_buffers: &[vertex_buffer_descriptor], - sample_count: 1, - sample_mask: !0, - alpha_to_coverage_enabled: false, - }); - - ForwardShadowPass { - pipeline, - bind_group, - forward_uniform_buffer, - depth_texture: Self::get_depth_texture(device, swap_chain_descriptor) - } - } - - fn get_depth_texture(device: &Device, swap_chain_descriptor: &SwapChainDescriptor) -> wgpu::TextureView { - let texture = device.create_texture(&wgpu::TextureDescriptor { - size: wgpu::Extent3d { - width: swap_chain_descriptor.width, - height: swap_chain_descriptor.height, - depth: 1, - }, - array_layer_count: 1, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: Self::DEPTH_FORMAT, - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, - }); - - texture.create_default_view() - } -} - diff --git a/src/render/mod.rs b/src/render/mod.rs index 67005ec0c8..f6f15de777 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -2,27 +2,18 @@ pub mod camera; pub mod shader; pub mod mesh; pub mod render_resources; -mod forward; -mod forward_shadow; -mod forward_instanced; -mod shadow; +pub mod passes; + mod light; -mod pipeline; -mod pass; +mod render_graph; mod material; -pub use forward::{ForwardUniforms, ForwardPipelineNew, ForwardPass}; -pub use forward_shadow::{ForwardShadowPass}; -pub use forward_instanced::ForwardInstancedPipeline; -pub use shadow::ShadowPassOld; pub use light::*; pub use shader::*; -pub use pipeline::*; -pub use pass::*; +pub use render_graph::*; pub use material::*; pub use mesh::*; pub use camera::*; -pub use render_resources::RenderResources; use std::mem; use crate::vertex::Vertex; diff --git a/src/render/forward/forward.frag b/src/render/passes/forward/forward.frag similarity index 100% rename from src/render/forward/forward.frag rename to src/render/passes/forward/forward.frag diff --git a/src/render/forward/forward.vert b/src/render/passes/forward/forward.vert similarity index 100% rename from src/render/forward/forward.vert rename to src/render/passes/forward/forward.vert diff --git a/src/render/passes/forward/forward_pass.rs b/src/render/passes/forward/forward_pass.rs new file mode 100644 index 0000000000..a0da1fbb92 --- /dev/null +++ b/src/render/passes/forward/forward_pass.rs @@ -0,0 +1,84 @@ +use crate::render::*; +use legion::prelude::*; +use zerocopy::{AsBytes, FromBytes}; +use wgpu::{Device, SwapChainDescriptor}; + +#[repr(C)] +#[derive(Clone, Copy, AsBytes, FromBytes)] +pub struct ForwardUniforms { + pub proj: [[f32; 4]; 4], + pub num_lights: [u32; 4], +} + +pub struct ForwardPass { + pub depth_format: wgpu::TextureFormat, +} + +impl ForwardPass { + pub fn new(depth_format: wgpu::TextureFormat) -> Self { + ForwardPass { + depth_format, + } + } + fn get_depth_texture(&self, device: &Device, swap_chain_descriptor: &SwapChainDescriptor) -> wgpu::TextureView { + let texture = device.create_texture(&wgpu::TextureDescriptor { + size: wgpu::Extent3d { + width: swap_chain_descriptor.width, + height: swap_chain_descriptor.height, + depth: 1, + }, + array_layer_count: 1, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: self.depth_format, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + }); + + texture.create_default_view() + } +} + +const DEPTH_TEXTURE_NAME: &str = "forward_depth"; + +impl Pass for ForwardPass { + fn initialize(&self, render_graph: &mut RenderGraphData) { + let depth_texture = self.get_depth_texture(&render_graph.device, &render_graph.swap_chain_descriptor); + render_graph.set_texture(DEPTH_TEXTURE_NAME, depth_texture); + } + fn begin<'a>(&mut self, render_graph: &mut RenderGraphData, _: &mut World, encoder: &'a mut wgpu::CommandEncoder, frame: &'a wgpu::SwapChainOutput) -> Option> { + let depth_texture = render_graph.get_texture(DEPTH_TEXTURE_NAME); + Some(encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Clear, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.3, + g: 0.4, + b: 0.5, + a: 1.0, + }, + }], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: depth_texture.unwrap(), + depth_load_op: wgpu::LoadOp::Clear, + depth_store_op: wgpu::StoreOp::Store, + stencil_load_op: wgpu::LoadOp::Clear, + stencil_store_op: wgpu::StoreOp::Store, + clear_depth: 1.0, + clear_stencil: 0, + }), + })) + } + + fn resize(&self, render_graph: &mut RenderGraphData) { + let depth_texture = self.get_depth_texture(&render_graph.device, &render_graph.swap_chain_descriptor); + render_graph.set_texture(DEPTH_TEXTURE_NAME, depth_texture); + } + + fn should_repeat(&self) -> bool { + false + } +} \ No newline at end of file diff --git a/src/render/forward/mod.rs b/src/render/passes/forward/forward_pipeline.rs similarity index 65% rename from src/render/forward/mod.rs rename to src/render/passes/forward/forward_pipeline.rs index 72cb75a65d..f98a7bbf0c 100644 --- a/src/render/forward/mod.rs +++ b/src/render/passes/forward/forward_pipeline.rs @@ -1,97 +1,16 @@ use crate::{render::*, asset::*, render::mesh::*}; use legion::prelude::*; -use zerocopy::{AsBytes, FromBytes}; -use wgpu::{Device, SwapChainDescriptor, SwapChainOutput}; +use wgpu::SwapChainOutput; -#[repr(C)] -#[derive(Clone, Copy, AsBytes, FromBytes)] -pub struct ForwardUniforms { - pub proj: [[f32; 4]; 4], - pub num_lights: [u32; 4], -} - -pub struct ForwardPipelineNew { +pub struct ForwardPipeline { pub pipeline: Option, pub depth_format: wgpu::TextureFormat, pub local_bind_group: Option, } -pub struct ForwardPass { - pub depth_format: wgpu::TextureFormat, -} - -impl ForwardPass { - pub fn new(depth_format: wgpu::TextureFormat) -> Self { - ForwardPass { - depth_format, - } - } - fn get_depth_texture(&self, device: &Device, swap_chain_descriptor: &SwapChainDescriptor) -> wgpu::TextureView { - let texture = device.create_texture(&wgpu::TextureDescriptor { - size: wgpu::Extent3d { - width: swap_chain_descriptor.width, - height: swap_chain_descriptor.height, - depth: 1, - }, - array_layer_count: 1, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: self.depth_format, - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, - }); - - texture.create_default_view() - } -} - -const DEPTH_TEXTURE_NAME: &str = "forward_depth"; - -impl Pass for ForwardPass { - fn initialize(&self, render_graph: &mut RenderGraphData) { - let depth_texture = self.get_depth_texture(&render_graph.device, &render_graph.swap_chain_descriptor); - render_graph.set_texture(DEPTH_TEXTURE_NAME, depth_texture); - } - fn begin<'a>(&mut self, render_graph: &mut RenderGraphData, world: &mut World, encoder: &'a mut wgpu::CommandEncoder, frame: &'a wgpu::SwapChainOutput) -> Option> { - let depth_texture = render_graph.get_texture(DEPTH_TEXTURE_NAME); - Some(encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.view, - resolve_target: None, - load_op: wgpu::LoadOp::Clear, - store_op: wgpu::StoreOp::Store, - clear_color: wgpu::Color { - r: 0.3, - g: 0.4, - b: 0.5, - a: 1.0, - }, - }], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: depth_texture.unwrap(), - depth_load_op: wgpu::LoadOp::Clear, - depth_store_op: wgpu::StoreOp::Store, - stencil_load_op: wgpu::LoadOp::Clear, - stencil_store_op: wgpu::StoreOp::Store, - clear_depth: 1.0, - clear_stencil: 0, - }), - })) - } - - fn resize(&self, render_graph: &mut RenderGraphData) { - let depth_texture = self.get_depth_texture(&render_graph.device, &render_graph.swap_chain_descriptor); - render_graph.set_texture(DEPTH_TEXTURE_NAME, depth_texture); - } - - fn should_repeat(&self) -> bool { - false - } -} - -impl ForwardPipelineNew { +impl ForwardPipeline { pub fn new() -> Self { - ForwardPipelineNew { + ForwardPipeline { pipeline: None, local_bind_group: None, depth_format: wgpu::TextureFormat::Depth32Float @@ -99,8 +18,8 @@ impl ForwardPipelineNew { } } -impl PipelineNew for ForwardPipelineNew { - fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World) { +impl Pipeline for ForwardPipeline { + fn initialize(&mut self, render_graph: &mut RenderGraphData, _: &mut World) { let vs_bytes = shader::load_glsl( include_str!("forward.vert"), shader::ShaderStage::Vertex, @@ -201,7 +120,7 @@ impl PipelineNew for ForwardPipelineNew { alpha_to_coverage_enabled: false, })); } - fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, frame: &SwapChainOutput, world: &mut World) { + fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, _: &SwapChainOutput, world: &mut World) { pass.set_bind_group(0, self.local_bind_group.as_ref().unwrap(), &[]); let mut mesh_storage = world.resources.get_mut::>().unwrap(); @@ -233,9 +152,10 @@ impl PipelineNew for ForwardPipelineNew { last_mesh_id = Some(current_mesh_id); } } - fn resize(&mut self, render_graph: &RenderGraphData) { - + + fn resize(&mut self, _: &RenderGraphData) { } + fn get_pipeline(&self) -> &wgpu::RenderPipeline { self.pipeline.as_ref().unwrap() } diff --git a/src/render/passes/forward/mod.rs b/src/render/passes/forward/mod.rs new file mode 100644 index 0000000000..a5923f8d62 --- /dev/null +++ b/src/render/passes/forward/mod.rs @@ -0,0 +1,5 @@ +mod forward_pipeline; +mod forward_pass; + +pub use forward_pipeline::*; +pub use forward_pass::*; \ No newline at end of file diff --git a/src/render/forward_instanced/forward_instanced.frag b/src/render/passes/forward_instanced/forward_instanced.frag similarity index 100% rename from src/render/forward_instanced/forward_instanced.frag rename to src/render/passes/forward_instanced/forward_instanced.frag diff --git a/src/render/forward_instanced/forward_instanced.vert b/src/render/passes/forward_instanced/forward_instanced.vert similarity index 100% rename from src/render/forward_instanced/forward_instanced.vert rename to src/render/passes/forward_instanced/forward_instanced.vert diff --git a/src/render/forward_instanced/mod.rs b/src/render/passes/forward_instanced/mod.rs similarity index 98% rename from src/render/forward_instanced/mod.rs rename to src/render/passes/forward_instanced/mod.rs index 1d9bf674ad..0e075a62d7 100644 --- a/src/render/forward_instanced/mod.rs +++ b/src/render/passes/forward_instanced/mod.rs @@ -64,6 +64,7 @@ impl ForwardInstancedPipeline { instance_buffer_infos } + #[allow(dead_code)] fn create_instance_buffer_infos_direct(device: &Device, world: &World) -> Vec { let mut entities = <(Read, Read, Read>, Read)>::query(); let entities_count = entities.iter_immutable(world).count(); @@ -97,7 +98,7 @@ impl ForwardInstancedPipeline { } } -impl PipelineNew for ForwardInstancedPipeline { +impl Pipeline for ForwardInstancedPipeline { fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World) { let vs_bytes = shader::load_glsl( include_str!("forward_instanced.vert"), @@ -126,7 +127,6 @@ impl PipelineNew for ForwardInstancedPipeline { // TODO: this is the same as normal forward pipeline. we can probably reuse self.local_bind_group = Some({ - let forward_uniform_buffer = render_graph.get_uniform_buffer(render_resources::FORWARD_UNIFORM_BUFFER_NAME).unwrap(); let light_uniform_buffer = render_graph.get_uniform_buffer(render_resources::LIGHT_UNIFORM_BUFFER_NAME).unwrap(); @@ -218,7 +218,7 @@ impl PipelineNew for ForwardInstancedPipeline { self.instance_buffer_infos = Some(Self::create_instance_buffer_infos(&render_graph.device, world)); } - fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, frame: &SwapChainOutput, world: &mut World) { + fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, _: &SwapChainOutput, world: &mut World) { self.instance_buffer_infos = Some(Self::create_instance_buffer_infos(&render_graph.device, world)); pass.set_bind_group(0, self.local_bind_group.as_ref().unwrap(), &[]); @@ -234,7 +234,7 @@ impl PipelineNew for ForwardInstancedPipeline { } } - fn resize(&mut self, render_graph: &RenderGraphData) { + fn resize(&mut self, _: &RenderGraphData) { } diff --git a/src/render/forward_shadow/forward_shadow.frag b/src/render/passes/forward_shadow/forward_shadow.frag similarity index 100% rename from src/render/forward_shadow/forward_shadow.frag rename to src/render/passes/forward_shadow/forward_shadow.frag diff --git a/src/render/forward_shadow/forward_shadow.vert b/src/render/passes/forward_shadow/forward_shadow.vert similarity index 100% rename from src/render/forward_shadow/forward_shadow.vert rename to src/render/passes/forward_shadow/forward_shadow.vert diff --git a/src/render/passes/forward_shadow/mod.rs b/src/render/passes/forward_shadow/mod.rs new file mode 100644 index 0000000000..80aed483cf --- /dev/null +++ b/src/render/passes/forward_shadow/mod.rs @@ -0,0 +1,167 @@ +use crate::{render::*, render::passes::shadow, asset::*, render::mesh::*}; +use legion::prelude::*; +use wgpu::SwapChainOutput; + +pub struct ForwardShadowPassNew { + pub pipeline: Option, + pub bind_group: Option, + pub depth_format: wgpu::TextureFormat, +} + +impl ForwardShadowPassNew { + pub fn new() -> Self { + ForwardShadowPassNew { + pipeline: None, + bind_group: None, + depth_format: wgpu::TextureFormat::Depth32Float, + } + } +} + +impl Pipeline for ForwardShadowPassNew { + fn initialize(&mut self, render_graph: &mut RenderGraphData, _world: &mut World) { + let vs_bytes = shader::load_glsl( + include_str!("forward_shadow.vert"), + shader::ShaderStage::Vertex, + ); + let fs_bytes = shader::load_glsl( + include_str!("forward_shadow.frag"), + shader::ShaderStage::Fragment, + ); + + let bind_group_layout = + render_graph.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[ + wgpu::BindGroupLayoutBinding { + binding: 0, // global + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }, + wgpu::BindGroupLayoutBinding { + binding: 1, // lights + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }, + wgpu::BindGroupLayoutBinding { + binding: 2, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::SampledTexture { + multisampled: false, + dimension: wgpu::TextureViewDimension::D2Array, + }, + }, + wgpu::BindGroupLayoutBinding { + binding: 3, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler, + }, + ], + }); + + self.bind_group = Some({ + let forward_uniform_buffer = render_graph.get_uniform_buffer(render_resources::FORWARD_UNIFORM_BUFFER_NAME).unwrap(); + let light_uniform_buffer = render_graph.get_uniform_buffer(render_resources::LIGHT_UNIFORM_BUFFER_NAME).unwrap(); + let shadow_sampler = render_graph.get_sampler(shadow::SHADOW_SAMPLER_NAME).unwrap(); + let shadow_texture = render_graph.get_texture(shadow::SHADOW_TEXTURE_NAME).unwrap(); + + // Create bind group + render_graph.device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &bind_group_layout, + bindings: &[ + wgpu::Binding { + binding: 0, + resource: forward_uniform_buffer.get_binding_resource(), + }, + wgpu::Binding { + binding: 1, + resource: light_uniform_buffer.get_binding_resource(), + }, + wgpu::Binding { + binding: 2, + resource: wgpu::BindingResource::TextureView(shadow_texture), + }, + wgpu::Binding { + binding: 3, + resource: wgpu::BindingResource::Sampler(shadow_sampler), + }, + ], + }) + }); + + let local_bind_group_layout = render_graph.get_bind_group_layout("local").unwrap(); + + let pipeline_layout = render_graph.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&bind_group_layout, local_bind_group_layout], + }); + + let vs_module = render_graph.device.create_shader_module(&vs_bytes); + let fs_module = render_graph.device.create_shader_module(&fs_bytes); + + let vertex_buffer_descriptor = get_vertex_buffer_descriptor(); + + self.pipeline = Some(render_graph.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + layout: &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, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + }), + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: &[ + wgpu::ColorStateDescriptor { + format: render_graph.swap_chain_descriptor.format, + color_blend: wgpu::BlendDescriptor::REPLACE, + alpha_blend: wgpu::BlendDescriptor::REPLACE, + write_mask: wgpu::ColorWrite::ALL, + }, + ], + depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { + format: self.depth_format, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, + stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE, + stencil_read_mask: 0, + stencil_write_mask: 0, + }), + index_format: wgpu::IndexFormat::Uint16, + vertex_buffers: &[vertex_buffer_descriptor], + sample_count: 1, + sample_mask: !0, + alpha_to_coverage_enabled: false, + })); + } + + fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, _swap_chain_output: &SwapChainOutput, world: &mut World) { + let mut mesh_query = <(Read, Read>)>::query(); + pass.set_bind_group(0, self.bind_group.as_ref().unwrap(), &[]); + + let mut mesh_storage = world.resources.get_mut::>().unwrap(); + for (entity, mesh) in mesh_query.iter_immutable(world) { + if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { + mesh_asset.setup_buffers(&render_graph.device); + pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]); + pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0); + pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); + pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. 1); + }; + } + } + + fn resize(&mut self, _render_graph: &RenderGraphData) { + } + + fn get_pipeline(&self) -> &wgpu::RenderPipeline { + self.pipeline.as_ref().unwrap() + } +} \ No newline at end of file diff --git a/src/render/passes/mod.rs b/src/render/passes/mod.rs new file mode 100644 index 0000000000..2ad6658ecf --- /dev/null +++ b/src/render/passes/mod.rs @@ -0,0 +1,10 @@ + +mod forward; +mod forward_shadow; +mod forward_instanced; +mod shadow; + +pub use forward::{ForwardUniforms, ForwardPipeline, ForwardPass}; +pub use forward_shadow::{ForwardShadowPassNew}; +pub use forward_instanced::ForwardInstancedPipeline; +pub use shadow::ShadowPass; \ No newline at end of file diff --git a/src/render/passes/shadow/mod.rs b/src/render/passes/shadow/mod.rs new file mode 100644 index 0000000000..957a7085ad --- /dev/null +++ b/src/render/passes/shadow/mod.rs @@ -0,0 +1,5 @@ +mod shadow_pass; +mod shadow_pipeline; + +pub use shadow_pass::*; +pub use shadow_pipeline::*; \ No newline at end of file diff --git a/src/render/shadow/shadow.frag b/src/render/passes/shadow/shadow.frag similarity index 100% rename from src/render/shadow/shadow.frag rename to src/render/passes/shadow/shadow.frag diff --git a/src/render/shadow/shadow.vert b/src/render/passes/shadow/shadow.vert similarity index 100% rename from src/render/shadow/shadow.vert rename to src/render/passes/shadow/shadow.vert diff --git a/src/render/passes/shadow/shadow_pass.rs b/src/render/passes/shadow/shadow_pass.rs new file mode 100644 index 0000000000..ff0a47d63a --- /dev/null +++ b/src/render/passes/shadow/shadow_pass.rs @@ -0,0 +1,113 @@ +use crate::{render::*, render::passes::shadow, LocalToWorld, Translation}; +use legion::prelude::*; +use std::mem; + +pub struct ShadowPass { + pub shadow_size: wgpu::Extent3d, + light_index: isize, + shadow_texture: Option, + shadow_format: wgpu::TextureFormat, + pub max_lights: usize, +} + +pub const SHADOW_TEXTURE_NAME: &str = "shadow_texture"; + +impl ShadowPass { + pub fn new(shadow_size: wgpu::Extent3d, shadow_format: wgpu::TextureFormat, max_lights: usize) -> Self { + ShadowPass { + light_index: -1, + shadow_texture: None, + shadow_size, + shadow_format, + max_lights, + } + } +} + +impl Pass for ShadowPass { + fn initialize(&self, render_graph: &mut RenderGraphData) { + let shadow_texture = render_graph.device.create_texture(&wgpu::TextureDescriptor { + size: self.shadow_size, + array_layer_count: self.max_lights as u32, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: self.shadow_format, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::SAMPLED, + }); + + let shadow_view = shadow_texture.create_default_view(); + render_graph.set_texture(SHADOW_TEXTURE_NAME, shadow_view); + } + + fn begin<'a>( + &mut self, + render_graph: &mut RenderGraphData, + world: &mut World, + encoder: &'a mut wgpu::CommandEncoder, + _frame: &'a wgpu::SwapChainOutput, + ) -> Option> { + if self.light_index == -1 { + self.light_index = 0; + } + + let mut light_query = <(Write, Read, Read)>::query(); + let light_count = light_query.iter(world).count(); + for (i, (mut light, _, _)) in light_query.iter(world).enumerate() { + if i != self.light_index as usize { + continue; + } + + if let None = light.target_view { + light.target_view = Some(self.shadow_texture.as_ref().unwrap().create_view( + &wgpu::TextureViewDescriptor { + format: self.shadow_format, + dimension: wgpu::TextureViewDimension::D2, + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + level_count: 1, + base_array_layer: i as u32, + array_layer_count: 1, + }, + )); + } + + // The light uniform buffer already has the projection, + // let's just copy it over to the shadow uniform buffer. + let light_uniform_buffer = render_graph.get_uniform_buffer(render_resources::LIGHT_UNIFORM_BUFFER_NAME).unwrap(); + let shadow_pipeline_uniform_buffer = render_graph.get_uniform_buffer(shadow::SHADOW_PIPELINE_UNIFORMS).unwrap(); + encoder.copy_buffer_to_buffer( + &light_uniform_buffer.buffer, + (i * mem::size_of::()) as wgpu::BufferAddress, + &shadow_pipeline_uniform_buffer.buffer, + 0, + 64, + ); + + self.light_index += 1; + if self.light_index as usize == light_count { + self.light_index = -1; + } + return Some(encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: light.target_view.as_ref().unwrap(), + depth_load_op: wgpu::LoadOp::Clear, + depth_store_op: wgpu::StoreOp::Store, + stencil_load_op: wgpu::LoadOp::Clear, + stencil_store_op: wgpu::StoreOp::Store, + clear_depth: 1.0, + clear_stencil: 0, + }), + })); + } + + None + } + + fn resize(&self, _render_graph: &mut RenderGraphData) {} + + fn should_repeat(&self) -> bool { + return self.light_index != -1; + } +} \ No newline at end of file diff --git a/src/render/passes/shadow/shadow_pipeline.rs b/src/render/passes/shadow/shadow_pipeline.rs new file mode 100644 index 0000000000..8c8a1227bf --- /dev/null +++ b/src/render/passes/shadow/shadow_pipeline.rs @@ -0,0 +1,167 @@ +use crate::{asset::*, render::*}; +use legion::prelude::*; +use std::mem; +use wgpu::SwapChainOutput; + +pub const SHADOW_PIPELINE_UNIFORMS: &str = "shadow_pipeline"; +pub const SHADOW_SAMPLER_NAME: &str = "shadow_sampler"; + +#[repr(C)] +pub struct ShadowUniforms { + pub proj: [[f32; 4]; 4], +} + +pub struct ShadowPipeline { + pub pipeline: Option, + pub bind_group: Option, + pub shadow_format: wgpu::TextureFormat, +} + +impl ShadowPipeline { + #[allow(dead_code)] + pub fn new(shadow_format: wgpu::TextureFormat) -> Self { + ShadowPipeline { + bind_group: None, + pipeline: None, + shadow_format, + } + } +} + +impl Pipeline for ShadowPipeline { + fn initialize(&mut self, render_graph: &mut RenderGraphData, _: &mut World) { + let bind_group_layout = render_graph.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[wgpu::BindGroupLayoutBinding { + binding: 0, // global + visibility: wgpu::ShaderStage::VERTEX, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }], + }); + + // TODO: stop using "local" + let local_bind_group_layout = render_graph.get_bind_group_layout("local").unwrap(); + + let pipeline_layout = render_graph.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[ + &bind_group_layout, + local_bind_group_layout, + ], + }); + + let uniform_size = mem::size_of::() as wgpu::BufferAddress; + let uniform_buf = render_graph.device.create_buffer(&wgpu::BufferDescriptor { + size: uniform_size, + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + }); + + // Create bind group + self.bind_group = Some(render_graph.device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &bind_group_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &uniform_buf, + range: 0..uniform_size, + }, + }], + })); + + render_graph.set_uniform_buffer(SHADOW_PIPELINE_UNIFORMS, UniformBuffer { + buffer: uniform_buf, + size: uniform_size, + }); + + // Create other resources + let shadow_sampler = render_graph.device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + lod_min_clamp: -100.0, + lod_max_clamp: 100.0, + compare_function: wgpu::CompareFunction::LessEqual, + }); + + render_graph.set_sampler(SHADOW_SAMPLER_NAME, shadow_sampler); + + let vertex_buffer_descriptor = get_vertex_buffer_descriptor(); + + // Create the render pipeline + let vs_bytes = + shader::load_glsl(include_str!("shadow.vert"), shader::ShaderStage::Vertex); + let fs_bytes = + shader::load_glsl(include_str!("shadow.frag"), shader::ShaderStage::Fragment); + let vs_module = render_graph.device.create_shader_module(&vs_bytes); + let fs_module = render_graph.device.create_shader_module(&fs_bytes); + + self.pipeline = Some(render_graph.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + layout: &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, + depth_bias: 2, // corresponds to bilinear filtering + depth_bias_slope_scale: 2.0, + depth_bias_clamp: 0.0, + }), + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: &[], + depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { + format: self.shadow_format, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::LessEqual, + stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, + stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE, + stencil_read_mask: 0, + stencil_write_mask: 0, + }), + index_format: wgpu::IndexFormat::Uint16, + vertex_buffers: &[vertex_buffer_descriptor], + sample_count: 1, + sample_mask: !0, + alpha_to_coverage_enabled: false, + })); + } + + fn render( + &mut self, + render_graph: &RenderGraphData, + pass: &mut wgpu::RenderPass, + _: &SwapChainOutput, + world: &mut World, + ) { + let mut mesh_query = + <(Read, Read>)>::query().filter(!component::()); + pass.set_bind_group(0, self.bind_group.as_ref().unwrap(), &[]); + + let mut mesh_storage = world + .resources + .get_mut::>() + .unwrap(); + for (entity, mesh) in mesh_query.iter_immutable(world) { + if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { + mesh_asset.setup_buffers(&render_graph.device); + + pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]); + pass.set_index_buffer(&mesh_asset.index_buffer.as_ref().unwrap(), 0); + pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); + pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1); + }; + } + } + + fn resize(&mut self, _: &RenderGraphData) {} + + fn get_pipeline(&self) -> &wgpu::RenderPipeline { + self.pipeline.as_ref().unwrap() + } +} \ No newline at end of file diff --git a/src/render/pipeline.rs b/src/render/pipeline.rs deleted file mode 100644 index 26837e7869..0000000000 --- a/src/render/pipeline.rs +++ /dev/null @@ -1,17 +0,0 @@ -use legion::world::World; -use wgpu::{Buffer, CommandEncoder, Device, SwapChainDescriptor, SwapChainOutput}; -use crate::render::{RenderResources, RenderGraphData}; - - -pub trait Pipeline { - fn render(&mut self, device: &Device, frame: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World, render_resources: &RenderResources); - fn resize(&mut self, device: &Device, frame: &SwapChainDescriptor); - fn get_camera_uniform_buffer(&self) -> Option<&Buffer>; -} - -pub trait PipelineNew { - fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World); - fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, frame: &SwapChainOutput, world: &mut World); - fn resize(&mut self, render_graph: &RenderGraphData); - fn get_pipeline(&self) -> &wgpu::RenderPipeline; -} \ No newline at end of file diff --git a/src/render/pass.rs b/src/render/render_graph/mod.rs similarity index 86% rename from src/render/pass.rs rename to src/render/render_graph/mod.rs index 4ee5bcfc4e..c53e3a10dd 100644 --- a/src/render/pass.rs +++ b/src/render/render_graph/mod.rs @@ -1,24 +1,19 @@ -use crate::render::{PipelineNew, UniformBuffer}; +mod pass; +mod pipeline; +mod render_resource_manager; + +pub use pass::Pass; +pub use pipeline::Pipeline; +pub use render_resource_manager::RenderResourceManager; + +use crate::render::UniformBuffer; use std::collections::HashMap; use legion::world::World; -pub trait Pass { - fn initialize(&self, render_graph: &mut RenderGraphData); - fn begin<'a>(&mut self, render_graph: &mut RenderGraphData, world: &mut World, encoder: &'a mut wgpu::CommandEncoder, frame: &'a wgpu::SwapChainOutput) -> Option>; - fn should_repeat(&self) -> bool; - fn resize(&self, render_graph: &mut RenderGraphData); -} - -pub trait RenderResourceManager { - fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World); - fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World); - fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World); -} - pub struct RenderGraph { pub data: RenderGraphData, passes: HashMap>, - pipelines: HashMap>, + pipelines: HashMap>, pass_pipelines: HashMap>, render_resource_managers: Vec>, pub swap_chain: wgpu::SwapChain, // TODO: this is weird @@ -30,6 +25,7 @@ pub struct RenderGraphData { pub queue: wgpu::Queue, pub surface: wgpu::Surface, textures: HashMap, + samplers: HashMap, uniform_buffers: HashMap, bind_group_layouts: HashMap, } @@ -37,6 +33,7 @@ impl RenderGraphData { pub fn new(device: wgpu::Device, swap_chain_descriptor: wgpu::SwapChainDescriptor, queue: wgpu::Queue, surface: wgpu::Surface) -> Self { RenderGraphData { textures: HashMap::new(), + samplers: HashMap::new(), uniform_buffers: HashMap::new(), bind_group_layouts: HashMap::new(), device, @@ -69,6 +66,14 @@ impl RenderGraphData { pub fn get_texture(&self, name: &str) -> Option<&wgpu::TextureView> { self.textures.get(name) } + + pub fn set_sampler(&mut self, name: &str, sampler: wgpu::Sampler) { + self.samplers.insert(name.to_string(), sampler); + } + + pub fn get_sampler(&self, name: &str) -> Option<&wgpu::Sampler> { + self.samplers.get(name) + } } impl RenderGraph { @@ -162,10 +167,10 @@ impl RenderGraph { self.render_resource_managers.push(render_resource_manager); } - pub fn set_pipeline(&mut self, pass_name: &str, pipeline_name: &str, pipeline: Box) { + pub fn set_pipeline(&mut self, pass_name: &str, pipeline_name: &str, pipeline: Box) { self.pipelines.insert(pipeline_name.to_string(), pipeline); if let None = self.pass_pipelines.get_mut(pass_name) { - let mut pipelines = Vec::new(); + let pipelines = Vec::new(); self.pass_pipelines.insert(pass_name.to_string(), pipelines); }; diff --git a/src/render/render_graph/pass.rs b/src/render/render_graph/pass.rs new file mode 100644 index 0000000000..db01ff5016 --- /dev/null +++ b/src/render/render_graph/pass.rs @@ -0,0 +1,9 @@ +use crate::render::render_graph::RenderGraphData; +use legion::world::World; + +pub trait Pass { + fn initialize(&self, render_graph: &mut RenderGraphData); + fn begin<'a>(&mut self, render_graph: &mut RenderGraphData, world: &mut World, encoder: &'a mut wgpu::CommandEncoder, frame: &'a wgpu::SwapChainOutput) -> Option>; + fn should_repeat(&self) -> bool; + fn resize(&self, render_graph: &mut RenderGraphData); +} \ No newline at end of file diff --git a/src/render/render_graph/pipeline.rs b/src/render/render_graph/pipeline.rs new file mode 100644 index 0000000000..0262473afe --- /dev/null +++ b/src/render/render_graph/pipeline.rs @@ -0,0 +1,10 @@ +use legion::world::World; +use wgpu::SwapChainOutput; +use crate::render::RenderGraphData; + +pub trait Pipeline { + fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World); + fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, frame: &SwapChainOutput, world: &mut World); + fn resize(&mut self, render_graph: &RenderGraphData); + fn get_pipeline(&self) -> &wgpu::RenderPipeline; +} \ No newline at end of file diff --git a/src/render/render_graph/render_resource_manager.rs b/src/render/render_graph/render_resource_manager.rs new file mode 100644 index 0000000000..847bb1a93d --- /dev/null +++ b/src/render/render_graph/render_resource_manager.rs @@ -0,0 +1,8 @@ +use legion::world::World; +use crate::render::RenderGraphData; + +pub trait RenderResourceManager { + fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World); + fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World); + fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World); +} \ No newline at end of file diff --git a/src/render/render_resources.rs b/src/render/render_resources.rs deleted file mode 100644 index a23dc26dbb..0000000000 --- a/src/render/render_resources.rs +++ /dev/null @@ -1,246 +0,0 @@ -use crate::{render::*, LocalToWorld, Translation, math}; - -use legion::prelude::*; -use std::sync::Arc; -use std::rc::Rc; -use std::mem; -use zerocopy::AsBytes; - -use wgpu::{BindGroupLayout, CommandEncoder, Device}; - -pub const LIGHT_UNIFORM_BUFFER_NAME: &str = "lights"; -pub const FORWARD_UNIFORM_BUFFER_NAME: &str = "forward"; -pub struct LightResourceManager { - pub lights_are_dirty: bool, - pub max_lights: usize, -} - -impl LightResourceManager { - pub fn new(max_lights: usize) -> Self { - LightResourceManager { - lights_are_dirty: true, - max_lights: max_lights, - } - } -} - -impl RenderResourceManager for LightResourceManager { - fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World) { - let light_uniform_size = - (self.max_lights * mem::size_of::()) as wgpu::BufferAddress; - - let light_uniform_buffer = UniformBuffer { - buffer: render_graph.device.create_buffer(&wgpu::BufferDescriptor { - size: light_uniform_size, - usage: wgpu::BufferUsage::UNIFORM - | wgpu::BufferUsage::COPY_SRC - | wgpu::BufferUsage::COPY_DST, - }), - size: light_uniform_size, - }; - - render_graph.set_uniform_buffer(LIGHT_UNIFORM_BUFFER_NAME, light_uniform_buffer); - } - fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { - if self.lights_are_dirty { - let mut light_query = <(Read, Read, Read)>::query(); - let light_count = light_query.iter(world).count(); - - self.lights_are_dirty = false; - let size = mem::size_of::(); - let total_size = size * light_count; - let temp_buf_data = - render_graph.device.create_buffer_mapped(total_size, wgpu::BufferUsage::COPY_SRC); - for ((light, local_to_world, translation), slot) in light_query - .iter(world) - .zip(temp_buf_data.data.chunks_exact_mut(size)) - { - slot.copy_from_slice(LightRaw::from(&light, &local_to_world.0, &translation).as_bytes()); - } - - let light_uniform_buffer = render_graph.get_uniform_buffer(LIGHT_UNIFORM_BUFFER_NAME).unwrap(); - encoder.copy_buffer_to_buffer( - &temp_buf_data.finish(), - 0, - &light_uniform_buffer.buffer, - 0, - total_size as wgpu::BufferAddress, - ); - - } - } - fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { } -} - -pub struct CameraResourceManager; - -impl RenderResourceManager for CameraResourceManager { - fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World) { - let light_count = >::query().iter_immutable(world).count(); - let forward_uniforms = ForwardUniforms { - proj: math::Mat4::identity().to_cols_array_2d(), - num_lights: [light_count as u32, 0, 0, 0], - }; - - let uniform_size = mem::size_of::() as wgpu::BufferAddress; - let buffer = render_graph.device.create_buffer_with_data( - forward_uniforms.as_bytes(), - wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, - ); - - let uniform_buffer = UniformBuffer { - buffer: buffer, - size: uniform_size, - }; - render_graph.set_uniform_buffer(FORWARD_UNIFORM_BUFFER_NAME, uniform_buffer); - } - fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { - - } - fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { - for (mut camera, local_to_world) in <(Write, Read)>::query().iter(world) { - camera.update(render_graph.swap_chain_descriptor.width, render_graph.swap_chain_descriptor.height); - let camera_matrix: [[f32; 4]; 4] = (camera.view_matrix * local_to_world.0).to_cols_array_2d(); - let matrix_size = mem::size_of::<[[f32; 4]; 4]>() as u64; - let temp_camera_buffer = - render_graph.device.create_buffer_with_data(camera_matrix.as_bytes(), wgpu::BufferUsage::COPY_SRC); - let forward_uniform_buffer = render_graph.get_uniform_buffer(FORWARD_UNIFORM_BUFFER_NAME).unwrap(); - encoder.copy_buffer_to_buffer(&temp_camera_buffer, 0, &forward_uniform_buffer.buffer, 0, matrix_size); - } - } -} - -pub struct MaterialResourceManager; - -impl RenderResourceManager for MaterialResourceManager { - fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World) { - - } - fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { - let mut entities = <(Write, Read)>::query() - .filter(!component::()); - let entities_count = entities.iter(world).count(); - let size = mem::size_of::(); - let temp_buf_data = render_graph.device - .create_buffer_mapped(entities_count * size, wgpu::BufferUsage::COPY_SRC); - - for ((material, transform), slot) in entities.iter(world) - .zip(temp_buf_data.data.chunks_exact_mut(size)) - { - slot.copy_from_slice( - MaterialUniforms { - model: transform.0.to_cols_array_2d(), - color: material.color.into(), - } - .as_bytes(), - ); - } - - // TODO: dont use inline local - let local_bind_group_layout = render_graph.get_bind_group_layout("local").unwrap(); - - for mut material in >::query().filter(!component::()).iter(world) { - if let None = material.bind_group { - let material_uniform_size = mem::size_of::() as wgpu::BufferAddress; - let uniform_buf = render_graph.device.create_buffer(&wgpu::BufferDescriptor { - size: material_uniform_size, - usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, - }); - - let bind_group = render_graph.device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: local_bind_group_layout, - bindings: &[wgpu::Binding { - binding: 0, - resource: wgpu::BindingResource::Buffer { - buffer: &uniform_buf, - range: 0 .. material_uniform_size, - }, - }], - }); - - material.bind_group = Some(bind_group); - material.uniform_buf = Some(uniform_buf); - } - } - - let temp_buf = temp_buf_data.finish(); - for (i, (material, _)) in entities.iter(world).enumerate() { - encoder.copy_buffer_to_buffer( - &temp_buf, - (i * size) as wgpu::BufferAddress, - material.uniform_buf.as_ref().unwrap(), - 0, - size as wgpu::BufferAddress, - ); - } - } - fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { - - } - -} - -pub struct RenderResources { - pub local_bind_group_layout: Rc, - pub light_uniform_buffer: Arc, - pub lights_are_dirty: bool, - pub max_lights: usize, -} - -impl RenderResources { - pub fn new(device: &mut Device, max_lights: usize) -> RenderResources { - let light_uniform_size = - (max_lights * mem::size_of::()) as wgpu::BufferAddress; - - let local_bind_group_layout = - Rc::new(device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - bindings: &[wgpu::BindGroupLayoutBinding { - binding: 0, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::UniformBuffer { dynamic: false }, - }], - })); - - let light_uniform_buffer = Arc::new(UniformBuffer { - buffer: device.create_buffer(&wgpu::BufferDescriptor { - size: light_uniform_size, - usage: wgpu::BufferUsage::UNIFORM - | wgpu::BufferUsage::COPY_SRC - | wgpu::BufferUsage::COPY_DST, - }), - size: light_uniform_size, - }); - - RenderResources { - local_bind_group_layout, - light_uniform_buffer, - lights_are_dirty: true, - max_lights - } - } - pub fn update_lights(&mut self, device: &Device, encoder: &mut CommandEncoder, world: &mut World) { - if self.lights_are_dirty { - let mut light_query = <(Read, Read, Read)>::query(); - let light_count = light_query.iter(world).count(); - - self.lights_are_dirty = false; - let size = mem::size_of::(); - let total_size = size * light_count; - let temp_buf_data = - device.create_buffer_mapped(total_size, wgpu::BufferUsage::COPY_SRC); - for ((light, local_to_world, translation), slot) in light_query - .iter(world) - .zip(temp_buf_data.data.chunks_exact_mut(size)) - { - slot.copy_from_slice(LightRaw::from(&light, &local_to_world.0, &translation).as_bytes()); - } - encoder.copy_buffer_to_buffer( - &temp_buf_data.finish(), - 0, - &self.light_uniform_buffer.buffer, - 0, - total_size as wgpu::BufferAddress, - ); - } - } -} diff --git a/src/render/render_resources/camera_resource_manager.rs b/src/render/render_resources/camera_resource_manager.rs new file mode 100644 index 0000000000..b131c082f2 --- /dev/null +++ b/src/render/render_resources/camera_resource_manager.rs @@ -0,0 +1,45 @@ +use crate::{render::*, render::passes::ForwardUniforms, LocalToWorld, math}; + +use legion::prelude::*; +use std::mem; +use zerocopy::AsBytes; + +pub const FORWARD_UNIFORM_BUFFER_NAME: &str = "forward"; + +pub struct CameraResourceManager; + +impl RenderResourceManager for CameraResourceManager { + fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World) { + let light_count = >::query().iter_immutable(world).count(); + let forward_uniforms = ForwardUniforms { + proj: math::Mat4::identity().to_cols_array_2d(), + num_lights: [light_count as u32, 0, 0, 0], + }; + + let uniform_size = mem::size_of::() as wgpu::BufferAddress; + let buffer = render_graph.device.create_buffer_with_data( + forward_uniforms.as_bytes(), + wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + ); + + let uniform_buffer = UniformBuffer { + buffer: buffer, + size: uniform_size, + }; + render_graph.set_uniform_buffer(FORWARD_UNIFORM_BUFFER_NAME, uniform_buffer); + } + fn update<'a>(&mut self, _render_graph: &mut RenderGraphData, _encoder: &'a mut wgpu::CommandEncoder, _world: &mut World) { + + } + fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { + for (mut camera, local_to_world) in <(Write, Read)>::query().iter(world) { + camera.update(render_graph.swap_chain_descriptor.width, render_graph.swap_chain_descriptor.height); + let camera_matrix: [[f32; 4]; 4] = (camera.view_matrix * local_to_world.0).to_cols_array_2d(); + let matrix_size = mem::size_of::<[[f32; 4]; 4]>() as u64; + let temp_camera_buffer = + render_graph.device.create_buffer_with_data(camera_matrix.as_bytes(), wgpu::BufferUsage::COPY_SRC); + let forward_uniform_buffer = render_graph.get_uniform_buffer(FORWARD_UNIFORM_BUFFER_NAME).unwrap(); + encoder.copy_buffer_to_buffer(&temp_camera_buffer, 0, &forward_uniform_buffer.buffer, 0, matrix_size); + } + } +} \ No newline at end of file diff --git a/src/render/render_resources/light_resource_manager.rs b/src/render/render_resources/light_resource_manager.rs new file mode 100644 index 0000000000..6cc754ef5f --- /dev/null +++ b/src/render/render_resources/light_resource_manager.rs @@ -0,0 +1,69 @@ +use crate::{render::*, LocalToWorld, Translation}; + +use legion::prelude::*; +use std::mem; +use zerocopy::AsBytes; + +pub const LIGHT_UNIFORM_BUFFER_NAME: &str = "lights"; + +pub struct LightResourceManager { + pub lights_are_dirty: bool, + pub max_lights: usize, +} + +impl LightResourceManager { + pub fn new(max_lights: usize) -> Self { + LightResourceManager { + lights_are_dirty: true, + max_lights: max_lights, + } + } +} + +impl RenderResourceManager for LightResourceManager { + fn initialize(&self, render_graph: &mut RenderGraphData, _world: &mut World) { + let light_uniform_size = + (self.max_lights * mem::size_of::()) as wgpu::BufferAddress; + + let light_uniform_buffer = UniformBuffer { + buffer: render_graph.device.create_buffer(&wgpu::BufferDescriptor { + size: light_uniform_size, + usage: wgpu::BufferUsage::UNIFORM + | wgpu::BufferUsage::COPY_SRC + | wgpu::BufferUsage::COPY_DST, + }), + size: light_uniform_size, + }; + + render_graph.set_uniform_buffer(LIGHT_UNIFORM_BUFFER_NAME, light_uniform_buffer); + } + fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { + if self.lights_are_dirty { + let mut light_query = <(Read, Read, Read)>::query(); + let light_count = light_query.iter(world).count(); + + self.lights_are_dirty = false; + let size = mem::size_of::(); + let total_size = size * light_count; + let temp_buf_data = + render_graph.device.create_buffer_mapped(total_size, wgpu::BufferUsage::COPY_SRC); + for ((light, local_to_world, translation), slot) in light_query + .iter(world) + .zip(temp_buf_data.data.chunks_exact_mut(size)) + { + slot.copy_from_slice(LightRaw::from(&light, &local_to_world.0, &translation).as_bytes()); + } + + let light_uniform_buffer = render_graph.get_uniform_buffer(LIGHT_UNIFORM_BUFFER_NAME).unwrap(); + encoder.copy_buffer_to_buffer( + &temp_buf_data.finish(), + 0, + &light_uniform_buffer.buffer, + 0, + total_size as wgpu::BufferAddress, + ); + + } + } + fn resize<'a>(&self, _render_graph: &mut RenderGraphData, _encoder: &'a mut wgpu::CommandEncoder, _world: &mut World) { } +} \ No newline at end of file diff --git a/src/render/render_resources/material_resource_manager.rs b/src/render/render_resources/material_resource_manager.rs new file mode 100644 index 0000000000..a99efa0910 --- /dev/null +++ b/src/render/render_resources/material_resource_manager.rs @@ -0,0 +1,75 @@ +use crate::{render::*, LocalToWorld}; + +use legion::prelude::*; +use std::mem; +use zerocopy::AsBytes; + +pub struct MaterialResourceManager; + +impl RenderResourceManager for MaterialResourceManager { + fn initialize(&self, _render_graph: &mut RenderGraphData, _world: &mut World) { + + } + + fn update<'a>(&mut self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) { + let mut entities = <(Write, Read)>::query() + .filter(!component::()); + let entities_count = entities.iter(world).count(); + let size = mem::size_of::(); + let temp_buf_data = render_graph.device + .create_buffer_mapped(entities_count * size, wgpu::BufferUsage::COPY_SRC); + + for ((material, transform), slot) in entities.iter(world) + .zip(temp_buf_data.data.chunks_exact_mut(size)) + { + slot.copy_from_slice( + MaterialUniforms { + model: transform.0.to_cols_array_2d(), + color: material.color.into(), + } + .as_bytes(), + ); + } + + // TODO: dont use inline local + let local_bind_group_layout = render_graph.get_bind_group_layout("local").unwrap(); + + for mut material in >::query().filter(!component::()).iter(world) { + if let None = material.bind_group { + let material_uniform_size = mem::size_of::() as wgpu::BufferAddress; + let uniform_buf = render_graph.device.create_buffer(&wgpu::BufferDescriptor { + size: material_uniform_size, + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + }); + + let bind_group = render_graph.device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: local_bind_group_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &uniform_buf, + range: 0 .. material_uniform_size, + }, + }], + }); + + material.bind_group = Some(bind_group); + material.uniform_buf = Some(uniform_buf); + } + } + + let temp_buf = temp_buf_data.finish(); + for (i, (material, _)) in entities.iter(world).enumerate() { + encoder.copy_buffer_to_buffer( + &temp_buf, + (i * size) as wgpu::BufferAddress, + material.uniform_buf.as_ref().unwrap(), + 0, + size as wgpu::BufferAddress, + ); + } + } + fn resize<'a>(&self, _render_graph: &mut RenderGraphData, _encoder: &'a mut wgpu::CommandEncoder, _world: &mut World) { + + } +} \ No newline at end of file diff --git a/src/render/render_resources/mod.rs b/src/render/render_resources/mod.rs new file mode 100644 index 0000000000..13c859e6f8 --- /dev/null +++ b/src/render/render_resources/mod.rs @@ -0,0 +1,7 @@ +mod light_resource_manager; +mod camera_resource_manager; +mod material_resource_manager; + +pub use light_resource_manager::*; +pub use camera_resource_manager::*; +pub use material_resource_manager::*; \ No newline at end of file diff --git a/src/render/shadow/mod.rs b/src/render/shadow/mod.rs deleted file mode 100644 index 0e1e8abff5..0000000000 --- a/src/render/shadow/mod.rs +++ /dev/null @@ -1,483 +0,0 @@ -use crate::{asset::*, render::*, LocalToWorld, Translation}; -use legion::prelude::*; -use std::mem; -use wgpu::{ - Buffer, CommandEncoder, Device, SwapChainDescriptor, SwapChainOutput, VertexBufferDescriptor, -}; - -pub struct ShadowPassOld { - pub pipeline: wgpu::RenderPipeline, - pub bind_group: wgpu::BindGroup, - pub uniform_buf: wgpu::Buffer, - pub shadow_texture: wgpu::Texture, - pub shadow_view: wgpu::TextureView, - pub shadow_sampler: wgpu::Sampler, - pub lights_are_dirty: bool, -} - -pub struct ShadowPass { - pub shadow_size: wgpu::Extent3d, - light_index: isize, - shadow_texture: Option, - shadow_format: wgpu::TextureFormat, - pub max_lights: usize, -} - -impl ShadowPass { - pub fn new(shadow_size: wgpu::Extent3d, shadow_format: wgpu::TextureFormat, max_lights: usize) -> Self { - ShadowPass { - light_index: -1, - shadow_texture: None, - shadow_size, - shadow_format, - max_lights, - } - } -} - -impl Pass for ShadowPass { - fn initialize(&self, render_graph: &mut RenderGraphData) { - let shadow_texture = render_graph.device.create_texture(&wgpu::TextureDescriptor { - size: self.shadow_size, - array_layer_count: self.max_lights as u32, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: self.shadow_format, - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::SAMPLED, - }); - - let shadow_view = shadow_texture.create_default_view(); - } - - fn begin<'a>( - &mut self, - render_graph: &mut RenderGraphData, - world: &mut World, - encoder: &'a mut wgpu::CommandEncoder, - frame: &'a wgpu::SwapChainOutput, - ) -> Option> { - if self.light_index == -1 { - self.light_index = 0; - } - - let mut light_query = <(Write, Read, Read)>::query(); - let light_count = light_query.iter(world).count(); - for (i, (mut light, _, _)) in light_query.iter(world).enumerate() { - if i != self.light_index as usize { - continue; - } - - if let None = light.target_view { - light.target_view = Some(self.shadow_texture.as_ref().unwrap().create_view( - &wgpu::TextureViewDescriptor { - format: ShadowPassOld::SHADOW_FORMAT, - dimension: wgpu::TextureViewDimension::D2, - aspect: wgpu::TextureAspect::All, - base_mip_level: 0, - level_count: 1, - base_array_layer: i as u32, - array_layer_count: 1, - }, - )); - } - - // The light uniform buffer already has the projection, - // let's just copy it over to the shadow uniform buffer. - let light_uniform_buffer = render_graph.get_uniform_buffer(render_resources::LIGHT_UNIFORM_BUFFER_NAME).unwrap(); - let shadow_pipeline_uniform_buffer = render_graph.get_uniform_buffer(SHADOW_PIPELINE_UNIFORMS).unwrap(); - encoder.copy_buffer_to_buffer( - &light_uniform_buffer.buffer, - (i * mem::size_of::()) as wgpu::BufferAddress, - &shadow_pipeline_uniform_buffer.buffer, - 0, - 64, - ); - - self.light_index += 1; - if self.light_index as usize == light_count { - self.light_index = -1; - } - return Some(encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: light.target_view.as_ref().unwrap(), - depth_load_op: wgpu::LoadOp::Clear, - depth_store_op: wgpu::StoreOp::Store, - stencil_load_op: wgpu::LoadOp::Clear, - stencil_store_op: wgpu::StoreOp::Store, - clear_depth: 1.0, - clear_stencil: 0, - }), - })); - } - - None - } - - fn resize(&self, render_graph: &mut RenderGraphData) {} - - fn should_repeat(&self) -> bool { - return self.light_index != -1; - } -} - -pub struct ShadowPipeline { - pub pipeline: Option, - pub bind_group: Option, - pub shadow_format: wgpu::TextureFormat, -} - -pub const SHADOW_PIPELINE_UNIFORMS: &str = "shadow_pipeline"; - -impl ShadowPipeline { - pub fn new(shadow_format: wgpu::TextureFormat, shadow_size: wgpu::Extent3d, max_lights: usize) -> Self { - ShadowPipeline { - bind_group: None, - pipeline: None, - shadow_format, - } - } -} - -impl PipelineNew for ShadowPipeline { - fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World) { - let bind_group_layout = render_graph.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - bindings: &[wgpu::BindGroupLayoutBinding { - binding: 0, // global - visibility: wgpu::ShaderStage::VERTEX, - ty: wgpu::BindingType::UniformBuffer { dynamic: false }, - }], - }); - - // TODO: stop using "local" - let local_bind_group_layout = render_graph.get_bind_group_layout("local").unwrap(); - - let pipeline_layout = render_graph.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[ - &bind_group_layout, - local_bind_group_layout, - ], - }); - - let uniform_size = mem::size_of::() as wgpu::BufferAddress; - let uniform_buf = render_graph.device.create_buffer(&wgpu::BufferDescriptor { - size: uniform_size, - usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, - }); - - // Create bind group - self.bind_group = Some(render_graph.device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_group_layout, - bindings: &[wgpu::Binding { - binding: 0, - resource: wgpu::BindingResource::Buffer { - buffer: &uniform_buf, - range: 0..uniform_size, - }, - }], - })); - - render_graph.set_uniform_buffer(SHADOW_PIPELINE_UNIFORMS, UniformBuffer { - buffer: uniform_buf, - size: uniform_size, - }); - - // Create other resources - let shadow_sampler = render_graph.device.create_sampler(&wgpu::SamplerDescriptor { - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Nearest, - lod_min_clamp: -100.0, - lod_max_clamp: 100.0, - compare_function: wgpu::CompareFunction::LessEqual, - }); - - let vertex_buffer_descriptor = get_vertex_buffer_descriptor(); - - // Create the render pipeline - let vs_bytes = shader::load_glsl(include_str!("shadow.vert"), shader::ShaderStage::Vertex); - let fs_bytes = - shader::load_glsl(include_str!("shadow.frag"), shader::ShaderStage::Fragment); - let vs_module = render_graph.device.create_shader_module(&vs_bytes); - let fs_module = render_graph.device.create_shader_module(&fs_bytes); - - self.pipeline = Some(render_graph.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - layout: &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, - depth_bias: 2, // corresponds to bilinear filtering - depth_bias_slope_scale: 2.0, - depth_bias_clamp: 0.0, - }), - primitive_topology: wgpu::PrimitiveTopology::TriangleList, - color_states: &[], - depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { - format: self.shadow_format, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::LessEqual, - stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, - stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE, - stencil_read_mask: 0, - stencil_write_mask: 0, - }), - index_format: wgpu::IndexFormat::Uint16, - vertex_buffers: &[vertex_buffer_descriptor], - sample_count: 1, - sample_mask: !0, - alpha_to_coverage_enabled: false, - })); - } - - fn render( - &mut self, - render_graph: &RenderGraphData, - pass: &mut wgpu::RenderPass, - frame: &SwapChainOutput, - world: &mut World, - ) { - let mut mesh_query = - <(Read, Read>)>::query().filter(!component::()); - pass.set_bind_group(0, self.bind_group.as_ref().unwrap(), &[]); - - let mut mesh_storage = world - .resources - .get_mut::>() - .unwrap(); - for (entity, mesh) in mesh_query.iter_immutable(world) { - if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { - mesh_asset.setup_buffers(&render_graph.device); - - pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]); - pass.set_index_buffer(&mesh_asset.index_buffer.as_ref().unwrap(), 0); - pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); - pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1); - }; - } - } - - fn resize(&mut self, render_graph: &RenderGraphData) {} - - fn get_pipeline(&self) -> &wgpu::RenderPipeline { - self.pipeline.as_ref().unwrap() - } -} - -#[repr(C)] -pub struct ShadowUniforms { - pub proj: [[f32; 4]; 4], -} - -impl Pipeline for ShadowPassOld { - fn render( - &mut self, - device: &Device, - _: &SwapChainOutput, - encoder: &mut CommandEncoder, - world: &mut World, - render_resources: &RenderResources, - ) { - let mut light_query = <(Read, Read, Read)>::query(); - let mut mesh_query = - <(Read, Read>)>::query().filter(!component::()); - - for (i, (light, _, _)) in light_query.iter_immutable(world).enumerate() { - // if let None = light.target_view { - // light.target_view = Some(self.shadow_texture.create_view( - // &wgpu::TextureViewDescriptor { - // format: ShadowPassOld::SHADOW_FORMAT, - // dimension: wgpu::TextureViewDimension::D2, - // aspect: wgpu::TextureAspect::All, - // base_mip_level: 0, - // level_count: 1, - // base_array_layer: i as u32, - // array_layer_count: 1, - // }, - // )); - // } - - // The light uniform buffer already has the projection, - // let's just copy it over to the shadow uniform buffer. - encoder.copy_buffer_to_buffer( - &render_resources.light_uniform_buffer.buffer, - (i * mem::size_of::()) as wgpu::BufferAddress, - &self.uniform_buf, - 0, - 64, - ); - - let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: light.target_view.as_ref().unwrap(), - depth_load_op: wgpu::LoadOp::Clear, - depth_store_op: wgpu::StoreOp::Store, - stencil_load_op: wgpu::LoadOp::Clear, - stencil_store_op: wgpu::StoreOp::Store, - clear_depth: 1.0, - clear_stencil: 0, - }), - }); - pass.set_pipeline(&self.pipeline); - pass.set_bind_group(0, &self.bind_group, &[]); - - let mut mesh_storage = world - .resources - .get_mut::>() - .unwrap(); - for (entity, mesh) in mesh_query.iter_immutable(world) { - if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) { - mesh_asset.setup_buffers(device); - - pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]); - pass.set_index_buffer(&mesh_asset.index_buffer.as_ref().unwrap(), 0); - pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); - pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1); - }; - } - } - } - - fn resize(&mut self, _: &Device, _: &SwapChainDescriptor) {} - fn get_camera_uniform_buffer(&self) -> Option<&Buffer> { - None - } -} - -impl ShadowPassOld { - pub const SHADOW_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; - pub const SHADOW_SIZE: wgpu::Extent3d = wgpu::Extent3d { - width: 512, - height: 512, - depth: 1, - }; - - pub fn new( - device: &Device, - _: &World, - render_resources: &RenderResources, - vertex_buffer_descriptor: VertexBufferDescriptor, - ) -> ShadowPassOld { - // Create pipeline layout - let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - bindings: &[wgpu::BindGroupLayoutBinding { - binding: 0, // global - visibility: wgpu::ShaderStage::VERTEX, - ty: wgpu::BindingType::UniformBuffer { dynamic: false }, - }], - }); - let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[ - &bind_group_layout, - &render_resources.local_bind_group_layout, - ], - }); - - let uniform_size = mem::size_of::() as wgpu::BufferAddress; - let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { - size: uniform_size, - usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, - }); - - // Create bind group - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_group_layout, - bindings: &[wgpu::Binding { - binding: 0, - resource: wgpu::BindingResource::Buffer { - buffer: &uniform_buf, - range: 0..uniform_size, - }, - }], - }); - - let shadow_texture = device.create_texture(&wgpu::TextureDescriptor { - size: Self::SHADOW_SIZE, - array_layer_count: render_resources.max_lights as u32, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: Self::SHADOW_FORMAT, - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::SAMPLED, - }); - - let shadow_view = shadow_texture.create_default_view(); - - // Create other resources - let shadow_sampler = device.create_sampler(&wgpu::SamplerDescriptor { - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Nearest, - lod_min_clamp: -100.0, - lod_max_clamp: 100.0, - compare_function: wgpu::CompareFunction::LessEqual, - }); - - // Create the render pipeline - let vs_bytes = shader::load_glsl(include_str!("shadow.vert"), shader::ShaderStage::Vertex); - let fs_bytes = - shader::load_glsl(include_str!("shadow.frag"), shader::ShaderStage::Fragment); - let vs_module = device.create_shader_module(&vs_bytes); - let fs_module = device.create_shader_module(&fs_bytes); - - let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - layout: &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, - depth_bias: 2, // corresponds to bilinear filtering - depth_bias_slope_scale: 2.0, - depth_bias_clamp: 0.0, - }), - primitive_topology: wgpu::PrimitiveTopology::TriangleList, - color_states: &[], - depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { - format: Self::SHADOW_FORMAT, - depth_write_enabled: true, - depth_compare: wgpu::CompareFunction::LessEqual, - stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, - stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE, - stencil_read_mask: 0, - stencil_write_mask: 0, - }), - index_format: wgpu::IndexFormat::Uint16, - vertex_buffers: &[vertex_buffer_descriptor], - sample_count: 1, - sample_mask: !0, - alpha_to_coverage_enabled: false, - }); - - ShadowPassOld { - pipeline, - bind_group, - uniform_buf, - shadow_texture, - shadow_view, - shadow_sampler, - lights_are_dirty: true, - } - } -}