use crate::anim::{self, SphereParams}; use crate::trace::{self, Tracer, TracerData}; use glam::{mat3, uvec2, vec3, UVec2, Vec3}; use std::f32::consts::PI; struct CamLoc { eye: Vec3, forward: Vec3, right: Vec3, } fn make_viewport(w: u32, h: u32) -> trace::Viewport { let size = uvec2(w, h).as_vec2(); let size = size.normalize(); trace::Viewport { corner: vec3(size.x, size.y, 1.), } } fn convert_location(cam: CamLoc) -> trace::CameraLocation { let fwd = cam.forward.normalize(); let up = cam.right.cross(fwd).normalize(); let right = up.cross(fwd).normalize(); trace::CameraLocation { eye: cam.eye, view: mat3(right, up, fwd), } } const N_SPHERES: u32 = 100; const CAMERA_LAG: f32 = 0.03; pub struct Renderer { tracer: Tracer, } impl Renderer { pub fn new(device: &wgpu::Device) -> Self { let hdr_format = wgpu::TextureFormat::Rgba16Float; let tracer = Tracer::new(&device, hdr_format); Self { tracer } } } pub struct SceneParams { pub spheres: Vec, pub camera: SphereParams, pub target: SphereParams, } impl SceneParams { pub fn new(n_spheres: u32) -> Self { let mut rng = rand_pcg::Pcg32::new(42, 0); let spheres: Vec<_> = { let distr = anim::distr(); (0..n_spheres).map(|_| distr(&mut rng)).collect() }; let camera = { let mut p = anim::distr()(&mut rng); p.amplitudes *= 2.0; p.frequencies *= 0.1; p }; let target = { let mut p = spheres[0]; p.phases -= 2. * PI * CAMERA_LAG * p.frequencies; p }; Self { spheres, camera, target, } } } impl Default for SceneParams { fn default() -> Self { Self::new(N_SPHERES) } } pub struct RenderPass<'encoder>(wgpu::RenderPass<'encoder>); impl Renderer { pub fn prepare<'encoder>( &self, encoder: &'encoder mut wgpu::CommandEncoder, target: &wgpu::TextureView, ) -> RenderPass<'encoder> { RenderPass(self.tracer.prepare(encoder, target)) } pub fn render_frame( &self, device: &wgpu::Device, render_pass: &mut RenderPass, size: UVec2, scene: &SceneParams, time: f32, seed: u32, ) { let target = scene.target.to_sphere(time).center; let eye = scene.camera.to_sphere(time).center; let right = scene.camera.deriv(time); let forward = target - eye; let viewport = make_viewport(size.x, size.y); let location = convert_location(CamLoc { eye, forward, right }); let spheres: Vec<_> = scene.spheres.iter().map(|p| p.to_sphere(time)).collect(); let data = TracerData::new(&device, &self.tracer, &spheres); self.tracer.render( &mut render_pass.0, &data, trace::Params { max_reflections: 3, min_strength: 0.1, sphere_count: N_SPHERES, seed, }, viewport, trace::Aperture { radius: 0.0003, focal_distance: std::f32::INFINITY, glare_strength: 0.1, glare_radius: 0.1, }, location, ); } }