diff --git a/src/app/app_builder.rs b/src/app/app_builder.rs index 1e3eda99c3..74e202a479 100644 --- a/src/app/app_builder.rs +++ b/src/app/app_builder.rs @@ -4,7 +4,7 @@ use crate::{ core::Time, legion::prelude::{Runnable, Schedulable, Schedule, Universe, World}, render::render_graph_2, - render::render_graph_2::{pipelines::*, wgpu_renderer::WgpuRenderer, resource_provider::CameraResourceProvider, UniformResourceProvider, StandardMaterial}, + render::render_graph_2::{pipelines::*, passes::*, wgpu_renderer::WgpuRenderer, resource_provider::{CameraResourceProvider, LightResourceProvider}, UniformResourceProvider, StandardMaterial}, render::{passes::*, *}, plugin::load_plugin, ui, @@ -175,6 +175,7 @@ impl AppBuilder { self.render_graph_builder = self .render_graph_builder .add_resource_provider(Box::new(CameraResourceProvider)) + .add_resource_provider(Box::new(LightResourceProvider::new(10))) .add_resource_provider(Box::new(UniformResourceProvider::::new())) .add_resource_provider(Box::new(UniformResourceProvider::::new())) .add_forward_pass() diff --git a/src/render/render_graph_2/mod.rs b/src/render/render_graph_2/mod.rs index edb24e0512..d7c689bc87 100644 --- a/src/render/render_graph_2/mod.rs +++ b/src/render/render_graph_2/mod.rs @@ -2,6 +2,7 @@ pub mod pipelines; pub mod resource_name; pub mod wgpu_renderer; pub mod resource_provider; +pub mod passes; mod resource; mod pipeline; mod pipeline_layout; diff --git a/src/render/render_graph_2/passes/forward.rs b/src/render/render_graph_2/passes/forward.rs new file mode 100644 index 0000000000..f9b8c1fe34 --- /dev/null +++ b/src/render/render_graph_2/passes/forward.rs @@ -0,0 +1,43 @@ +use crate::render::{ + render_graph_2::{ + resource_name, PassDescriptor, + RenderGraphBuilder, RenderPassColorAttachmentDescriptor, + }, + }; + +pub trait ForwardPassBuilder { + fn add_forward_pass(self) -> Self; +} + +impl ForwardPassBuilder for RenderGraphBuilder { + fn add_forward_pass(self) -> Self { + self.add_pass( + "main", + PassDescriptor { + color_attachments: vec![RenderPassColorAttachmentDescriptor { + attachment: resource_name::texture::SWAP_CHAIN.to_string(), + 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: None, + // depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor { + // attachment: "forward_depth".to_string(), + // 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, + // }), + sample_count: 1, + }, + ) + } +} \ No newline at end of file diff --git a/src/render/render_graph_2/passes/mod.rs b/src/render/render_graph_2/passes/mod.rs new file mode 100644 index 0000000000..f36f84ce95 --- /dev/null +++ b/src/render/render_graph_2/passes/mod.rs @@ -0,0 +1,3 @@ +mod forward; + +pub use forward::*; \ No newline at end of file diff --git a/src/render/render_graph_2/pipelines/forward/mod.rs b/src/render/render_graph_2/pipelines/forward/mod.rs index b982d187a5..4ad99675c3 100644 --- a/src/render/render_graph_2/pipelines/forward/mod.rs +++ b/src/render/render_graph_2/pipelines/forward/mod.rs @@ -2,8 +2,8 @@ use crate::render::{ Vertex, { render_graph_2::{ - mesh_draw_target, resource_name, pipeline_layout::*, PassDescriptor, PipelineDescriptor, - RenderGraphBuilder, RenderPassColorAttachmentDescriptor, + mesh_draw_target, pipeline_layout::*, PipelineDescriptor, + RenderGraphBuilder, }, shader::{Shader, ShaderStage}, }, @@ -95,41 +95,4 @@ impl ForwardPipelineBuilder for RenderGraphBuilder { .build(), ) } -} - -pub trait ForwardPassBuilder { - fn add_forward_pass(self) -> Self; -} - -impl ForwardPassBuilder for RenderGraphBuilder { - fn add_forward_pass(self) -> Self { - self.add_pass( - "main", - PassDescriptor { - color_attachments: vec![RenderPassColorAttachmentDescriptor { - attachment: resource_name::texture::SWAP_CHAIN.to_string(), - 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: None, - // depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor { - // attachment: "forward_depth".to_string(), - // 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, - // }), - sample_count: 1, - }, - ) - } -} +} \ No newline at end of file diff --git a/src/render/render_graph_2/pipelines/forward_flat/forward_flat.frag b/src/render/render_graph_2/pipelines/forward_flat/forward_flat.frag new file mode 100644 index 0000000000..55f30d1328 --- /dev/null +++ b/src/render/render_graph_2/pipelines/forward_flat/forward_flat.frag @@ -0,0 +1,21 @@ +#version 450 + +layout(location = 0) in vec4 v_Position; +layout(location = 1) in vec3 v_Normal; +layout(location = 2) in vec2 v_Uv; + +layout(location = 0) out vec4 o_Target; + +layout(set = 0, binding = 0) uniform Camera { + mat4 ViewProj; +}; + +layout(set = 1, binding = 1) uniform StandardMaterial { + vec4 Albedo; +}; + +void main() { + // multiply the light by material color + o_Target = vec4(1.0, 0.0, 0.0, 1.0); + o_Target = Albedo; +} diff --git a/src/render/render_graph_2/pipelines/forward_flat/forward_flat.vert b/src/render/render_graph_2/pipelines/forward_flat/forward_flat.vert new file mode 100644 index 0000000000..4bb8e07c84 --- /dev/null +++ b/src/render/render_graph_2/pipelines/forward_flat/forward_flat.vert @@ -0,0 +1,29 @@ +#version 450 + +layout(location = 0) in vec4 a_Pos; +layout(location = 1) in vec4 a_Normal; +layout(location = 2) in vec2 a_Uv; + +layout(location = 0) out vec4 v_Position; +layout(location = 1) out vec3 v_Normal; +layout(location = 2) out vec2 v_Uv; + +layout(set = 0, binding = 0) uniform Camera { + mat4 ViewProj; +}; + +layout(set = 1, binding = 0) uniform Object { + mat4 Model; +}; + +layout(set = 1, binding = 1) uniform StandardMaterial { + vec4 Albedo; +}; + +void main() { + v_Normal = mat3(Model) * vec3(a_Normal.xyz); + v_Position = Model * vec4(a_Pos); + // v_Normal = vec3(a_Normal.xyz); + // v_Position = vec4(a_Pos); + gl_Position = ViewProj * v_Position; +} diff --git a/src/render/render_graph_2/pipelines/forward_flat/mod.rs b/src/render/render_graph_2/pipelines/forward_flat/mod.rs new file mode 100644 index 0000000000..5716ba4f9c --- /dev/null +++ b/src/render/render_graph_2/pipelines/forward_flat/mod.rs @@ -0,0 +1,98 @@ +use crate::render::{ + Vertex, + { + render_graph_2::{ + mesh_draw_target, pipeline_layout::*, PipelineDescriptor, + RenderGraphBuilder, + }, + shader::{Shader, ShaderStage}, + }, +}; +pub trait ForwardFlatPipelineBuilder { + fn add_forward_flat_pipeline(self) -> Self; +} + +impl ForwardFlatPipelineBuilder for RenderGraphBuilder { + fn add_forward_flat_pipeline(self) -> Self { + self.add_pipeline( + "forward_flat", + PipelineDescriptor::build(Shader::from_glsl( + include_str!("forward_flat.vert"), + ShaderStage::Vertex, + )) + .with_fragment_shader(Shader::from_glsl( + include_str!("forward_flat.frag"), + ShaderStage::Fragment, + )) + .add_bind_group(BindGroup::new( + vec![ + Binding { + name: "Camera".to_string(), + bind_type: BindType::Uniform { + dynamic: false, + properties: vec![ + UniformProperty { + name: "ViewProj".to_string(), + property_type: UniformPropertyType::Mat4, + }, + ] + } + }, + ] + )) + .add_bind_group(BindGroup::new( + vec![ + Binding { + name: "Object".to_string(), + bind_type: BindType::Uniform { + dynamic: true, + properties: vec![ + UniformProperty { + name: "Model".to_string(), + property_type: UniformPropertyType::Mat4, + }, + ] + } + }, + Binding { + name: "StandardMaterial".to_string(), + bind_type: BindType::Uniform { + dynamic: true, + properties: vec![ + UniformProperty { + name: "Albedo".to_string(), + property_type: UniformPropertyType::Vec4, + }, + ] + } + }, + ] + )) + .with_rasterization_state(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, + }) + // .with_depth_stencil_state(wgpu::DepthStencilStateDescriptor { + // format: wgpu::TextureFormat::Depth32Float, + // 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, + // }) + .add_color_state(wgpu::ColorStateDescriptor { + format: wgpu::TextureFormat::Bgra8UnormSrgb, + color_blend: wgpu::BlendDescriptor::REPLACE, + alpha_blend: wgpu::BlendDescriptor::REPLACE, + write_mask: wgpu::ColorWrite::ALL, + }) + .add_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor()) + .add_draw_target(mesh_draw_target) + .build(), + ) + } +} \ No newline at end of file diff --git a/src/render/render_graph_2/pipelines/mod.rs b/src/render/render_graph_2/pipelines/mod.rs index f36f84ce95..906ec8e291 100644 --- a/src/render/render_graph_2/pipelines/mod.rs +++ b/src/render/render_graph_2/pipelines/mod.rs @@ -1,3 +1,5 @@ mod forward; +mod forward_flat; -pub use forward::*; \ No newline at end of file +pub use forward::*; +pub use forward_flat::*; \ No newline at end of file diff --git a/src/render/render_graph_2/resource_name.rs b/src/render/render_graph_2/resource_name.rs index a1884a4f13..a419eadd2a 100644 --- a/src/render/render_graph_2/resource_name.rs +++ b/src/render/render_graph_2/resource_name.rs @@ -4,4 +4,5 @@ pub mod texture { pub mod uniform { pub const CAMERA: &str = "Camera"; + pub const LIGHTS: &str = "Lights"; } \ No newline at end of file diff --git a/src/render/render_graph_2/resource_provider.rs b/src/render/render_graph_2/resource_provider.rs index f891c675f2..e914da9282 100644 --- a/src/render/render_graph_2/resource_provider.rs +++ b/src/render/render_graph_2/resource_provider.rs @@ -1,7 +1,7 @@ -use crate::render::{ +use crate::{render::{ render_graph_2::{resource_name, Renderer}, - ActiveCamera, Camera, -}; + ActiveCamera, Camera, Light, LightRaw, +}, transform::prelude::Translation}; use bevy_transform::prelude::LocalToWorld; use legion::prelude::*; use zerocopy::AsBytes; @@ -33,11 +33,84 @@ impl ResourceProvider for CameraResourceProvider { let camera_matrix: [[f32; 4]; 4] = (camera.view_matrix * local_to_world.0).to_cols_array_2d(); - renderer.create_buffer_mapped("camera_tmp", matrix_size, wgpu::BufferUsage::COPY_SRC, &mut |data| { - data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); - }); + renderer.create_buffer_mapped( + "camera_tmp", + matrix_size, + wgpu::BufferUsage::COPY_SRC, + &mut |data| { + data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); + }, + ); - renderer.copy_buffer_to_buffer("camera_tmp", 0, resource_name::uniform::CAMERA, 0, matrix_size as u64); + renderer.copy_buffer_to_buffer( + "camera_tmp", + 0, + resource_name::uniform::CAMERA, + 0, + matrix_size as u64, + ); } } -} \ No newline at end of file +} + +pub struct LightResourceProvider { + pub lights_are_dirty: bool, + pub max_lights: usize, +} + +impl LightResourceProvider { + pub fn new(max_lights: usize) -> Self { + LightResourceProvider { + lights_are_dirty: true, + max_lights: max_lights, + } + } +} + +impl ResourceProvider for LightResourceProvider { + fn initialize(&mut self, renderer: &mut dyn Renderer, _world: &mut World) { + let light_uniform_size = + (self.max_lights * std::mem::size_of::()) as wgpu::BufferAddress; + + renderer.create_buffer( + resource_name::uniform::LIGHTS, + light_uniform_size, + wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::COPY_DST, + ); + } + + fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World) { + if self.lights_are_dirty { + let light_query = <(Read, Read, Read)>::query(); + let light_count = light_query.iter(world).count(); + + if light_count == 0 { + return; + } + + self.lights_are_dirty = false; + let size = std::mem::size_of::(); + let total_size = size * light_count; + renderer + .create_buffer_mapped("LIGHT_TMP", total_size, wgpu::BufferUsage::COPY_SRC, &mut |data| { + for ((light, local_to_world, translation), slot) in light_query + .iter(world) + .zip(data.chunks_exact_mut(size)) + { + slot.copy_from_slice( + LightRaw::from(&light, &local_to_world.0, &translation).as_bytes(), + ); + } + }); + + renderer.copy_buffer_to_buffer( + "LIGHT_TMP", + 0, + resource_name::uniform::LIGHTS, + 0, + total_size as wgpu::BufferAddress, + ); + } + } + fn resize(&mut self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) {} +}