feat(camera): render anim using ffmpeg

This commit is contained in:
2026-03-31 20:15:30 +02:00
parent d0840759b3
commit fc40e0b798
6 changed files with 111 additions and 26 deletions

View File

@@ -1,11 +1,15 @@
use std::fmt::Display;
use std::{fmt::Display, path::Path};
use super::{
scene::Scene,
types::{Color, Point3, Ray, Scalar, Vector3},
RTError,
};
use image::RgbImage;
use lispers_core::lisp::eval::EvalError;
use ndarray::Array3;
use rayon::prelude::*;
use video_rs::{encode::Settings, Encoder, Time};
/// A camera that can render a scene.
#[derive(Clone, PartialEq, Debug)]
@@ -119,26 +123,47 @@ impl Camera {
Camera::new(position, center, up, fovy, self.width, self.height)
}
pub fn render_animation<SFn: Fn(u32) -> Scene, CFn: Fn(u32, &Camera) -> Camera>(
pub fn render_animation<
SFn: Fn(u32) -> Result<Scene, EvalError>,
CFn: Fn(u32, &Camera) -> Result<Camera, EvalError>,
>(
&self,
path: &Path,
scene_fn: SFn,
update_cam: CFn,
frames: u32,
fps: u32,
depth: u32,
subp: u32,
) {
) -> Result<(), RTError> {
let mut encoder = Encoder::new(
path,
Settings::preset_h264_yuv420p(self.width, self.height, false),
)?;
let frame_duration = Time::from_nth_of_a_second(fps as usize);
let mut timestamp = Time::zero();
let mut cam = self.to_owned();
for t in 0..frames {
println!("Rendering frame {}/{}", t + 1, frames);
cam = update_cam(t, &cam);
let img = cam.render(&scene_fn(t), depth, subp);
println!(
"Rendering frame {}/{} for {}",
t + 1,
frames,
path.display()
);
cam = update_cam(t, &cam)?;
let img = cam.render(&scene_fn(t)?, depth, subp);
match img.save(format!("frame_{:04}.png", t)) {
Ok(_) => {}
Err(e) => print!("Could not render frame: {}", e),
}
let frame = Array3::from_shape_fn((self.height, self.width, 3), |(y, x, c)| {
img.get_pixel(x as u32, y as u32)[c]
});
encoder.encode(&frame, timestamp)?;
timestamp = timestamp.aligned_with(frame_duration).add();
}
encoder.finish()?;
Ok(())
}
}