From 5a8dec8d0286040cb08aacf7e3127542ea340ed9 Mon Sep 17 00:00:00 2001 From: nullprop Date: Wed, 8 Nov 2023 23:16:31 +0200 Subject: [PATCH] WIP: don't draw fog past scene depth --- res/shaders/fog.wgsl | 53 +++++++++++++++- src/core/state.rs | 140 ++++++++++++++++++++++++++----------------- src/core/texture.rs | 20 ++++--- 3 files changed, 146 insertions(+), 67 deletions(-) diff --git a/res/shaders/fog.wgsl b/res/shaders/fog.wgsl index 83379de..ccd20dd 100644 --- a/res/shaders/fog.wgsl +++ b/res/shaders/fog.wgsl @@ -8,6 +8,8 @@ struct FogVertexOutput { @location(1) light_world_position: vec3, } +// Vertex shader + @vertex fn vs_main( model: VertexInput, @@ -30,6 +32,33 @@ fn vs_main( return out; } +// Fragment shader + +@group(2)@binding(0) +var t_light_depth: texture_depth_2d_array; +@group(2) @binding(1) +var s_light_depth: sampler_comparison; + +@group(2)@binding(2) +var t_geometry_depth: texture_depth_2d; +@group(2) @binding(3) +var s_geometry_depth: sampler; + +@group(3) @binding(0) +var t_diffuse: texture_2d; +@group(3)@binding(1) +var s_diffuse: sampler; + +@group(3)@binding(2) +var t_normal: texture_2d; +@group(3) @binding(3) +var s_normal: sampler; + +@group(3)@binding(4) +var t_roughness_metalness: texture_2d; +@group(3) @binding(5) +var s_roughness_metalness: sampler; + fn fog_noise(pos: vec3) -> f32 { var p = pos * FOG_SCALE; p.x += global_uniforms.time * 0.01; @@ -59,13 +88,31 @@ fn ray_march(origin: vec3, direction: vec3, scene_depth: f32) -> f32 { return density; } +// FIXME: always 0??? +fn scene_depth(clip_position: vec4) -> f32 { + if (clip_position.w <= 0.0) { + return 0.0; + } + + let ndc = clip_position.xy / clip_position.w; + let uv = ndc * vec2(0.5, -0.5) + vec2(0.5, 0.5); + return textureSample(t_geometry_depth, s_geometry_depth, uv); +} + @fragment fn fs_main(vert: FogVertexOutput) -> @location(0) vec4 { var color = vec4(0.5, 0.5, 0.5, 1.0); - let direction = normalize(vert.world_position.xyz - camera.position.xyz); - let scene_depth = FOG_MAX_DIST; // TODO: sample geometry pass depth buffer - let density = ray_march(vert.world_position.xyz, direction, scene_depth); + let cam_to_volume = vert.world_position.xyz - camera.position.xyz; + let distance_to_volume = length(cam_to_volume); + let direction = cam_to_volume / distance_to_volume; + // TODO: pass near and far plane in uniforms + let geometry_depth = scene_depth(vert.clip_position) * (3000.0 - 1.0) + 1.0 - distance_to_volume; + if (geometry_depth <= 0.0) + { + return vec4(0.0); + } + let density = ray_march(vert.world_position.xyz, direction, geometry_depth); color.a *= density; return color; diff --git a/src/core/state.rs b/src/core/state.rs index d1b2667..07fef01 100644 --- a/src/core/state.rs +++ b/src/core/state.rs @@ -45,7 +45,7 @@ pub struct State { geom_instance_buffer: wgpu::Buffer, fog_instances: Vec, fog_instance_buffer: wgpu::Buffer, - depth_texture: Texture, + geometry_depth_texture: Texture, geom_model: Model, fog_model: Model, light_model: Model, @@ -53,7 +53,7 @@ pub struct State { light_buffer: wgpu::Buffer, light_debug_pass: RenderPass, light_bind_group: wgpu::BindGroup, - light_depth_bind_group: wgpu::BindGroup, + depth_bind_group: wgpu::BindGroup, light_depth_pass: RenderPass, light_depth_texture_target_views: [TextureView; SHADOW_MAP_LAYERS as usize], global_uniforms: GlobalUniforms, @@ -152,16 +152,18 @@ impl State { let camera_controller = CameraController::new(400.0, 2.0); - let depth_texture = Texture::create_depth_texture( + let geometry_depth_texture = Texture::create_depth_texture( &device, - "depth_texture", + "geometry_depth_texture", Some(wgpu::CompareFunction::Less), config.width, config.height, 1, - wgpu::TextureUsages::RENDER_ATTACHMENT, + wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, ); + let geometry_abs_depth_sampler = Texture::create_sampler(&device, None); + let light_depth_texture = Texture::create_depth_texture( &device, "light_depth_texture", @@ -254,10 +256,10 @@ impl State { label: Some("Light Bind Group"), }); - let light_depth_bind_group_layout = + let depth_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { entries: &[ - // depth textures + // light cubemap wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStages::FRAGMENT, @@ -274,14 +276,31 @@ impl State { ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Comparison), count: None, }, + // geometry depth + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + view_dimension: wgpu::TextureViewDimension::D2, + sample_type: wgpu::TextureSampleType::Depth, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 3, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, ], - label: Some("Light Depth Bind Group Layout"), + label: Some("Depth Bind Group Layout"), }); - let light_depth_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &light_depth_bind_group_layout, + let depth_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &depth_bind_group_layout, entries: &[ - // depth textures + // light cubemap wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::TextureView(&light_depth_texture.view), @@ -290,8 +309,17 @@ impl State { binding: 1, resource: wgpu::BindingResource::Sampler(&light_depth_texture.sampler), }, + // geometry depth + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::TextureView(&geometry_depth_texture.view), + }, + wgpu::BindGroupEntry { + binding: 3, + resource: wgpu::BindingResource::Sampler(&geometry_abs_depth_sampler), + }, ], - label: Some("Light Depth Bind Group"), + label: Some("Depth Bind Group"), }); surface.configure(&device, &config); @@ -427,7 +455,7 @@ impl State { &[ &camera_bind_group_layout, &light_bind_group_layout, - &light_depth_bind_group_layout, + &depth_bind_group_layout, &texture_bind_group_layout, ], &[], @@ -445,7 +473,7 @@ impl State { &[ &camera_bind_group_layout, &light_bind_group_layout, - &light_depth_bind_group_layout, + &depth_bind_group_layout, &texture_bind_group_layout, ], &[], @@ -488,7 +516,7 @@ impl State { geom_instance_buffer, fog_instances, fog_instance_buffer, - depth_texture, + geometry_depth_texture, geom_model, fog_model, light_model, @@ -496,7 +524,7 @@ impl State { light_buffer, light_debug_pass, light_bind_group, - light_depth_bind_group, + depth_bind_group, light_depth_pass, light_depth_texture_target_views, global_uniforms, @@ -513,14 +541,14 @@ impl State { self.camera .projection .resize(new_size.width, new_size.height); - self.depth_texture = Texture::create_depth_texture( + self.geometry_depth_texture = Texture::create_depth_texture( &self.device, - "depth_texture", + "geometry_depth_texture", Some(wgpu::CompareFunction::Less), self.config.width, self.config.height, 1, - wgpu::TextureUsages::RENDER_ATTACHMENT, + wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, ); } } @@ -641,7 +669,7 @@ impl State { }, })], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.depth_texture.view, + view: &self.geometry_depth_texture.view, depth_ops: Some(wgpu::Operations { load: wgpu::LoadOp::Clear(1.0), store: StoreOp::Store, @@ -657,41 +685,7 @@ impl State { geom_render_pass.draw_model_instanced( &self.geom_model, 0..self.geom_instances.len() as u32, - [&self.camera_bind_group, &self.light_bind_group, &self.light_depth_bind_group].into(), - ); - } - encoder.pop_debug_group(); - - encoder.push_debug_group("fog pass"); - { - let mut fog_render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Fog Render Pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &surface_view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: StoreOp::Store, - }, - })], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.depth_texture.view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Load, - store: StoreOp::Store, - }), - stencil_ops: None, - }), - timestamp_writes: None, - occlusion_query_set: None, - }); - - fog_render_pass.set_vertex_buffer(1, self.fog_instance_buffer.slice(..)); - fog_render_pass.set_pipeline(&self.fog_pass.pipeline); - fog_render_pass.draw_model_instanced( - &self.fog_model, - 0..self.fog_instances.len() as u32, - [&self.camera_bind_group, &self.light_bind_group, &self.light_depth_bind_group].into(), + [&self.camera_bind_group, &self.light_bind_group, &self.depth_bind_group].into(), ); } encoder.pop_debug_group(); @@ -710,7 +704,7 @@ impl State { }, })], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.depth_texture.view, + view: &self.geometry_depth_texture.view, depth_ops: Some(wgpu::Operations { load: wgpu::LoadOp::Load, store: StoreOp::Store, @@ -730,6 +724,40 @@ impl State { } encoder.pop_debug_group(); + encoder.push_debug_group("fog pass"); + { + let mut fog_render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Fog Render Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &surface_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: StoreOp::Store, + }, + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.geometry_depth_texture.view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Load, + store: StoreOp::Store, + }), + stencil_ops: None, + }), + timestamp_writes: None, + occlusion_query_set: None, + }); + + fog_render_pass.set_vertex_buffer(1, self.fog_instance_buffer.slice(..)); + fog_render_pass.set_pipeline(&self.fog_pass.pipeline); + fog_render_pass.draw_model_instanced( + &self.fog_model, + 0..self.fog_instances.len() as u32, + [&self.camera_bind_group, &self.light_bind_group, &self.depth_bind_group].into(), + ); + } + encoder.pop_debug_group(); + self.queue.submit(std::iter::once(encoder.finish())); surface_texture.present(); diff --git a/src/core/texture.rs b/src/core/texture.rs index daae949..fd6458b 100644 --- a/src/core/texture.rs +++ b/src/core/texture.rs @@ -37,7 +37,17 @@ impl Texture { let texture = device.create_texture(&desc); let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); - let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + let sampler = Texture::create_sampler(device, compare); + + Self { + texture, + view, + sampler, + } + } + + pub fn create_sampler(device: &wgpu::Device, compare: Option) -> wgpu::Sampler { + device.create_sampler(&wgpu::SamplerDescriptor { address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::ClampToEdge, @@ -48,13 +58,7 @@ impl Texture { lod_min_clamp: 0.0, lod_max_clamp: 100.0, ..Default::default() - }); - - Self { - texture, - view, - sampler, - } + }) } pub fn from_pixels(