131 lines
2.8 KiB
Rust
131 lines
2.8 KiB
Rust
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<SphereParams>,
|
|
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,
|
|
);
|
|
}
|
|
}
|