tirbofish/dropbear · diff
wip: resetting computer, creating backup
Signature present but could not be verified.
Unverified
@@ -80,14 +80,6 @@ pub struct Camera { pub view_mat: DMat4, /// Projection Matrix pub proj_mat: DMat4, - - /// Smooth damping factor for camera position updates (0.0 = no smoothing, higher = more smoothing) - /// This helps prevent jittering when camera follows physics-driven objects - pub position_smoothing: f64, - /// Internal: previous eye position for smoothing - smooth_eye: DVec3, - /// Internal: previous target position for smoothing - smooth_target: DVec3, } /// A simple builder/struct that allows you to build a [`Camera`] @@ -102,7 +94,7 @@ pub struct CameraBuilder { } impl Camera { - pub const CAMERA_BIND_GROUP_LAYOUT: wgpu::BindGroupLayoutDescriptor<'_> = + pub const CAMERA_BIND_GROUP_LAYOUT: wgpu::BindGroupLayoutDescriptor<'_> = BindGroupLayoutDescriptor { entries: &[BindGroupLayoutEntry { binding: 0, @@ -173,9 +165,6 @@ impl Camera { }, view_mat, proj_mat, - position_smoothing: 10.0, // Default smoothing value - smooth_eye: builder.eye, - smooth_target: builder.target, }; log::debug!("Created new camera{}", if let Some(l) = label { format!(" with the label {}", l) } else { String::new() } ); @@ -228,17 +217,7 @@ impl Camera { } fn build_vp(&mut self) -> DMat4 { - // Apply smooth interpolation to camera position if smoothing is enabled - if self.position_smoothing > 0.0 { - let lerp_factor = (1.0 / (1.0 + self.position_smoothing)).clamp(0.0, 1.0); - self.smooth_eye = self.smooth_eye.lerp(self.eye, lerp_factor); - self.smooth_target = self.smooth_target.lerp(self.target, lerp_factor); - } else { - self.smooth_eye = self.eye; - self.smooth_target = self.target; - } - - let view = DMat4::look_at_lh(self.smooth_eye, self.smooth_target, self.up); + let view = DMat4::look_at_lh(self.eye, self.target, self.up); let proj = DMat4::perspective_infinite_reverse_lh( self.settings.fov_y.to_radians(), self.aspect, @@ -62,6 +62,7 @@ pub use gilrs; pub use wgpu; pub use winit; use winit::window::{WindowAttributes, WindowId}; +use crate::pipelines::hdr::HdrPipeline; use crate::scene::Scene; pub struct BindGroupLayouts { @@ -94,6 +95,7 @@ pub struct State { pub texture_id: Arc<TextureId>, pub future_queue: Arc<FutureQueue>, pub mipmapper: Arc<MipMapper>, + pub hdr: Arc<HdrPipeline>, physics_accumulator: Duration, @@ -243,8 +245,8 @@ Hardware: let mut egui_renderer = Arc::new(Mutex::new(EguiRenderer::new( &device, - config.format, - None, + Texture::TEXTURE_FORMAT, + Some(Texture::DEPTH_FORMAT), 1, &window, ))); @@ -333,6 +335,8 @@ Hardware: let device = Arc::new(device); let queue = Arc::new(queue); + let hdr = Arc::new(HdrPipeline::new(&device, &config)); + // let yakui_renderer = Arc::new(Mutex::new(yakui_wgpu::YakuiWgpu::new( // &device, // &queue @@ -375,6 +379,7 @@ Hardware: supports_storage: supports_storage_resources, // yakui_renderer, // yakui_texture, + hdr, }; Ok(result) @@ -390,6 +395,8 @@ Hardware: } self.surface.configure(&self.device, &self.config.read()); self.is_surface_configured = true; + Arc::get_mut(&mut self.hdr) + .resize(&self.device, width, height); } self.depth_texture = @@ -466,7 +473,7 @@ Hardware: let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("surface clear pass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &view, + view: &self.hdr.view(), depth_slice: None, resolve_target: None, ops: wgpu::Operations { @@ -1,158 +1,166 @@ -// use crate::texture::Texture; -// -// pub struct HdrPipeline { -// pipeline: wgpu::RenderPipeline, -// bind_group: wgpu::BindGroup, -// texture: Texture, -// width: u32, -// height: u32, -// format: wgpu::TextureFormat, -// layout: wgpu::BindGroupLayout, -// } -// -// impl HdrPipeline { -// pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration) -> Self { -// let width = config.width; -// let height = config.height; -// -// // We could use `Rgba32Float`, but that requires some extra -// // features to be enabled for rendering. -// let format = wgpu::TextureFormat::Rgba16Float; -// -// let texture = Texture( -// device, -// width, -// height, -// format, -// wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT, -// wgpu::FilterMode::Nearest, -// Some("Hdr::texture"), -// ); -// -// let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { -// label: Some("Hdr::layout"), -// entries: &[ -// // This is the HDR texture -// wgpu::BindGroupLayoutEntry { -// binding: 0, -// visibility: wgpu::ShaderStages::FRAGMENT, -// ty: wgpu::BindingType::Texture { -// sample_type: wgpu::TextureSampleType::Float { filterable: true }, -// view_dimension: wgpu::TextureViewDimension::D2, -// multisampled: false, -// }, -// count: None, -// }, -// wgpu::BindGroupLayoutEntry { -// binding: 1, -// visibility: wgpu::ShaderStages::FRAGMENT, -// ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), -// count: None, -// }, -// ], -// }); -// let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { -// label: Some("Hdr::bind_group"), -// layout: &layout, -// entries: &[ -// wgpu::BindGroupEntry { -// binding: 0, -// resource: wgpu::BindingResource::TextureView(&texture.view), -// }, -// wgpu::BindGroupEntry { -// binding: 1, -// resource: wgpu::BindingResource::Sampler(&texture.sampler), -// }, -// ], -// }); -// -// // We'll cover the shader next -// let shader = wgpu::include_wgsl!("hdr.wgsl"); -// let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { -// label: None, -// bind_group_layouts: &[&layout], -// push_constant_ranges: &[], -// }); -// -// let pipeline = create_render_pipeline( -// device, -// &pipeline_layout, -// config.format.add_srgb_suffix(), -// None, -// // We'll use some math to generate the vertex data in -// // the shader, so we don't need any vertex buffers -// &[], -// wgpu::PrimitiveTopology::TriangleList, -// shader, -// ); -// -// Self { -// pipeline, -// bind_group, -// layout, -// texture, -// width, -// height, -// format, -// } -// } -// -// /// Resize the HDR texture -// pub fn resize(&mut self, device: &wgpu::Device, width: u32, height: u32) { -// self.texture = texture::Texture::create_2d_texture( -// device, -// width, -// height, -// wgpu::TextureFormat::Rgba16Float, -// wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT, -// wgpu::FilterMode::Nearest, -// Some("Hdr::texture"), -// ); -// self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { -// label: Some("Hdr::bind_group"), -// layout: &self.layout, -// entries: &[ -// wgpu::BindGroupEntry { -// binding: 0, -// resource: wgpu::BindingResource::TextureView(&self.texture.view), -// }, -// wgpu::BindGroupEntry { -// binding: 1, -// resource: wgpu::BindingResource::Sampler(&self.texture.sampler), -// }, -// ], -// }); -// self.width = width; -// self.height = height; -// } -// -// /// Exposes the HDR texture -// pub fn view(&self) -> &wgpu::TextureView { -// &self.texture.view -// } -// -// /// The format of the HDR texture -// pub fn format(&self) -> wgpu::TextureFormat { -// self.format -// } -// -// /// This renders the internal HDR texture to the [TextureView] -// /// supplied as parameter. -// pub fn process(&self, encoder: &mut wgpu::CommandEncoder, output: &wgpu::TextureView) { -// let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { -// label: Some("Hdr::process"), -// color_attachments: &[Some(wgpu::RenderPassColorAttachment { -// view: &output, -// resolve_target: None, -// ops: Operations { -// load: wgpu::LoadOp::Load, -// store: wgpu::StoreOp::Store, -// }, -// })], -// depth_stencil_attachment: None, -// }); -// pass.set_pipeline(&self.pipeline); -// pass.set_bind_group(0, &self.bind_group, &[]); -// pass.draw(0..3, 0..1); -// } -// } +use wgpu::Operations; +use crate::pipelines::create_render_pipeline; +use crate::texture::Texture; + +pub struct HdrPipeline { + pipeline: wgpu::RenderPipeline, + bind_group: wgpu::BindGroup, + texture: Texture, + width: u32, + height: u32, + format: wgpu::TextureFormat, + layout: wgpu::BindGroupLayout, +} + +impl HdrPipeline { + pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration) -> Self { + let width = config.width; + let height = config.height; + + // We could use `Rgba32Float`, but that requires some extra + // features to be enabled for rendering. + let format = wgpu::TextureFormat::Rgba16Float; + + let texture = Texture::create_2d_texture( + device, + width, + height, + format, + wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT, + wgpu::FilterMode::Nearest, + Some("Hdr::texture"), + ); + + + + let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Hdr::layout"), + entries: &[ + // This is the HDR texture + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + }); + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("Hdr::bind_group"), + layout: &layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&texture.view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&texture.sampler), + }, + ], + }); + + // We'll cover the shader next + let shader = wgpu::include_wgsl!("shaders/hdr.wgsl"); + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&layout], + push_constant_ranges: &[], + }); + + let pipeline = create_render_pipeline( + Some("hdr render pipeline"), + device, + &pipeline_layout, + config.format.add_srgb_suffix(), + None, + // We'll use some math to generate the vertex data in + // the shader, so we don't need any vertex buffers + &[], + wgpu::PrimitiveTopology::TriangleList, + shader, + ); + + Self { + pipeline, + bind_group, + layout, + texture, + width, + height, + format, + } + } + + /// Resize the HDR texture + pub fn resize(&mut self, device: &wgpu::Device, width: u32, height: u32) { + self.texture = Texture::create_2d_texture( + device, + width, + height, + wgpu::TextureFormat::Rgba16Float, + wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT, + wgpu::FilterMode::Nearest, + Some("Hdr::texture"), + ); + self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("Hdr::bind_group"), + layout: &self.layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&self.texture.view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&self.texture.sampler), + }, + ], + }); + self.width = width; + self.height = height; + } + + /// Exposes the HDR texture + pub fn view(&self) -> &wgpu::TextureView { + &self.texture.view + } + + /// The format of the HDR texture + pub fn format(&self) -> wgpu::TextureFormat { + self.format + } + + /// This renders the internal HDR texture to the [TextureView] + /// supplied as parameter. + pub fn process(&self, encoder: &mut wgpu::CommandEncoder, output: &wgpu::TextureView) { + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Hdr::process"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &output, + depth_slice: None, + resolve_target: None, + ops: Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + pass.set_pipeline(&self.pipeline); + pass.set_bind_group(0, &self.bind_group, &[]); + pass.draw(0..3, 0..1); + } +} @@ -5,7 +5,7 @@ use crate::shader::Shader; pub mod shader; pub mod light_cube; pub mod globals; -mod hdr; +pub mod hdr; pub use globals::{Globals, GlobalsUniform}; @@ -21,4 +21,64 @@ pub trait DropbearShaderPipeline { fn pipeline_layout(&self) -> &wgpu::PipelineLayout; /// Fetches the pipeline fn pipeline(&self) -> &wgpu::RenderPipeline; -} +} + +fn create_render_pipeline( + label: Option<&str>, + device: &wgpu::Device, + layout: &wgpu::PipelineLayout, + color_format: wgpu::TextureFormat, + depth_format: Option<wgpu::TextureFormat>, + vertex_layouts: &[wgpu::VertexBufferLayout], + topology: wgpu::PrimitiveTopology, + shader: wgpu::ShaderModuleDescriptor, +) -> wgpu::RenderPipeline { + let shader = device.create_shader_module(shader); + + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label, + layout: Some(layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: Some("vs_main"), + buffers: vertex_layouts, + compilation_options: Default::default(), + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: Some("fs_main"), + targets: &[Some(wgpu::ColorTargetState { + format: color_format, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + })], + compilation_options: Default::default(), + }), + primitive: wgpu::PrimitiveState { + topology, // NEW! + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: Some(wgpu::Face::Back), + // Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE + polygon_mode: wgpu::PolygonMode::Fill, + // Requires Features::DEPTH_CLIP_CONTROL + unclipped_depth: false, + // Requires Features::CONSERVATIVE_RASTERIZATION + conservative: false, + }, + depth_stencil: depth_format.map(|format| wgpu::DepthStencilState { + format, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::LessEqual, // UDPATED! + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + cache: None, + multiview: None, + }) +} @@ -0,0 +1,55 @@ +// Maps HDR values to linear values +// Based on http://www.oscars.org/science-technology/sci-tech-projects/aces +fn aces_tone_map(hdr: vec3<f32>) -> vec3<f32> { + let m1 = mat3x3( + 0.59719, 0.07600, 0.02840, + 0.35458, 0.90834, 0.13383, + 0.04823, 0.01566, 0.83777, + ); + let m2 = mat3x3( + 1.60475, -0.10208, -0.00327, + -0.53108, 1.10813, -0.07276, + -0.07367, -0.00605, 1.07602, + ); + let v = m1 * hdr; + let a = v * (v + 0.0245786) - 0.000090537; + let b = v * (0.983729 * v + 0.4329510) + 0.238081; + return clamp(m2 * (a / b), vec3(0.0), vec3(1.0)); +} + +struct VertexOutput { + @location(0) uv: vec2<f32>, + @builtin(position) clip_position: vec4<f32>, +}; + +@vertex +fn vs_main( + @builtin(vertex_index) vi: u32, +) -> VertexOutput { + var out: VertexOutput; + // Generate a triangle that covers the whole screen + out.uv = vec2<f32>( + f32((vi << 1u) & 2u), + f32(vi & 2u), + ); + out.clip_position = vec4<f32>(out.uv * 2.0 - 1.0, 0.0, 1.0); + // We need to invert the y coordinate so the image + // is not upside down + out.uv.y = 1.0 - out.uv.y; + return out; +} + +@group(0) +@binding(0) +var hdr_image: texture_2d<f32>; + +@group(0) +@binding(1) +var hdr_sampler: sampler; + +@fragment +fn fs_main(vs: VertexOutput) -> @location(0) vec4<f32> { + let hdr = textureSample(hdr_image, hdr_sampler, vs.uv); + let sdr = aces_tone_map(hdr.rgb); + return vec4(sdr, hdr.a); +} @@ -75,6 +75,71 @@ impl Texture { pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; pub const TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8UnormSrgb; + pub fn create_2d_texture( + device: &wgpu::Device, + width: u32, + height: u32, + format: wgpu::TextureFormat, + usage: wgpu::TextureUsages, + mag_filter: wgpu::FilterMode, + label: Option<&str>, + ) -> Self { + let size = wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }; + Self::create_texture( + device, + label, + size, + format, + usage, + wgpu::TextureDimension::D2, + mag_filter, + ) + } + + pub fn create_texture( + device: &wgpu::Device, + label: Option<&str>, + size: wgpu::Extent3d, + format: wgpu::TextureFormat, + usage: wgpu::TextureUsages, + dimension: wgpu::TextureDimension, + mag_filter: wgpu::FilterMode, + ) -> Self { + let texture = device.create_texture(&wgpu::TextureDescriptor { + label, + size, + mip_level_count: 1, + sample_count: 1, + dimension, + format, + usage, + view_formats: &[], + }); + + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + + Self { + label: label.and_then(|v| Some(v.to_string())), + texture, + view, + sampler, + size, + } + } + /// Creates a new depth texture. This is an internal function. pub fn depth_texture( config: &wgpu::SurfaceConfiguration,