diff --git a/blade-render/code/fill-gbuf.wgsl b/blade-render/code/fill-gbuf.wgsl index f379c8a0..9d43c382 100644 --- a/blade-render/code/fill-gbuf.wgsl +++ b/blade-render/code/fill-gbuf.wgsl @@ -3,8 +3,6 @@ #include "debug.inc.wgsl" #include "debug-param.inc.wgsl" -const DEBUG_CONSISTENCY: bool = false; - // Has to match the host! struct Vertex { pos: vec3, @@ -46,6 +44,7 @@ var out_depth: texture_storage_2d; var out_flat_normal: texture_storage_2d; var out_basis: texture_storage_2d; var out_albedo: texture_storage_2d; +var out_debug: texture_storage_2d; fn decode_normal(raw: u32) -> vec3 { return unpack4x8snorm(raw).xyz; @@ -149,16 +148,20 @@ fn main(@builtin(global_invocation_id) global_id: vec3) { let base_color_sample = textureSampleLevel(textures[entry.base_color_texture], sampler_linear, tex_coords, lod); albedo = (base_color_factor * base_color_sample).xyz; } - if (DEBUG_CONSISTENCY) { + if (debug.view_mode == DebugMode_HitConsistency) { let reprojected = get_projected_pixel(camera, hit_position); let barycentrics_pos_diff = positions * barycentrics - hit_position; let camera_projection_diff = vec2(global_id.xy) - vec2(reprojected); - albedo = vec3(length(barycentrics_pos_diff), length(camera_projection_diff), 0.0); + let consistency = vec4(length(barycentrics_pos_diff), length(camera_projection_diff), 0.0, 0.0); + textureStore(out_debug, global_id.xy, consistency); } } else { if (enable_debug) { debug_buf.entry = DebugEntry(); } + if (debug.view_mode != DebugMode_Final) { + textureStore(out_debug, global_id.xy, vec4(0.0)); + } } textureStore(out_depth, global_id.xy, vec4(depth, 0.0, 0.0, 0.0)); diff --git a/blade-render/code/post-proc.wgsl b/blade-render/code/post-proc.wgsl index 3c5cd41f..c0eea300 100644 --- a/blade-render/code/post-proc.wgsl +++ b/blade-render/code/post-proc.wgsl @@ -1,5 +1,7 @@ +#use PostProcMode + struct ToneMapParams { - enabled: u32, + mode: u32, average_lum: f32, key_value: f32, // minimum value of the pixels mapped to white brightness @@ -8,6 +10,7 @@ struct ToneMapParams { var t_albedo: texture_2d; var light_diffuse: texture_2d; +var t_debug: texture_2d; var tone_map_params: ToneMapParams; struct VertexOutput { @@ -25,17 +28,21 @@ fn blit_vs(@builtin(vertex_index) vi: u32) -> VertexOutput { @fragment fn blit_fs(vo: VertexOutput) -> @location(0) vec4 { - let tc = vec2(i32(vo.clip_pos.x), i32(vo.input_size.y) - i32(vo.clip_pos.y)); - let albedo = textureLoad(t_albedo, tc, 0); - let radiance = textureLoad(light_diffuse, tc, 0); - let color = albedo * radiance; - if (tone_map_params.enabled != 0u) { - // Following https://blog.en.uwa4d.com/2022/07/19/physically-based-renderingg-hdr-tone-mapping/ - let l_adjusted = tone_map_params.key_value / tone_map_params.average_lum * color.xyz; - let l_white = tone_map_params.white_level; - let l_ldr = l_adjusted * (1.0 + l_adjusted / (l_white*l_white)) / (1.0 + l_adjusted); - return vec4(l_ldr, 1.0); + let tc = vec2(i32(vo.clip_pos.x), i32(vo.input_size.y) - i32(vo.clip_pos.y) - 1); + if (tone_map_params.mode == PostProcMode_Debug) { + return textureLoad(t_debug, tc, 0); } else { - return color; + let albedo = textureLoad(t_albedo, tc, 0); + let radiance = textureLoad(light_diffuse, tc, 0); + let color = albedo * radiance; + if (tone_map_params.mode == PostProcMode_Tonemap) { + // Following https://blog.en.uwa4d.com/2022/07/19/physically-based-renderingg-hdr-tone-mapping/ + let l_adjusted = tone_map_params.key_value / tone_map_params.average_lum * color.xyz; + let l_white = tone_map_params.white_level; + let l_ldr = l_adjusted * (1.0 + l_adjusted / (l_white*l_white)) / (1.0 + l_adjusted); + return vec4(l_ldr, 1.0); + } else { + return color; + } } } diff --git a/blade-render/code/ray-trace.wgsl b/blade-render/code/ray-trace.wgsl index 253862fa..8b30b7b2 100644 --- a/blade-render/code/ray-trace.wgsl +++ b/blade-render/code/ray-trace.wgsl @@ -131,6 +131,7 @@ var t_prev_basis: texture_2d; var t_flat_normal: texture_2d; var t_prev_flat_normal: texture_2d; var out_diffuse: texture_storage_2d; +var out_debug: texture_storage_2d; fn sample_circle(random: f32) -> vec2 { let angle = 2.0 * PI * random; @@ -312,8 +313,7 @@ struct RestirOutput { fn compute_restir(surface: Surface, pixel: vec2, rng: ptr, enable_debug: bool) -> RestirOutput { if (debug.view_mode == DebugMode_Depth) { - let depth = vec3(surface.depth / camera.depth); - return RestirOutput(depth); + textureStore(out_debug, pixel, vec4(surface.depth / camera.depth)); } let ray_dir = get_ray_direction(camera, pixel); let pixel_index = get_reservoir_index(pixel, camera); @@ -327,7 +327,7 @@ fn compute_restir(surface: Surface, pixel: vec2, rng: ptr(0.0, 0.0, 1.0)); if (debug.view_mode == DebugMode_Normal) { - return RestirOutput(normal); + textureStore(out_debug, pixel, vec4(normal, 0.0)); } var canonical = LiveReservoir(); diff --git a/blade-render/src/asset_hub.rs b/blade-render/src/asset_hub.rs index aa297e52..60904e19 100644 --- a/blade-render/src/asset_hub.rs +++ b/blade-render/src/asset_hub.rs @@ -37,6 +37,7 @@ impl AssetHub { sh_baker.register_enum::(); sh_baker.register_bitflags::(); sh_baker.register_bitflags::(); + sh_baker.register_enum::(); let shaders = AssetManager::new(target, choir, sh_baker); Self { diff --git a/blade-render/src/render/mod.rs b/blade-render/src/render/mod.rs index 5bbb7fb6..84a42e49 100644 --- a/blade-render/src/render/mod.rs +++ b/blade-render/src/render/mod.rs @@ -25,17 +25,26 @@ struct Samplers { #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, blade_macros::AsPrimitive, strum::EnumIter)] #[repr(u32)] pub enum DebugMode { - None = 0, + Final = 0, Depth = 1, Normal = 2, + HitConsistency = 3, } impl Default for DebugMode { fn default() -> Self { - Self::None + Self::Final } } +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, blade_macros::AsPrimitive, strum::EnumIter)] +#[repr(u32)] +pub enum PostProcMode { + Tonemap = 0, + Reconstruct = 1, + Debug = 2, +} + bitflags::bitflags! { #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, PartialOrd)] pub struct DebugDrawFlags: u32 { @@ -250,6 +259,7 @@ impl FrameData { let (depth, depth_view) = Self::create_target("depth", blade_graphics::TextureFormat::R32Float, size, gpu); encoder.init_texture(depth); + let (basis, basis_view) = Self::create_target( "basis", blade_graphics::TextureFormat::Rgba8Snorm, @@ -257,6 +267,7 @@ impl FrameData { gpu, ); encoder.init_texture(basis); + let (flat_normal, flat_normal_view) = Self::create_target( "flat_normal", blade_graphics::TextureFormat::Rgba8Snorm, @@ -264,6 +275,7 @@ impl FrameData { gpu, ); encoder.init_texture(flat_normal); + let (albedo, albedo_view) = Self::create_target( "basis", blade_graphics::TextureFormat::Rgba8Unorm, @@ -271,6 +283,7 @@ impl FrameData { gpu, ); encoder.init_texture(albedo); + Self { reservoir_buf, depth, @@ -312,6 +325,8 @@ pub struct Renderer { shaders: Shaders, frame_data: [FrameData; 2], lighting_diffuse: DoubleRenderTarget, + debug_texture: blade_graphics::Texture, + debug_view: blade_graphics::TextureView, fill_pipeline: blade_graphics::ComputePipeline, main_pipeline: blade_graphics::ComputePipeline, atrous_pipeline: blade_graphics::ComputePipeline, @@ -383,6 +398,7 @@ struct FillData<'a> { out_basis: blade_graphics::TextureView, out_flat_normal: blade_graphics::TextureView, out_albedo: blade_graphics::TextureView, + out_debug: blade_graphics::TextureView, } #[derive(blade_macros::ShaderData)] @@ -406,6 +422,7 @@ struct MainData { reservoirs: blade_graphics::BufferPiece, prev_reservoirs: blade_graphics::BufferPiece, out_diffuse: blade_graphics::TextureView, + out_debug: blade_graphics::TextureView, } #[repr(C)] @@ -426,16 +443,17 @@ struct AtrousData { #[repr(C)] #[derive(Clone, Copy, Default, bytemuck::Zeroable, bytemuck::Pod)] struct ToneMapParams { - enabled: u32, + mode: u32, average_lum: f32, key_value: f32, white_level: f32, } #[derive(blade_macros::ShaderData)] -struct BlitData { +struct PostProcData { t_albedo: blade_graphics::TextureView, light_diffuse: blade_graphics::TextureView, + t_debug: blade_graphics::TextureView, tone_map_params: ToneMapParams, } @@ -563,7 +581,7 @@ impl ShaderPipelines { format: blade_graphics::TextureFormat, gpu: &blade_graphics::Context, ) -> blade_graphics::RenderPipeline { - let layout = ::layout(); + let layout = ::layout(); gpu.create_render_pipeline(blade_graphics::RenderPipelineDesc { name: "main", data_layouts: &[&layout], @@ -712,6 +730,13 @@ impl Renderer { FrameData::new(config.screen_size, sp.reservoir_size, encoder, gpu), ]; let dummy = DummyResources::new(encoder, gpu); + let (debug_texture, debug_view) = FrameData::create_target( + "debug", + blade_graphics::TextureFormat::Rgba8Unorm, + config.screen_size, + gpu, + ); + encoder.init_texture(debug_texture); let samplers = Samplers { nearest: gpu.create_sampler(blade_graphics::SamplerDesc { @@ -743,6 +768,8 @@ impl Renderer { encoder, gpu, ), + debug_texture, + debug_view, scene: super::Scene::default(), fill_pipeline: sp.fill, main_pipeline: sp.main, @@ -772,6 +799,8 @@ impl Renderer { frame_data.destroy(gpu); } self.lighting_diffuse.destroy(gpu); + gpu.destroy_texture(self.debug_texture); + gpu.destroy_texture_view(self.debug_view); if self.hit_buffer != blade_graphics::Buffer::default() { gpu.destroy_buffer(self.hit_buffer); } @@ -889,9 +918,22 @@ impl Renderer { frame_data.destroy(gpu); *frame_data = FrameData::new(size, self.reservoir_size, encoder, gpu); } + self.lighting_diffuse.destroy(gpu); self.lighting_diffuse = DoubleRenderTarget::new("light/diffuse", RADIANCE_FORMAT, size, encoder, gpu); + + gpu.destroy_texture(self.debug_texture); + gpu.destroy_texture_view(self.debug_view); + let (debug_texture, debug_view) = FrameData::create_target( + "debug", + blade_graphics::TextureFormat::Rgba8Unorm, + size, + gpu, + ); + encoder.init_texture(debug_texture); + self.debug_texture = debug_texture; + self.debug_view = debug_view; } /// Prepare to render a frame. @@ -1180,6 +1222,7 @@ impl Renderer { out_basis: cur.basis_view, out_flat_normal: cur.flat_normal_view, out_albedo: cur.albedo_view, + out_debug: self.debug_view, }, ); pc.dispatch(groups); @@ -1219,6 +1262,7 @@ impl Renderer { reservoirs: cur.reservoir_buf.into(), prev_reservoirs: prev.reservoir_buf.into(), out_diffuse: self.lighting_diffuse.cur(), + out_debug: self.debug_view, }, ); pc.dispatch(groups); @@ -1254,17 +1298,23 @@ impl Renderer { } /// Blit the rendering result into a specified render pass. - pub fn blit(&self, pass: &mut blade_graphics::RenderCommandEncoder, debug_blits: &[DebugBlit]) { + pub fn post_proc( + &self, + pass: &mut blade_graphics::RenderCommandEncoder, + mode: PostProcMode, + debug_blits: &[DebugBlit], + ) { let pp = &self.scene.post_processing; let cur = self.frame_data.first().unwrap(); if let mut pc = pass.with(&self.blit_pipeline) { pc.bind( 0, - &BlitData { + &PostProcData { t_albedo: cur.albedo_view, light_diffuse: self.lighting_diffuse.cur(), + t_debug: self.debug_view, tone_map_params: ToneMapParams { - enabled: 1, + mode: mode as u32, average_lum: pp.average_luminocity, key_value: pp.exposure_key_value, white_level: pp.white_level, diff --git a/examples/scene/data/scene.ron b/examples/scene/data/scene.ron index b5afd906..284cbaa8 100644 --- a/examples/scene/data/scene.ron +++ b/examples/scene/data/scene.ron @@ -1,7 +1,7 @@ ( camera: ( position: (2.7, 1.6, 2.1), - orientation: (-0.04, 0.92, -0.05, -0.37), + orientation: (-0.07, 0.36, 0.01, 0.93), fov_y: 1.0, max_depth: 100.0, speed: 1000.0, diff --git a/examples/scene/main.rs b/examples/scene/main.rs index 36e48a3c..55856535 100644 --- a/examples/scene/main.rs +++ b/examples/scene/main.rs @@ -342,6 +342,11 @@ impl Example { scale_factor, }; if self.pending_scene.is_none() { + let pp_mode = if self.debug.view_mode == blade_render::DebugMode::default() { + blade_render::PostProcMode::Tonemap + } else { + blade_render::PostProcMode::Debug + }; let mut debug_blit_array = [blade_render::DebugBlit::default()]; let debug_blits = match self.debug_blit { Some(ref blit) => { @@ -350,7 +355,7 @@ impl Example { } None => &[], }; - self.renderer.blit(&mut pass, debug_blits); + self.renderer.post_proc(&mut pass, pp_mode, debug_blits); } self.gui_painter .paint(&mut pass, gui_primitives, &screen_desc, &self.context);