From 8d7a62da7fe6400b4bca4747d6581d1baa971b04 Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Wed, 3 Feb 2021 22:56:38 -0800 Subject: [PATCH] uncommented and fixed the lights, but everything still is mega-dark --- src/light.rs | 17 +-- src/main.rs | 27 ++-- src/render.rs | 361 ++++++++++++++++--------------------------------- src/runtime.rs | 48 +++---- 4 files changed, 151 insertions(+), 302 deletions(-) diff --git a/src/light.rs b/src/light.rs index cd7d150..6ceef42 100644 --- a/src/light.rs +++ b/src/light.rs @@ -1,13 +1,7 @@ use bytemuck::__core::ops::Range; use bytemuck::{Zeroable, Pod}; -use crate::OPENGL_TO_WGPU_MATRIX; +use crate::{OPENGL_TO_WGPU_MATRIX, DirectionalLight, Position}; -pub struct Light { - pub(crate) pos: cgmath::Point3, - pub(crate) color: wgpu::Color, - pub(crate) fov: f32, - pub(crate) depth: Range, -} #[repr(C)] #[derive(Clone, Copy)] @@ -21,11 +15,12 @@ unsafe impl Pod for LightRaw {} unsafe impl Zeroable for LightRaw {} -impl Light { - fn to_raw(&self) -> LightRaw { +impl DirectionalLight { + pub fn to_raw(&self, pos: Position) -> LightRaw { use cgmath::{Deg, EuclideanSpace, Matrix4, PerspectiveFov, Point3, Vector3}; - let mx_view = Matrix4::look_at(self.pos, Point3::origin(), Vector3::unit_z()); + let pos = cgmath::Point3::new(pos.x, pos.y, pos.z); + let mx_view = Matrix4::look_at(pos, Point3::origin(), Vector3::unit_z()); let projection = PerspectiveFov { fovy: Deg(self.fov).into(), aspect: 1.0, @@ -37,7 +32,7 @@ impl Light { mx_correction * cgmath::Matrix4::from(projection.to_perspective()) * mx_view; LightRaw { proj: *mx_view_proj.as_ref(), - pos: [self.pos.x, self.pos.y, self.pos.z, 1.0], + pos: [pos.x, pos.y, pos.z, 1.0], color: [ self.color.r as f32, self.color.g as f32, diff --git a/src/main.rs b/src/main.rs index 6edfd62..804a0f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use bytemuck::__core::ops::Range; use cgmath::{Matrix4, Point3}; use futures::task::LocalSpawn; use legion::*; -use wgpu::{BindGroup, Buffer}; +use wgpu::{BindGroup, Buffer, TextureView}; use wgpu_subscriber; use winit::platform::unix::x11::ffi::Time; use winit::{ @@ -119,11 +119,12 @@ pub struct RangeCopy { pub end: Idx, } -#[derive(Clone, Copy, Debug, PartialEq)] -struct DirectionalLight { +#[derive(Clone, Debug)] +pub struct DirectionalLight { color: wgpu::Color, fov: f32, depth: RangeCopy, + target_view: Arc, } #[derive(Clone, Debug)] @@ -219,23 +220,11 @@ fn main() { // This could be used for relationships between entities...??? let light_entity: Entity = world.push(( cgmath::Point3 { - x: -5.0, - y: 7.0, - z: 10.0, - }, - DirectionalLight { - color: wgpu::Color { - r: 1.0, - g: 0.5, - b: 0.5, - a: 1.0, - }, - fov: 45.0, - depth: RangeCopy { - start: 1.0, - end: 20.0, - }, + x: -5.0 as f32, + y: 7.0 as f32, + z: 10.0 as f32, }, + renderer.create_light(), )); let mesh_entity: Entity = world.push(( diff --git a/src/render.rs b/src/render.rs index d1eca02..2f81f74 100644 --- a/src/render.rs +++ b/src/render.rs @@ -8,14 +8,15 @@ use futures::executor::LocalPool; use legion::world::SubWorld; use legion::*; use wgpu::util::DeviceExt; -use wgpu::{Buffer, Device, Instance, Queue, Surface, SwapChain, SwapChainDescriptor, SwapChainFrame, BindGroup, BindGroupLayout}; +use wgpu::{BindGroup, BindGroupLayout, Buffer, Device, Instance, Queue, Surface, SwapChain, SwapChainDescriptor, SwapChainFrame, TextureView}; use winit::dpi::PhysicalSize; use winit::platform::unix::x11::ffi::Time; use winit::window::Window; use crate::geometry::{create_plane, import_mesh, Vertex}; use crate::light::LightRaw; -use crate::{Color, Mesh, Position, Velocity, OPENGL_TO_WGPU_MATRIX}; +use crate::{Color, DirectionalLight, Mesh, Position, RangeCopy, Velocity, OPENGL_TO_WGPU_MATRIX}; + #[repr(C)] #[derive(Clone, Copy)] @@ -67,8 +68,9 @@ pub struct Renderer { forward_depth: wgpu::TextureView, entity_bind_group_layout: BindGroupLayout, - light_uniform_buf: wgpu::Buffer, + shadow_target_views: Vec>, + light_uniform_buf: wgpu::Buffer, } impl Renderer { @@ -93,26 +95,12 @@ impl Renderer { } } -/* -SOOOOOOOOOOOOooo... Legion systems have to be standalone functions, which is fine -we can do a special kind of song and dance - -Main loop { - - renderer - runtime - - render_system(param1,2,3, renderer); - animation_system(param1,2,3, runtime); - - renderer.finalize() - -} - */ #[system] #[write_component(Position)] +#[write_component(Point3)] #[write_component(Mesh)] #[write_component(Color)] +#[write_component(DirectionalLight)] pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { let frame = renderer.get_current_frame(); @@ -120,11 +108,8 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { // Update the entity uniforms for (pos, mesh, color) in query.iter_mut(world) { - // Revolve the entity by the rotation speed, only if it is non-zero - // if vel.rs != 0.0 { - // let rotation = cgmath::Matrix4::from_angle_x(cgmath::Deg(vel.rs)); - // pos.mx = pos.mx * rotation; - // } + let rotation = cgmath::Matrix4::from_angle_x(cgmath::Deg(1.0)); + pos.mx = pos.mx * rotation; let data = EntityUniforms { model: pos.mx.into(), @@ -140,66 +125,78 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { .write_buffer(&mesh.uniform_buffer, 0, bytemuck::bytes_of(&data)); } - // if self.lights_are_dirty { - // self.lights_are_dirty = false; - // for (i, light) in self.lights.iter().enumerate() { - // queue.write_buffer( - // &self.light_uniform_buf, - // (i * mem::size_of::()) as wgpu::BufferAddress, - // bytemuck::bytes_of(&light.to_raw()), - // ); - // } - // } + if renderer.lights_are_dirty { + renderer.lights_are_dirty = false; + let mut query = <(&mut DirectionalLight, &mut Position)>::query(); + for (i, (light, pos)) in query.iter_mut(world).enumerate() { + renderer.queue.write_buffer( + &renderer.light_uniform_buf, + (i * mem::size_of::()) as wgpu::BufferAddress, + bytemuck::bytes_of(&light.to_raw(*pos)), + ); + } + } let mut encoder = renderer .device .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); encoder.push_debug_group("shadow passes"); - /*for (i, light) in self.lights.iter().enumerate() { + + let mut query = <(&mut DirectionalLight, &mut Point3)>::query(); + + let mut light_stack = Vec::new(); + for (i, (light, pos)) in query.iter_mut(world).enumerate() { + + light_stack.push(light.clone()); encoder.push_debug_group(&format!( "shadow pass {} (light at position {:?})", - i, light.pos + i, pos )); // The light uniform buffer already has the projection, // let's just copy it over to the shadow uniform buffer. encoder.copy_buffer_to_buffer( - &self.light_uniform_buf, + &renderer.light_uniform_buf, (i * mem::size_of::()) as wgpu::BufferAddress, - &self.shadow_pass.uniform_buf, + &renderer.shadow_pass.uniform_buf, 0, 64, ); + encoder.pop_debug_group(); + } + + for light in light_stack { encoder.insert_debug_marker("render entities"); { let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { color_attachments: &[], - depth_stencil_attachment: Some( - wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: &light.target_view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: true, - }), - stencil_ops: None, - }, - ), + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &light.target_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: true, + }), + stencil_ops: None, + }), }); - pass.set_pipeline(&self.shadow_pass.pipeline); - pass.set_bind_group(0, &self.shadow_pass.bind_group, &[]); - - for entity in &self.entities { - pass.set_bind_group(1, &entity.bind_group, &[]); - pass.set_index_buffer(entity.index_buf.slice(..)); - pass.set_vertex_buffer(0, entity.vertex_buf.slice(..)); - pass.draw_indexed(0..entity.index_count as u32, 0, 0..1); + pass.set_pipeline(&renderer.shadow_pass.pipeline); + pass.set_bind_group(0, &renderer.shadow_pass.bind_group, &[]); + + let mut query = <(&mut Position, &mut Mesh, &mut Color)>::query(); + + for (pos, mesh, color) in query.iter_mut(world) { + pass.set_bind_group(1, &mesh.bind_group, &[]); + pass.set_index_buffer(mesh.index_buffer.slice(..)); + pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); + pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); } } + } + + - encoder.pop_debug_group(); - }*/ encoder.pop_debug_group(); // forward pass @@ -258,7 +255,6 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) { } impl Renderer { - pub fn get_current_frame(&mut self) -> SwapChainFrame { // Update the renderers swapchain state match self.swapchain.get_current_frame() { @@ -299,25 +295,28 @@ impl Renderer { }), ); - // // Creates the vertex and index buffers for the plane - // let (plane_vertex_data, plane_index_data) = create_plane(7.0); - // self.plane_vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - // label: Some("Plane Vertex Buffer"), - // contents: bytemuck::cast_slice(&plane_vertex_data), - // usage: wgpu::BufferUsage::VERTEX, - // }); - // - // self.plane_index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - // label: Some("Plane Index Buffer"), - // contents: bytemuck::cast_slice(&plane_index_data), - // usage: wgpu::BufferUsage::INDEX, - // }); - - // Creates the uniform for entities, which does the rotation and projection - (vertex_buf, index_buf) } + pub fn create_light(&self) -> DirectionalLight { + + let target = self.shadow_target_views.get(0).take().unwrap(); + DirectionalLight { + color: wgpu::Color { + r: 1.0, + g: 0.5, + b: 0.5, + a: 1.0, + }, + fov: 45.0, + depth: RangeCopy { + start: 1.0, + end: 20.0, + }, + target_view: target.clone() + } + } + pub fn load_mesh_to_buffer(&self, filepath: &str) -> Mesh { let (vertices, indices) = import_mesh(filepath); let index_count = indices.len(); @@ -370,11 +369,6 @@ impl Renderer { let optional_features = Renderer::optional_features(); let required_features = Renderer::required_features(); let adapter_features = adapter.features(); - // assert!( - // adapter_features.contains(required_features), - // "Adapter does not support required features for this example: {:?}", - // required_features - adapter_features - // ); let needed_limits = wgpu::Limits::default(); //Renderer::required_limits(); @@ -453,19 +447,6 @@ impl Renderer { mapped_at_creation: false, }); - // Pre init the light uniform, with slots enough for MAX_LIGHTS - let light_uniform_size = - (Self::MAX_LIGHTS * mem::size_of::()) as wgpu::BufferAddress; - - let light_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { - label: None, - size: light_uniform_size, - usage: wgpu::BufferUsage::UNIFORM - | wgpu::BufferUsage::COPY_SRC - | wgpu::BufferUsage::COPY_DST, - mapped_at_creation: false, - }); - // This seems way way way way easier than what I was doing in tracer // Though the attr thing is still a macro. Which would cause issues if // I wanted to get tricky with the 0,1 types @@ -494,7 +475,6 @@ impl Renderer { }], }); - /* There appear to be two passes required for shadows, the shadow pass, and the forward pass Need to open this up in renderdoc and see what it's actually doing @@ -592,6 +572,44 @@ impl Renderer { } }; + // Pre init the light uniform, with slots enough for MAX_LIGHTS + let light_uniform_size = + (Self::MAX_LIGHTS * mem::size_of::()) as wgpu::BufferAddress; + + let light_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: light_uniform_size, + usage: wgpu::BufferUsage::UNIFORM + | wgpu::BufferUsage::COPY_SRC + | wgpu::BufferUsage::COPY_DST, + mapped_at_creation: false, + }); + + let shadow_texture = device.create_texture(&wgpu::TextureDescriptor { + size: Self::SHADOW_SIZE, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: Self::SHADOW_FORMAT, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::SAMPLED, + label: None, + }); + + let mut shadow_target_views = (0..2) + .map(|i| { + Arc::new(shadow_texture.create_view(&wgpu::TextureViewDescriptor { + label: Some("shadow"), + format: None, + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + level_count: None, + base_array_layer: i as u32, + array_layer_count: NonZeroU32::new(1), + })) + }) + .collect::>(); + let forward_pass = { // Create pipeline layout let bind_group_layout = @@ -660,30 +678,7 @@ impl Renderer { usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, }); - let shadow_texture = device.create_texture(&wgpu::TextureDescriptor { - size: Self::SHADOW_SIZE, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: Self::SHADOW_FORMAT, - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::SAMPLED, - label: None, - }); - let mut shadow_target_views = (0..2) - .map(|i| { - Some(shadow_texture.create_view(&wgpu::TextureViewDescriptor { - label: Some("shadow"), - format: None, - dimension: Some(wgpu::TextureViewDimension::D2), - aspect: wgpu::TextureAspect::All, - base_mip_level: 0, - level_count: None, - base_array_layer: i as u32, - array_layer_count: NonZeroU32::new(1), - })) - }) - .collect::>(); // shadow_target_views[0].take().unwrap(), // pub(crate) target_view: wgpu::TextureView, @@ -796,142 +791,12 @@ impl Renderer { forward_pass, forward_depth: depth_texture.create_view(&wgpu::TextureViewDescriptor::default()), entity_bind_group_layout: entity_bind_group_layout, + shadow_target_views: shadow_target_views, light_uniform_buf, swapchain_description: sc_desc, surface, instance: Arc::new(instance), - - } - } - - pub fn render( - &mut self, - frame: &wgpu::SwapChainTexture, - device: &wgpu::Device, - queue: &wgpu::Queue, - _spawner: &impl futures::task::LocalSpawn, - ) { - // update uniforms - // for entity in self.entities.iter_mut() { - // - // // Revolve the entity by the rotation speed, only if it is non-zero - // if entity.rotation_speed != 0.0 { - // let rotation = cgmath::Matrix4::from_angle_x(cgmath::Deg(entity.rotation_speed)); - // entity.mx_world = entity.mx_world * rotation; - // } - // - // let data = EntityUniforms { - // model: entity.mx_world.into(), - // color: [ - // entity.color.r as f32, - // entity.color.g as f32, - // entity.color.b as f32, - // entity.color.a as f32, - // ], - // }; - // queue.write_buffer(&entity.uniform_buf, 0, bytemuck::bytes_of(&data)); - // } - - // if self.lights_are_dirty { - // self.lights_are_dirty = false; - // for (i, light) in self.lights.iter().enumerate() { - // queue.write_buffer( - // &self.light_uniform_buf, - // (i * mem::size_of::()) as wgpu::BufferAddress, - // bytemuck::bytes_of(&light.to_raw()), - // ); - // } - // } - - let mut encoder = - device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); - - encoder.push_debug_group("shadow passes"); - /*for (i, light) in self.lights.iter().enumerate() { - encoder.push_debug_group(&format!( - "shadow pass {} (light at position {:?})", - i, light.pos - )); - - // The light uniform buffer already has the projection, - // let's just copy it over to the shadow uniform buffer. - encoder.copy_buffer_to_buffer( - &self.light_uniform_buf, - (i * mem::size_of::()) as wgpu::BufferAddress, - &self.shadow_pass.uniform_buf, - 0, - 64, - ); - - encoder.insert_debug_marker("render entities"); - { - let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[], - depth_stencil_attachment: Some( - wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: &light.target_view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: true, - }), - stencil_ops: None, - }, - ), - }); - pass.set_pipeline(&self.shadow_pass.pipeline); - pass.set_bind_group(0, &self.shadow_pass.bind_group, &[]); - - for entity in &self.entities { - pass.set_bind_group(1, &entity.bind_group, &[]); - pass.set_index_buffer(entity.index_buf.slice(..)); - pass.set_vertex_buffer(0, entity.vertex_buf.slice(..)); - pass.draw_indexed(0..entity.index_count as u32, 0, 0..1); - } - } - - encoder.pop_debug_group(); - }*/ - encoder.pop_debug_group(); - - // forward pass - encoder.push_debug_group("forward rendering pass"); - { - let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.1, - g: 0.2, - b: 0.3, - a: 1.0, - }), - store: true, - }, - }], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: &self.forward_depth, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: false, - }), - stencil_ops: None, - }), - }); - pass.set_pipeline(&self.forward_pass.pipeline); - pass.set_bind_group(0, &self.forward_pass.bind_group, &[]); - - // for entity in &self.entities { - // pass.set_bind_group(1, &entity.bind_group, &[]); - // pass.set_index_buffer(entity.index_buf.slice(..)); - // pass.set_vertex_buffer(0, entity.vertex_buf.slice(..)); - // pass.draw_indexed(0..entity.index_count as u32, 0, 0..1); - // } } - encoder.pop_debug_group(); - - queue.submit(iter::once(encoder.finish())); } pub(crate) fn required_features() -> wgpu::Features { diff --git a/src/runtime.rs b/src/runtime.rs index 0658ba7..f5b6c3b 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -4,8 +4,8 @@ use bytemuck::__core::mem; use bytemuck::__core::num::NonZeroU32; use cgmath::{Decomposed, Deg, InnerSpace, Quaternion, Rotation3, SquareMatrix}; -use crate::light::Light; use crate::render::EntityUniforms; +use crate::DirectionalLight; /* @@ -34,7 +34,7 @@ struct Entity { pub struct Runtime { entities: Vec, // This is going to be ECS'd - lights: Vec, // ECS + lights: Vec, // ECS } impl Runtime { @@ -163,28 +163,28 @@ impl Runtime { // This is just metadata we hold for the lights. We can hold onto this let lights = vec![ - Light { - pos: cgmath::Point3::new(7.0, -5.0, 10.0), - color: wgpu::Color { - r: 0.5, - g: 1.0, - b: 0.5, - a: 1.0, - }, - fov: 60.0, - depth: 1.0..20.0, - }, - Light { - pos: cgmath::Point3::new(-5.0, 7.0, 10.0), - color: wgpu::Color { - r: 1.0, - g: 0.5, - b: 0.5, - a: 1.0, - }, - fov: 45.0, - depth: 1.0..20.0, - }, + // Light { + // pos: cgmath::Point3::new(7.0, -5.0, 10.0), + // color: wgpu::Color { + // r: 0.5, + // g: 1.0, + // b: 0.5, + // a: 1.0, + // }, + // fov: 60.0, + // depth: 1.0..20.0, + // }, + // Light { + // pos: cgmath::Point3::new(-5.0, 7.0, 10.0), + // color: wgpu::Color { + // r: 1.0, + // g: 0.5, + // b: 0.5, + // a: 1.0, + // }, + // fov: 45.0, + // depth: 1.0..20.0, + // }, ]; Runtime {