From 2a27cacba853f520d21b4bdaa7585a4793fe50cf Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 2 Dec 2019 15:19:56 -0800 Subject: [PATCH] lights and cameras data driven. setup moved to relevant passes --- examples/simple.rs | 58 ++++++ src/application.rs | 309 +++++++++++++------------------- src/legion_transform/Cargo.toml | 2 +- src/lib.rs | 2 + src/render/camera.rs | 42 ++++- src/render/forward/mod.rs | 15 +- src/render/light.rs | 7 +- src/render/mod.rs | 1 + src/render/pass.rs | 4 +- src/render/shadow/mod.rs | 33 +++- 10 files changed, 266 insertions(+), 207 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 72888c9bcc..92b69f9b35 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,6 +1,11 @@ use bevy::*; use bevy::{render::*, asset::{Asset, AssetStorage}, math}; +// fn build_move_system() -> Box { +// SystemBuilder::new("MoveSystem") +// .with_query(<>) +// } + fn main() { let universe = Universe::new(); let mut world = universe.create_world(); @@ -16,12 +21,14 @@ fn main() { world.resources.insert(mesh_storage); world.insert((), vec![ + // plane ( Material::new(math::vec4(0.1, 0.2, 0.1, 1.0)), plane_handle.clone(), LocalToWorld(math::translation(&math::vec3(0.0, 0.0, 0.0))), Translation::new(0.0, 0.0, 0.0) ), + // cubes ( Material::new(math::vec4(0.1, 0.1, 0.6, 1.0)), mesh_handle.clone(), @@ -35,6 +42,57 @@ fn main() { Translation::new(0.0, 0.0, 0.0) ), ]); + world.insert((), vec![ + // lights + ( + Light { + pos: math::vec3(7.0, -5.0, 10.0), + color: wgpu::Color { + r: 0.5, + g: 1.0, + b: 0.5, + a: 1.0, + }, + fov: f32::to_radians(60.0), + depth: 1.0 .. 20.0, + target_view: None, + }, + LocalToWorld(math::translation(&math::vec3(7.0, -5.0, 10.0))), + Translation::new(0.0, 0.0, 0.0) + ), + ( + Light { + pos: math::vec3(-5.0, 7.0, 10.0), + color: wgpu::Color { + r: 1.0, + g: 0.5, + b: 0.5, + a: 1.0, + }, + fov: f32::to_radians(45.0), + depth: 1.0 .. 20.0, + target_view: None, + }, + LocalToWorld(math::translation(&math::vec3(-1.5, 0.0, 1.0))), + Translation::new(0.0, 0.0, 0.0) + ), + ]); + world.insert((), vec![ + // camera + ( + Camera::new(CameraType::Projection { + fov: math::quarter_pi(), + near: 1.0, + far: 20.0, + aspect_ratio: 1.0, + }), + LocalToWorld(math::look_at_rh(&math::vec3(3.0, -10.0, 6.0), + &math::vec3(0.0, 0.0, 0.0), + &math::vec3(0.0, 0.0, 1.0),)), + Translation::new(0.0, 0.0, 0.0) + ) + ]); + // let transform_system_bundle = transform_system_bundle::build(&mut world); Application::run(universe, world); } \ No newline at end of file diff --git a/src/application.rs b/src/application.rs index bd9a7c23d5..56114598c8 100644 --- a/src/application.rs +++ b/src/application.rs @@ -2,6 +2,7 @@ use winit::{ event, event::WindowEvent, event_loop::{ControlFlow, EventLoop}, + window::Window, }; use zerocopy::AsBytes; @@ -10,33 +11,33 @@ use legion::prelude::*; use std::sync::Arc; use std::mem; +use wgpu::{Surface, Device, Queue, SwapChain, SwapChainDescriptor}; + use crate::{vertex::*, render::*, math, LocalToWorld, ApplicationStage}; pub struct Application { pub universe: Universe, pub world: World, + pub device: Device, + pub queue: Queue, + pub surface: Surface, + pub window: Window, + pub swap_chain: SwapChain, + pub swap_chain_descriptor: SwapChainDescriptor, pub scheduler: SystemScheduler, - pub shadow_pass: ShadowPass, - pub forward_pass: ForwardPass, - camera_position: math::Vec3, - camera_fov: f32, + pub render_passes: Vec>, } impl Application { pub const MAX_LIGHTS: usize = 10; - fn init( - universe: Universe, - mut world: World, - sc_desc: &wgpu::SwapChainDescriptor, - device: &wgpu::Device, - ) -> (Self, Option) - { - let vertex_size = mem::size_of::(); + fn add_default_passes(&mut self) { + let light_uniform_size = + (Self::MAX_LIGHTS * mem::size_of::()) as wgpu::BufferAddress; let local_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { bindings: &[wgpu::BindGroupLayoutBinding { binding: 0, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, @@ -44,16 +45,25 @@ impl Application { }], }); + let light_uniform_buffer = Arc::new(UniformBuffer { + buffer: self.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, + }); - let mut entities = >::query(); - for mut entity in entities.iter(&mut world) { + let mut materials = >::query(); + for mut material in materials.iter(&mut self.world) { let entity_uniform_size = mem::size_of::() as wgpu::BufferAddress; - let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { + let uniform_buf = self.device.create_buffer(&wgpu::BufferDescriptor { size: entity_uniform_size, usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, }); - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &local_bind_group_layout, bindings: &[wgpu::Binding { binding: 0, @@ -64,12 +74,17 @@ impl Application { }], }); - entity.bind_group = Some(bind_group); - entity.uniform_buf = Some(uniform_buf); + material.bind_group = Some(bind_group); + material.uniform_buf = Some(uniform_buf); } - let camera_position = math::vec3(3.0f32, -10.0, 6.0); - let camera_fov = math::quarter_pi(); + let light_count = >::query().iter(&mut self.world).count(); + let forward_uniforms = ForwardUniforms { + proj: math::Mat4::identity().into(), + num_lights: [light_count as u32, 0, 0, 0], + }; + + let vertex_size = mem::size_of::(); let vb_desc = wgpu::VertexBufferDescriptor { stride: vertex_size as wgpu::BufferAddress, @@ -88,162 +103,94 @@ impl Application { ], }; - let light_uniform_size = - (Self::MAX_LIGHTS * mem::size_of::()) as wgpu::BufferAddress; - - 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, - }); - - let shadow_pass = ShadowPass::new(device, light_uniform_buffer.clone(), vb_desc.clone(), &local_bind_group_layout, Self::MAX_LIGHTS as u32); - - let mut shadow_target_views = (0 .. 2) - .map(|i| { - Some(shadow_pass.shadow_texture.create_view(&wgpu::TextureViewDescriptor { - format: ShadowPass::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, - })) - }) - .collect::>(); - - let lights = vec![ - (Light { - pos: math::vec3(7.0, -5.0, 10.0), - color: wgpu::Color { - r: 0.5, - g: 1.0, - b: 0.5, - a: 1.0, - }, - fov: f32::to_radians(60.0), - depth: 1.0 .. 20.0, - target_view: shadow_target_views[0].take().unwrap(), - },), - (Light { - pos: math::vec3(-5.0, 7.0, 10.0), - color: wgpu::Color { - r: 1.0, - g: 0.5, - b: 0.5, - a: 1.0, - }, - fov: f32::to_radians(45.0), - depth: 1.0 .. 20.0, - target_view: shadow_target_views[1].take().unwrap(), - },), - ]; - - let light_count = lights.len(); - world.insert((), lights); - - let matrix = camera::get_projection_view_matrix(&camera_position, camera_fov, sc_desc.width as f32 / sc_desc.height as f32, 1.0, 20.0); - let forward_uniforms = ForwardUniforms { - proj: *matrix.as_ref(), - num_lights: [light_count as u32, 0, 0, 0], - }; - - let forward_pass = ForwardPass::new(device, forward_uniforms, light_uniform_buffer.clone(), &shadow_pass, vb_desc, &local_bind_group_layout, sc_desc); - - let this = Application { - universe, - world, - scheduler: SystemScheduler::new(), - shadow_pass, - forward_pass, - camera_position, - camera_fov - }; - (this, None) + let shadow_pass = ShadowPass::new(&mut self.device, &mut self.world, light_uniform_buffer.clone(), vb_desc.clone(), &local_bind_group_layout, Self::MAX_LIGHTS as u32); + let forward_pass = ForwardPass::new(&mut self.device, forward_uniforms, light_uniform_buffer.clone(), &shadow_pass, vb_desc, &local_bind_group_layout, &self.swap_chain_descriptor); + self.render_passes.push(Box::new(shadow_pass)); + self.render_passes.push(Box::new(forward_pass)); } - fn resize( - &mut self, - sc_desc: &wgpu::SwapChainDescriptor, - device: &wgpu::Device, - ) -> Option + fn resize(&mut self, width: u32, height: u32) { - let command_buf = { - let mx_total = camera::get_projection_view_matrix(&self.camera_position, self.camera_fov, sc_desc.width as f32 / sc_desc.height as f32, 1.0, 20.0); - let mx_ref: [[f32; 4]; 4] = mx_total.into(); + self.swap_chain_descriptor.width = width; + self.swap_chain_descriptor.height = height; + self.swap_chain = self.device.create_swap_chain(&self.surface, &self.swap_chain_descriptor); + let mut encoder = + self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); + + for (mut camera, local_to_world) in <(Write, Read)>::query().iter(&mut self.world) { + camera.update(self.swap_chain_descriptor.width, self.swap_chain_descriptor.height); + let camera_matrix: [[f32; 4]; 4] = (camera.view_matrix * local_to_world.0).into(); let temp_buf = - device.create_buffer_with_data(mx_ref.as_bytes(), wgpu::BufferUsage::COPY_SRC); + self.device.create_buffer_with_data(camera_matrix.as_bytes(), wgpu::BufferUsage::COPY_SRC); + for pass in self.render_passes.iter() { + if let Some(buffer) = pass.get_camera_uniform_buffer() { + encoder.copy_buffer_to_buffer(&temp_buf, 0, buffer, 0, 64); + } + } + } - let mut encoder = - device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); - encoder.copy_buffer_to_buffer(&temp_buf, 0, &self.forward_pass.forward_uniform_buffer, 0, 64); - encoder.finish() - }; + let command_buffer = encoder.finish(); - self.forward_pass.update_swap_chain_descriptor(device, sc_desc); - - Some(command_buf) + for pass in self.render_passes.iter_mut() { + pass.resize(&mut self.device, &mut self.swap_chain_descriptor); + } + self.queue.submit(&[command_buffer]); } fn update(&mut self, _: WindowEvent) { } - fn render( - &mut self, - frame: &wgpu::SwapChainOutput, - device: &wgpu::Device, - ) -> wgpu::CommandBuffer + fn render(&mut self) { + let mut frame = self.swap_chain + .get_next_texture() + .expect("Timeout when acquiring next swap chain texture"); + let mut encoder = - device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); + self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); + let mut entities = <(Read, Read)>::query(); + let entities_count = entities.iter(&mut self.world).count(); + let size = mem::size_of::(); + let temp_buf_data = self.device + .create_buffer_mapped(entities_count * size, wgpu::BufferUsage::COPY_SRC); + + for ((entity, transform), slot) in entities.iter(&mut self.world) + .zip(temp_buf_data.data.chunks_exact_mut(size)) { - let mut entities = <(Read, Read)>::query(); - let entities_count = entities.iter(&mut self.world).count(); - let size = mem::size_of::(); - let temp_buf_data = device - .create_buffer_mapped(entities_count * size, wgpu::BufferUsage::COPY_SRC); - - for ((entity, transform), slot) in entities.iter(&mut self.world) - .zip(temp_buf_data.data.chunks_exact_mut(size)) - { - slot.copy_from_slice( - MaterialUniforms { - model: transform.0.into(), - color: [ - entity.color.x as f32, - entity.color.y as f32, - entity.color.z as f32, - entity.color.w as f32, - ], - } - .as_bytes(), - ); - } - - let temp_buf = temp_buf_data.finish(); - - for (i, (entity, _)) in entities.iter(&mut self.world).enumerate() { - encoder.copy_buffer_to_buffer( - &temp_buf, - (i * size) as wgpu::BufferAddress, - entity.uniform_buf.as_ref().unwrap(), - 0, - size as wgpu::BufferAddress, - ); - } + slot.copy_from_slice( + MaterialUniforms { + model: transform.0.into(), + color: [ + entity.color.x as f32, + entity.color.y as f32, + entity.color.z as f32, + entity.color.w as f32, + ], + } + .as_bytes(), + ); } - self.shadow_pass.render(device, frame, &mut encoder, &mut self.world); - self.forward_pass.render(device, frame, &mut encoder, &mut self.world); + let temp_buf = temp_buf_data.finish(); - encoder.finish() + for (i, (entity, _)) in entities.iter(&mut self.world).enumerate() { + encoder.copy_buffer_to_buffer( + &temp_buf, + (i * size) as wgpu::BufferAddress, + entity.uniform_buf.as_ref().unwrap(), + 0, + size as wgpu::BufferAddress, + ); + } + + for pass in self.render_passes.iter_mut() { + pass.render(&mut self.device, &mut frame, &mut encoder, &mut self.world); + } + + let command_buffer = encoder.finish(); + self.queue.submit(&[command_buffer]); } #[allow(dead_code)] @@ -260,14 +207,14 @@ impl Application { ) .unwrap(); - let (device, mut queue) = adapter.request_device(&wgpu::DeviceDescriptor { + let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor { extensions: wgpu::Extensions { anisotropic_filtering: false, }, limits: wgpu::Limits::default(), }); - let (_window, hidpi_factor, size, surface) = { + let (window, hidpi_factor, size, surface) = { let window = winit::window::Window::new(&event_loop).unwrap(); window.set_title("bevy"); let hidpi_factor = window.hidpi_factor(); @@ -276,20 +223,30 @@ impl Application { (window, hidpi_factor, size, surface) }; - let mut sc_desc = wgpu::SwapChainDescriptor { + let swap_chain_descriptor = wgpu::SwapChainDescriptor { usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, format: wgpu::TextureFormat::Bgra8UnormSrgb, width: size.width.round() as u32, height: size.height.round() as u32, present_mode: wgpu::PresentMode::Vsync, }; - let mut swap_chain = device.create_swap_chain(&surface, &sc_desc); + let swap_chain = device.create_swap_chain(&surface, &swap_chain_descriptor); log::info!("Initializing the example..."); - let (mut example, init_command_buf) = Application::init(universe, world, &sc_desc, &device); - if let Some(command_buf) = init_command_buf { - queue.submit(&[command_buf]); - } + let mut app = Application { + universe, + world, + device, + surface, + window, + queue, + swap_chain, + swap_chain_descriptor, + scheduler: SystemScheduler::new(), + render_passes: Vec::new(), + }; + + app.add_default_passes(); log::info!("Entering render loop..."); event_loop.run(move |event, _, control_flow| { @@ -305,13 +262,9 @@ impl Application { } => { let physical = size.to_physical(hidpi_factor); log::info!("Resizing to {:?}", physical); - sc_desc.width = physical.width.round() as u32; - sc_desc.height = physical.height.round() as u32; - swap_chain = device.create_swap_chain(&surface, &sc_desc); - let command_buf = example.resize(&sc_desc, &device); - if let Some(command_buf) = command_buf { - queue.submit(&[command_buf]); - } + let width = physical.width.round() as u32; + let height = physical.height.round() as u32; + app.resize(width, height); } event::Event::WindowEvent { event, .. } => match event { WindowEvent::KeyboardInput { @@ -327,16 +280,12 @@ impl Application { *control_flow = ControlFlow::Exit; } _ => { - example.update(event); + app.update(event); } }, event::Event::EventsCleared => { - let frame = swap_chain - .get_next_texture() - .expect("Timeout when acquiring next swap chain texture"); - example.scheduler.execute(&mut example.world); - let command_buf = example.render(&frame, &device); - queue.submit(&[command_buf]); + app.scheduler.execute(&mut app.world); + app.render(); } _ => (), } diff --git a/src/legion_transform/Cargo.toml b/src/legion_transform/Cargo.toml index 9ca02e66b0..c051b229a4 100644 --- a/src/legion_transform/Cargo.toml +++ b/src/legion_transform/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" license = "MIT" [dependencies] -legion = { git = "https://github.com/TomGillen/legion.git" } +legion = { git = "https://github.com/TomGillen/legion.git", rev = "8628b227bcbe57582fffb5e80e73c634ec4eebd9" } #legion = { path = "../legion" } log = "0.4" nalgebra = { version = "0.19.0" } diff --git a/src/lib.rs b/src/lib.rs index ed650184c0..2d28baface 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,5 +11,7 @@ pub use wgpu; pub use legion; pub use legion_transform; pub use legion::prelude::*; +pub use legion::schedule::Schedulable; pub use legion_transform::prelude::*; +pub use legion_transform::transform_system_bundle; pub use nalgebra_glm as math; \ No newline at end of file diff --git a/src/render/camera.rs b/src/render/camera.rs index 1e8634da01..2f64b04a8f 100644 --- a/src/render/camera.rs +++ b/src/render/camera.rs @@ -1,15 +1,41 @@ use crate::math; -pub fn get_projection_view_matrix(eye: &math::Vec3, fov: f32, aspect_ratio: f32, near: f32, far: f32) -> math::Mat4 { +pub enum CameraType { + Projection { + fov: f32, + aspect_ratio: f32, + near: f32, + far: f32 + } +} + +pub struct Camera { + pub view_matrix: math::Mat4, + pub camera_type: CameraType, +} + +impl Camera { + pub fn new(camera_type: CameraType) -> Self { + Camera { + view_matrix: math::identity(), + camera_type, + } + } + + pub fn update(&mut self, width: u32, height: u32) { + match &mut self.camera_type { + CameraType::Projection { mut aspect_ratio, fov, near, far } => { + aspect_ratio = width as f32 / height as f32; + self.view_matrix = get_projection_matrix(aspect_ratio, *fov, *near, *far) + } + } + } +} + +pub fn get_projection_matrix(fov: f32, aspect_ratio: f32, near: f32, far: f32) -> math::Mat4 { let projection = math::perspective(aspect_ratio, fov, near, far); - let view = math::look_at_rh::( - &eye, - &math::vec3(0.0, 0.0, 0.0), - &math::vec3(0.0, 0.0, 1.0), - ); - - opengl_to_wgpu_matrix() * projection * view + opengl_to_wgpu_matrix() * projection } pub fn opengl_to_wgpu_matrix() -> math::Mat4 { diff --git a/src/render/forward/mod.rs b/src/render/forward/mod.rs index 40c5f5bc6d..edfa342e21 100644 --- a/src/render/forward/mod.rs +++ b/src/render/forward/mod.rs @@ -2,7 +2,7 @@ use crate::{render::*, asset::*, render::mesh::*}; use legion::prelude::*; use std::{mem, sync::Arc}; use zerocopy::{AsBytes, FromBytes}; -use wgpu::{CommandEncoder, Device, BindGroupLayout, VertexBufferDescriptor, SwapChainDescriptor, SwapChainOutput}; +use wgpu::{Buffer, CommandEncoder, Device, BindGroupLayout, VertexBufferDescriptor, SwapChainDescriptor, SwapChainOutput}; #[repr(C)] #[derive(Clone, Copy, AsBytes, FromBytes)] @@ -60,6 +60,14 @@ impl Pass for ForwardPass { }; } } + + 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 ForwardPass { @@ -198,11 +206,6 @@ impl ForwardPass { } } - - pub fn update_swap_chain_descriptor(&mut self, device: &Device, swap_chain_descriptor: &SwapChainDescriptor) { - self.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 { diff --git a/src/render/light.rs b/src/render/light.rs index 002f7ff385..2bc3cec015 100644 --- a/src/render/light.rs +++ b/src/render/light.rs @@ -8,7 +8,7 @@ pub struct Light { pub color: wgpu::Color, pub fov: f32, pub depth: Range, - pub target_view: wgpu::TextureView, + pub target_view: Option, } #[repr(C)] @@ -20,9 +20,10 @@ pub struct LightRaw { } impl Light { - pub fn to_raw(&self) -> LightRaw { + pub fn to_raw(&self, transform: &math::Mat4) -> LightRaw { + let proj = camera::get_projection_matrix(self.fov, 1.0, self.depth.start, self.depth.end) * transform; LightRaw { - proj: camera::get_projection_view_matrix(&self.pos, self.fov, 1.0, self.depth.start, self.depth.end).into(), + proj: proj.into(), pos: [self.pos.x, self.pos.y, self.pos.z, 1.0], color: [ self.color.r as f32, diff --git a/src/render/mod.rs b/src/render/mod.rs index 12f20ed4e2..3009599242 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -14,6 +14,7 @@ pub use shader::*; pub use pass::*; pub use material::*; pub use mesh::*; +pub use camera::*; pub struct UniformBuffer { pub buffer: wgpu::Buffer, diff --git a/src/render/pass.rs b/src/render/pass.rs index 04ae952280..071ad8a608 100644 --- a/src/render/pass.rs +++ b/src/render/pass.rs @@ -1,6 +1,8 @@ use legion::world::World; -use wgpu::{CommandEncoder, Device, SwapChainOutput}; +use wgpu::{Buffer, CommandEncoder, Device, SwapChainDescriptor, SwapChainOutput}; pub trait Pass { fn render(&mut self, device: &Device, frame: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World); + fn resize(&mut self, device: &Device, frame: &SwapChainDescriptor); + fn get_camera_uniform_buffer(&self) -> Option<&Buffer>; } \ No newline at end of file diff --git a/src/render/shadow/mod.rs b/src/render/shadow/mod.rs index 5fa4e3cfdb..408185f60b 100644 --- a/src/render/shadow/mod.rs +++ b/src/render/shadow/mod.rs @@ -1,5 +1,5 @@ -use crate::{render::*, asset::*}; -use wgpu::{BindGroupLayout, CommandEncoder, Device, VertexBufferDescriptor, SwapChainOutput}; +use crate::{render::*, asset::*, LocalToWorld}; +use wgpu::{BindGroupLayout, Buffer, CommandEncoder, Device, VertexBufferDescriptor, SwapChainOutput, SwapChainDescriptor}; use legion::prelude::*; use zerocopy::AsBytes; use std::{mem, sync::Arc}; @@ -22,7 +22,7 @@ pub struct ShadowUniforms { impl Pass for ShadowPass { fn render(&mut self, device: &Device, _: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World) { - let mut light_query = >::query(); + let mut light_query = <(Read, Read)>::query(); let mut mesh_query = <(Read, Read>)>::query(); let light_count = light_query.iter(world).count(); @@ -32,11 +32,11 @@ impl Pass for ShadowPass { let total_size = size * light_count; let temp_buf_data = device.create_buffer_mapped(total_size, wgpu::BufferUsage::COPY_SRC); - for (light, slot) in light_query + for ((light, local_to_world), slot) in light_query .iter(world) .zip(temp_buf_data.data.chunks_exact_mut(size)) { - slot.copy_from_slice(light.to_raw().as_bytes()); + slot.copy_from_slice(light.to_raw(&local_to_world.0).as_bytes()); } encoder.copy_buffer_to_buffer( &temp_buf_data.finish(), @@ -47,7 +47,21 @@ impl Pass for ShadowPass { ); } - for (i, light) in light_query.iter_immutable(world).enumerate() { + for (i, (mut light, _)) in <(Write, Read)>::query().iter(world).enumerate() { + if let None = light.target_view { + light.target_view = Some(self.shadow_texture.create_view(&wgpu::TextureViewDescriptor { + format: ShadowPass::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, + })); + } + } + + for (i, (light, _)) in light_query.iter_immutable(world).enumerate() { // The light uniform buffer already has the projection, // let's just copy it over to the shadow uniform buffer. encoder.copy_buffer_to_buffer( @@ -61,7 +75,7 @@ impl Pass for ShadowPass { let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { color_attachments: &[], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: &light.target_view, + 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, @@ -87,6 +101,9 @@ impl Pass for ShadowPass { } } } + + fn resize(&mut self, _: &Device, _: &SwapChainDescriptor) { } + fn get_camera_uniform_buffer(&self) -> Option<&Buffer> { None } } impl ShadowPass { @@ -97,7 +114,7 @@ impl ShadowPass { depth: 1, }; - pub fn new(device: &Device, light_uniform_buffer: Arc::, vertex_buffer_descriptor: VertexBufferDescriptor, local_bind_group_layout: &BindGroupLayout, max_lights: u32) -> ShadowPass { + pub fn new(device: &Device, _: &World, light_uniform_buffer: Arc::, vertex_buffer_descriptor: VertexBufferDescriptor, local_bind_group_layout: &BindGroupLayout, max_lights: u32) -> ShadowPass { // Create pipeline layout let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {