From 7fb89e7d6e3a312c1b3273925bd7c831a8c72b59 Mon Sep 17 00:00:00 2001 From: mitchellhansen Date: Wed, 24 Feb 2021 18:30:45 -0800 Subject: [PATCH] thinking about shaders --- shaders/forward.frag | 9 +-- shaders/g_buffer_input.frag | 4 ++ shaders/g_buffer_input.vert | 20 ++++++ src/render/mod.rs | 11 +++- src/render/state.rs | 117 +++++++++++++++++++++++++++++++++--- src/render/system.rs | 41 ++++++++++++- 6 files changed, 185 insertions(+), 17 deletions(-) create mode 100644 shaders/g_buffer_input.frag create mode 100644 shaders/g_buffer_input.vert diff --git a/shaders/forward.frag b/shaders/forward.frag index 6de53db..b4d3cd1 100644 --- a/shaders/forward.frag +++ b/shaders/forward.frag @@ -36,16 +36,17 @@ float fetch_shadow(int light_id, vec4 homogeneous_coords) { if (homogeneous_coords.w <= 0.0) { return 1.0; } - // compensate for the Y-flip difference between the NDC and texture coordinates + // compensate for the Y-flip difference between the normalized device + // coordinates (NDC) and texture coordinates const vec2 flip_correction = vec2(0.5, -0.5); // compute texture coordinates for shadow lookup vec4 light_local = vec4( // I don't know what kind of jank shit is going on on this line homogeneous_coords.xy * flip_correction/homogeneous_coords.w + 0.5, - light_id, - homogeneous_coords.z / homogeneous_coords.w + light_id, // array layer + homogeneous_coords.z / homogeneous_coords.w // D-Ref ); - // do the lookup, using HW PCF and comparison + // do the lookup, using HW percentage closer filtering(PCF) and comparison return texture(sampler2DArrayShadow(t_Shadow, s_Shadow), light_local); } diff --git a/shaders/g_buffer_input.frag b/shaders/g_buffer_input.frag new file mode 100644 index 0000000..f0bcb49 --- /dev/null +++ b/shaders/g_buffer_input.frag @@ -0,0 +1,4 @@ +#version 450 + +void main() { +} diff --git a/shaders/g_buffer_input.vert b/shaders/g_buffer_input.vert new file mode 100644 index 0000000..a94d57d --- /dev/null +++ b/shaders/g_buffer_input.vert @@ -0,0 +1,20 @@ +#version 450 + +layout(location = 0) in vec4 a_Pos; + +layout(set = 0, binding = 0) uniform Globals { + mat4 u_ViewProj; +}; + +layout(set = 0, binding = 1) uniform Globals { + mat4 u_ViewProj; +}; + +layout(set = 1, binding = 0) uniform Entity { + mat4 u_World; + vec4 u_Color; +}; + +void main() { + gl_Position = u_ViewProj * u_World * vec4(a_Pos); +} diff --git a/src/render/mod.rs b/src/render/mod.rs index 9a54a83..a656926 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -65,4 +65,13 @@ pub struct ShadowUniforms { } unsafe impl Pod for ShadowUniforms {} -unsafe impl Zeroable for ShadowUniforms {} \ No newline at end of file +unsafe impl Zeroable for ShadowUniforms {} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct CameraProjectionView { + proj: [[f32; 4]; 4], +} + +unsafe impl Pod for CameraProjectionView {} +unsafe impl Zeroable for CameraProjectionView {} \ No newline at end of file diff --git a/src/render/state.rs b/src/render/state.rs index 290e8c6..ed81e3d 100644 --- a/src/render/state.rs +++ b/src/render/state.rs @@ -33,11 +33,13 @@ use crate::current_ui; use crate::geometry::{load_obj, RawMesh, Vertex}; use crate::imgui_supp::imgui_support::{ImguiContext, ImguiPlatform}; use crate::light::{DirectionalLight, LightRaw}; -use crate::render::{EntityUniforms, ForwardUniforms, ShadowUniforms}; +use crate::render::{EntityUniforms, ForwardUniforms, ShadowUniforms, CameraProjectionView}; /// A render pass consists of a pipeline, bindgroup, and uniform buf /// The uniform buf is just the ShadowUniforms or ForwardUniforms +/// They are uniform across all cu's. /// And the bindgroup is just the localbindgroup (the EntityUniforms) and the rest +/// pub struct Pass { pub pipeline: wgpu::RenderPipeline, pub bind_group: wgpu::BindGroup, @@ -45,6 +47,7 @@ pub struct Pass { } pub struct RenderState { + swapchain: SwapChain, swapchain_description: SwapChainDescriptor, instance: Arc, @@ -62,6 +65,8 @@ pub struct RenderState { pub(in crate::render) forward_pass: Pass, pub(in crate::render) forward_depth: wgpu::TextureView, + pub(in crate::render) gbuffer_pass: Pass, + entity_bind_group_layout: BindGroupLayout, pub(in crate::render) light_uniform_buf: wgpu::Buffer, @@ -302,6 +307,107 @@ impl RenderState { hands-off global lighting / point lights */ + // This pass is just going to forward the vertex info to the fragments + // And they are going to render to the gbuffer + let g_buffer_pass = { + let uniform_size = mem::size_of::() as wgpu::BufferAddress; + + // Pretty sure this is the camera projction + let bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("g-buffer input pass bindgroup layout (cam)"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, // global + visibility: wgpu::ShaderStage::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + min_binding_size: wgpu::BufferSize::new(uniform_size), + has_dynamic_offset: false, + }, + count: None, + }], + }); + + // Pipeline is similar between passes, but with a different label + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("g-buffer input pipeline layout"), + bind_group_layouts: &[&bind_group_layout, &entity_bind_group_layout], + push_constant_ranges: &[], + }); + + // Holds the shadow uniforms, which is just a 4 vec of quaternians + let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("shadow pass shadow uniform buffer"), + size: uniform_size, + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + mapped_at_creation: false, + }); + + // Create bind group + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("Shadow uniform bind group"), + layout: &bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &uniform_buf, + offset: 0, + size: wgpu::BufferSize::new(uniform_size), + }, + }, + ], + + }); + + // Create the render pipeline + let vs_module = + device.create_shader_module(&wgpu::include_spirv!("../../shaders/bake.vert.spv")); + let fs_module = + device.create_shader_module(&wgpu::include_spirv!("../../shaders/bake.frag.spv")); + + let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("shadow"), + layout: Some(&pipeline_layout), + + vertex: VertexState { + module: &vs_module, + entry_point: "main", + buffers: &[vb_desc.clone()], + }, + fragment: Some(FragmentState { + module: &fs_module, + entry_point: "main", + targets: &[], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + front_face: wgpu::FrontFace::Ccw, + cull_mode: wgpu::CullMode::Back, + ..Default::default() + }, + depth_stencil: Some(wgpu::DepthStencilState { + format: Self::SHADOW_FORMAT, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::LessEqual, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState { + constant: 2, // corresponds to bilinear filtering + slope_scale: 2.0, + clamp: 0.0, + }, + clamp_depth: device.features().contains(wgpu::Features::DEPTH_CLAMPING), + }), + multisample: wgpu::MultisampleState::default(), + }); + + Pass { + pipeline, + bind_group, + uniform_buf, + } + }; + let shadow_pass = { let uniform_size = mem::size_of::() as wgpu::BufferAddress; @@ -356,14 +462,6 @@ impl RenderState { size: wgpu::BufferSize::new(uniform_size), }, }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Buffer { - buffer: &g_buffer, - offset: 0, - size: wgpu::BufferSize::new(uniform_size), - }, - }, ], label: Some("Shadow uniform bind group"), }); @@ -655,6 +753,7 @@ impl RenderState { shadow_pass, forward_pass, forward_depth: depth_texture.create_view(&wgpu::TextureViewDescriptor::default()), + gbuffer_pass: g_buffer_pass, entity_bind_group_layout: entity_bind_group_layout, shadow_target_views: shadow_target_views, light_uniform_buf, diff --git a/src/render/system.rs b/src/render/system.rs index ce3aeb0..4a1fd4a 100644 --- a/src/render/system.rs +++ b/src/render/system.rs @@ -36,9 +36,7 @@ use crate::geometry::{load_obj, Vertex}; use crate::imgui_supp::imgui_support::{ImguiContext, ImguiPlatform}; use crate::light::{DirectionalLight, LightRaw}; use crate::render::state::RenderState; -use crate::render::{ - insert_debug_marker_checked, pop_debug_group_checked, push_debug_group_checked, EntityUniforms, -}; +use crate::render::{insert_debug_marker_checked, pop_debug_group_checked, push_debug_group_checked, EntityUniforms, ForwardUniforms}; #[system] #[write_component(Camera)] @@ -235,6 +233,7 @@ pub fn render_test( mesh_stack.push(mesh.clone()); } + // Update the light uniforms only if flagged if renderer.lights_are_dirty { renderer.lights_are_dirty = false; let mut query = <(&mut DirectionalLight, &mut Position)>::query(); @@ -247,6 +246,39 @@ pub fn render_test( } } + // Render the g buffer + push_debug_group_checked("g-buffer stuff", &mut encoder); + { + + + insert_debug_marker_checked("render entities", &mut encoder); + + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("render pass"), + 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(&renderer.shadow_pass.pipeline); + pass.set_bind_group(0, &renderer.shadow_pass.bind_group, &[]); + + for mesh in &mesh_stack { + pass.set_bind_group(1, &mesh.bind_group, &[]); + // TODO, pipe through this index format through the mesh + pass.set_index_buffer(mesh.index_buffer.slice(..), mesh.index_format); + pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); + pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); + } + } + + pop_debug_group_checked(&mut encoder); + push_debug_group_checked("shadow passes", &mut encoder); let mut query = <(&mut DirectionalLight, &mut Position)>::query(); @@ -327,6 +359,7 @@ pub fn render_test( let mut query = <(&mut Position, &mut Mesh)>::query(); + // I could use that mesh stack here lol for (pos, mesh) in query.iter_mut(world) { pass.set_bind_group(1, &mesh.bind_group, &[]); // TODO: Pipe this in through the mesh @@ -335,9 +368,11 @@ pub fn render_test( pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); } } + pop_debug_group_checked(&mut encoder); pop_debug_group_checked(&mut encoder); + // Run the Imgui render { let mut imgui_context = &mut imgui_context.lock().unwrap().context; let mut imgui_platform = &mut imgui_platform.lock().unwrap().platform;