diff --git a/src/bin/minitracer/main.rs b/src/bin/minitracer/main.rs index 4ae1d0e..679373a 100644 --- a/src/bin/minitracer/main.rs +++ b/src/bin/minitracer/main.rs @@ -32,6 +32,7 @@ fn make_viewport(w: u32, h: u32) -> [Vertex; 4] { } const N_SPHERES: u32 = 100; +const RAYS_PER_PIXEL: u32 = 4; fn main() { let event_loop = EventLoop::new().unwrap(); @@ -89,7 +90,6 @@ fn main() { return; } time += 1. / 60.; - frame += 1; let spheres: Vec<_> = sphere_params.iter().map(|p| p.to_sphere(time)).collect(); let data = TracerData::new(&device, &tracer, &spheres); @@ -98,11 +98,7 @@ fn main() { let size = output.texture.size(); let hdr = device.create_texture(&wgpu::TextureDescriptor { label: None, - size: wgpu::Extent3d { - width: 2 * size.width, - height: 2 * size.height, - depth_or_array_layers: 1, - }, + size, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, @@ -127,17 +123,20 @@ fn main() { occlusion_query_set: None, timestamp_writes: None, }); - tracer.render( - &mut render_pass, - &data, - &tracer_env, - trace::Params { - max_reflections: 3, - min_strength: 0.1, - sphere_count: N_SPHERES, - seed: frame, - }, - ); + for _ in 0..RAYS_PER_PIXEL { + frame += 1; + tracer.render( + &mut render_pass, + &data, + &tracer_env, + trace::Params { + max_reflections: 3, + min_strength: 0.1, + sphere_count: N_SPHERES, + seed: frame, + }, + ); + } } { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { @@ -154,7 +153,14 @@ fn main() { occlusion_query_set: None, timestamp_writes: None, }); - presenter.render(&device, &mut render_pass, &hdr); + presenter.render( + &device, + &mut render_pass, + &hdr, + present::Params { + divisor: RAYS_PER_PIXEL as f32, + }, + ); } queue.submit(std::iter::once(encoder.finish())); output.present(); diff --git a/src/bin/minitracer/present.rs b/src/bin/minitracer/present.rs index ae2b069..2cf8d84 100644 --- a/src/bin/minitracer/present.rs +++ b/src/bin/minitracer/present.rs @@ -10,6 +10,12 @@ struct Vertex { pub screen: Vec2, } +#[derive(Debug, Clone, Copy, Pod, Zeroable)] +#[repr(C)] +pub struct Params { + pub divisor: f32, +} + pub struct Presenter { view_buf: wgpu::Buffer, sampler: wgpu::Sampler, @@ -80,7 +86,18 @@ impl Presenter { } } - pub fn render(&self, device: &wgpu::Device, pass: &mut wgpu::RenderPass, texture: &wgpu::TextureView) { + pub fn render( + &self, + device: &wgpu::Device, + pass: &mut wgpu::RenderPass, + texture: &wgpu::TextureView, + params: Params, + ) { + let params_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: None, + contents: bytes_of(¶ms), + usage: wgpu::BufferUsages::UNIFORM, + }); let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor { label: None, layout: &self.pipeline.get_bind_group_layout(0), @@ -93,6 +110,10 @@ impl Presenter { binding: 1, resource: wgpu::BindingResource::TextureView(texture), }, + wgpu::BindGroupEntry { + binding: 2, + resource: params_buf.as_entire_binding(), + }, ], }); pass.set_pipeline(&self.pipeline); diff --git a/src/bin/minitracer/present.wgsl b/src/bin/minitracer/present.wgsl index eb2c411..2a7412f 100644 --- a/src/bin/minitracer/present.wgsl +++ b/src/bin/minitracer/present.wgsl @@ -1,3 +1,7 @@ +struct Params { + divisor: f32, +} + struct Vertex { @location(0) screen: vec2f, } @@ -9,6 +13,7 @@ struct Varying { @group(0) @binding(0) var smp: sampler; @group(0) @binding(1) var tex: texture_2d; +@group(0) @binding(2) var params: Params; @vertex fn on_vertex(in: Vertex) -> Varying { @@ -19,7 +24,7 @@ fn on_vertex(in: Vertex) -> Varying { @fragment fn on_fragment(in: Varying) -> @location(0) vec4f { - let pixel = textureSample(tex, smp, in.tex); + let pixel = textureSample(tex, smp, in.tex) / params.divisor; return vec4(rational_tone_map(pixel.xyz), 1.0); } diff --git a/src/bin/minitracer/trace.wgsl b/src/bin/minitracer/trace.wgsl index 9ee1b35..5f47d8e 100644 --- a/src/bin/minitracer/trace.wgsl +++ b/src/bin/minitracer/trace.wgsl @@ -69,7 +69,9 @@ fn trace_fragment(in: Varying) -> vec4f { var result = vec4(0.0, 0.0, 0.0, 0.0); var color = vec3(1.0, 1.0, 1.0); pos = in.eye; - ray = normalize(in.world - in.eye); + let off_px = vec2(rand_float(), rand_float()) - .5; + let off_w = mat2x3(dpdx(in.world), dpdy(in.world)); + ray = normalize(in.world + off_w * off_px - in.eye); for (var k = 0; k < params.max_reflections; k++) { var sphere = -1;