diff --git a/src/lib.rs b/src/lib.rs index 926df41..457a3f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,8 @@ use std::{convert::identity, error::Error, f32::consts::PI}; -use glam::{Mat4, UVec2, Vec3, vec3}; +use glam::{Mat4, UVec2, Vec2, Vec3, vec3}; +use rand_distr::Distribution as _; use crate::{ camera::OrbitalCamera, @@ -33,6 +34,8 @@ pub struct RedrawArgs { pub light_position: SphericalPosition, pub light_radius: f32, pub light_spread: f32, + pub accum_sigma: f32, + pub accum_scale: f32, } pub struct Gpu { @@ -85,6 +88,22 @@ fn loop_list_ex( } } +impl OrbitalCamera { + fn make_ray(&self, rng: &mut impl rand::Rng) -> Ray { + let off: f32 = rand_distr::StandardUniform.sample(rng); + let side: Vec2 = rand_distr::UnitCircle.sample(rng).into(); + + let m = self.transform().inverse(); + let fwd = 1. - 0.1 * off; + let side_scale = (1. - fwd.powi(2)).sqrt(); + let dir = Vec3::from((side_scale * side, fwd)); + Ray { + base: self.position(), + dir: m.transform_vector3(dir), + } + } +} + impl Core { pub fn new(gpu: Gpu) -> Self { let Gpu { @@ -190,7 +209,8 @@ impl Core { }; let mut prng = rand_pcg::Pcg64::new(42, 0); - let source_rays: Vec = (0..1024).map(|_| source.make_ray(&mut prng)).collect(); + let source_rays: Vec = (0..10240).map(|_| source.make_ray(&mut prng)).collect(); + let camera_rays: Vec = (0..1024).map(|_| camera.make_ray(&mut prng)).collect(); let mut source_ray_display: Vec = Vec::with_capacity(source_rays.len()); let mut hits: Vec = Vec::with_capacity(source_rays.len()); for ray in source_rays { @@ -227,8 +247,39 @@ impl Core { ]); } } + let mut camera_ray_display: Vec = Vec::with_capacity(camera_rays.len()); + let sigma2 = args.accum_sigma.powi(2); + let weight = (2. * PI * sigma2).sqrt().recip() * args.accum_scale; + for ray in camera_rays { + let Some(hit) = scene.trace_ray(ray) else { + continue; + }; + let mut value = 0.0f32; + for light_hit in &hits { + let d2 = hit.base.distance_squared(light_hit.base); + let w = (-0.5 * d2 / sigma2).exp(); + value += w; + } + value *= weight; + let r = 0.01; + let color = vec3(value, value - 1., value - 2.).clamp(Vec3::splat(0.), Vec3::splat(1.)); + let vertex = |off: Vec3| Vertex { + pos: hit.base + r * off, + color, + }; + camera_ray_display.extend([ + vertex(-Vec3::X), + vertex(Vec3::X), + vertex(-Vec3::Y), + vertex(Vec3::Y), + vertex(-Vec3::Z), + vertex(Vec3::Z), + ]); + } self.pipeline .render(&mut pass, [&Mesh::new(&self.device, &source_ray_display)]); + self.pipeline + .render(&mut pass, [&Mesh::new(&self.device, &camera_ray_display)]); drop(pass); self.queue.submit(std::iter::once(encoder.finish())); diff --git a/ui/src/api.hxx b/ui/src/api.hxx index 50b9e67..19b742c 100644 --- a/ui/src/api.hxx +++ b/ui/src/api.hxx @@ -18,6 +18,8 @@ struct RedrawArgs { SphericalPosition light_position; float light_radius; float light_spread; + float accum_sigma; + float accum_scale; }; } // namespace ffi diff --git a/ui/src/main_window.cxx b/ui/src/main_window.cxx index bdf890f..97d4302 100644 --- a/ui/src/main_window.cxx +++ b/ui/src/main_window.cxx @@ -29,11 +29,15 @@ void PhotonLight::updateView() { }, .light_radius = 0.125, .light_spread = 0.125, + .accum_sigma = exp10f(m_ui->accumSigma->value() / 25.0), + .accum_scale = exp10f(m_ui->accumScale->value() / 25.0), }; m_ui->cameraYawLabel->setText(tr("Yaw: %1 deg").arg(QString::number(qRadiansToDegrees(args.camera_position.yaw)))); m_ui->cameraPitchLabel->setText(tr("Pitch: %1 deg").arg(QString::number(qRadiansToDegrees(args.camera_position.pitch)))); m_ui->lightYawLabel->setText(tr("Yaw: %1 deg").arg(QString::number(qRadiansToDegrees(args.light_position.yaw)))); m_ui->lightPitchLabel->setText(tr("Pitch: %1 deg").arg(QString::number(qRadiansToDegrees(args.light_position.pitch)))); + m_ui->accumSigmaLabel->setText(tr("Sigma: %1").arg(QString::number(args.accum_sigma))); + m_ui->accumScaleLabel->setText(tr("Scale: %1").arg(QString::number(args.accum_scale))); m_ui->viewport->setView(args); } diff --git a/ui/src/main_window.ui b/ui/src/main_window.ui index 26cf5b6..aef1ac0 100644 --- a/ui/src/main_window.ui +++ b/ui/src/main_window.ui @@ -162,6 +162,55 @@ + + + + Accumulating + + + + + + Sigma + + + + + + + -100 + + + 100 + + + Qt::Horizontal + + + + + + + Scale + + + + + + + -100 + + + 100 + + + Qt::Horizontal + + + + + + @@ -253,6 +302,38 @@ + + accumSigma + valueChanged(int) + MainWindow + updateView() + + + 729 + 479 + + + 399 + 299 + + + + + accumScale + valueChanged(int) + MainWindow + updateView() + + + 729 + 535 + + + 399 + 299 + + + updateView()