//! Generate a time-parameterized animation of a CSG object. //! //! > cargo run --example animation //! //! The animation will be saved as a series of VTK files in the `target/test_renderings/animation` directory. //! Applications like ParaView can natively render groups of VTK files as an animation. use crater::{ bounding::BoundingBox, csg::{ algebra::CSGAlgebra, marching_cubes::{marching_cubes, MarchingCubesParams}, regions::{Region, Side}, surfaces::Surface, transformations::Translate, }, mesh::MeshCollection, serde::vtk::evaluations::GeometryEvaluator, utils::Parallel, }; /// Emit a [`Region`] that is parameterized by time. fn region_at_time(t: f64) -> Region<3> { let omega = 100.0 / (2.0 * std::f64::consts::PI); let a = 1.0; let (kx, ky) = (1.0, 1.0); // Make a wavy surface let top = -Surface::parse_str( format!("z - {a} * (math::sin(math::sqrt({kx} * x^2 + {ky} * y^2) - {omega} * {t}))",) .as_str(), ) .unwrap(); // Make another wavy surface let bottom = Region::HalfSpace( Surface::parse_str( format!("z - {a} * (math::cos(math::sqrt({kx} * x^2 + {ky} * y^2) - {omega} * {t}))",) .as_str(), ) .unwrap() .transform(Translate([0.0, 0.0, -3.0])), Side::Positive, ); // Consider the region between the two wavy surfaces top & bottom } fn main() { let mut path_buf = std::path::PathBuf::from("./target/test_renderings/"); path_buf.push("animation"); std::fs::create_dir_all(&path_buf).expect("Failed to create directory"); let resolution = 50; let t_max = 10; let bound = 10.0; let bounds = BoundingBox { min: [-bound, -bound, -bound], max: [bound, bound, bound], }; for t in 0..t_max { let region = region_at_time(t as f64 / 100.0); // TODO: Params should not need to take ownership of the region/algebra let mesh: MeshCollection = marching_cubes::<Parallel>(&MarchingCubesParams { region, resolution: (resolution, resolution, resolution), bounds, algebra: CSGAlgebra::default(), }) .into(); let mut frame_path = path_buf.clone(); frame_path.push(format!("frame_{:04}", t)); frame_path.set_extension("vtk"); // Write the mesh to VTK: let algebra = CSGAlgebra::default(); let regions = [region_at_time(t as f64 / 100.0)]; mesh.to_vtk(Some(&[ Box::new(GeometryEvaluator::Gradients(®ions, &algebra)), // Box::new(GeometryEvaluator::Normals(®ions, &algebra)), // Box::new(GeometryEvaluator::Curvature(®ions, &algebra)), // Box::new(MeshColoring), ])) .export_be(frame_path) .expect("Failed to write frame"); } }