From 4b7532ca0d6ff21d5531febb749b43112d0451e8 Mon Sep 17 00:00:00 2001 From: Charlotte Pabst Date: Sat, 23 Mar 2024 16:54:20 +0100 Subject: --- examples/subdivision.rs | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 examples/subdivision.rs (limited to 'examples/subdivision.rs') diff --git a/examples/subdivision.rs b/examples/subdivision.rs new file mode 100644 index 0000000..ba80e49 --- /dev/null +++ b/examples/subdivision.rs @@ -0,0 +1,130 @@ +use dcel::{ptr_t, Dcel, ObjExport, ObjImport, Ptr, Shell}; +use std::array::from_fn; +use std::collections::HashMap; + +fn avg(mut iter: impl Iterator) -> Option<[f32; 3]> { + let mut count = 0usize; + let mut accum = [0.0; 3]; + + for x in iter { + count += 1; + accum = from_fn(|i| accum[i] + x[i]) + } + + (count > 0).then(|| accum.map(|x| x / (count as f32))) +} + +fn catmull_clark_subdivision<'brand, 'arena>( + dcel: &mut Dcel<'brand, 'arena, [f32; 3]>, + shell: ptr_t!(Shell<'brand, 'arena, [f32; 3]>), +) { + let face_points = shell + .iter_faces(dcel) + .map(|f| { + ( + f.id(), + avg(f.outer_loop().iter_half_edges().map(|x| *x.origin().data())).unwrap(), + ) + }) + .collect::>(); + + let vert_points = shell + .iter_vertices(dcel) + .map(|vert| { + let p = vert.data(); + let mut n = 0.0; + let mut f = [0.0; 3]; + let mut r = [0.0; 3]; + + for h in vert.iter_outgoing() { + let fp = face_points[&h.loop_().face().id()]; + let op = *h.origin().data(); + let tp = *h.target().data(); + + f = from_fn(|i| f[i] + fp[i]); + r = from_fn(|i| r[i] + op[i] + tp[i]); + + n += 1.0; + } + + ( + vert.id(), + ( + vert.item, + from_fn(|i| (f[i] / n + r[i] / n + (n - 3.0) * p[i]) / n), + ), + ) + }) + .collect::>(); + + for edge in shell.iter_edges(dcel).map(|x| x.item).collect::>() { + let data = avg(edge + .lens(dcel) + .half_edges() + .into_iter() + .flat_map(|h| [face_points[&h.loop_().face().id()], *h.origin().data()])) + .unwrap(); + + dcel.mve(edge, data).unwrap(); + } + + for &(vert, data) in vert_points.values() { + *vert.mut_data(dcel) = data; + } + + for face in shell.iter_faces(dcel).map(|x| x.item).collect::>() { + let loop_ = face.outer_loop(dcel); + + let mut verts = loop_ + .iter_half_edges(dcel) + .skip_while(|h| vert_points.contains_key(&h.origin().id())) + .map(|h| h.origin().item) + .step_by(2) + .collect::>() + .into_iter(); + + let inner = *dcel + .mev(loop_, verts.next().unwrap(), face_points[&face.id(dcel)]) + .unwrap() + .vertex; + + verts.fold([loop_; 2], |loops, vert| { + let l = loops + .into_iter() + .find(|&l| vert.find_outgoing(l, dcel).is_some()) + .unwrap(); + [l, *dcel.melf([vert, inner], l).unwrap().loop_] + }); + } +} + +fn main() { + Dcel::new(|mut dcel| { + let body = ObjImport::import( + &mut dcel, + &obj::raw::object::parse_obj(&mut std::io::BufReader::new( + std::fs::File::open("bunny.obj").unwrap(), + )) + .unwrap(), + |(x, y, z, _)| [x, y, z], + ) + .unwrap(); + + let shell = body.iter_shells(&dcel).next().unwrap().item; + + for i in 0..5 { + println!("{i}..."); + catmull_clark_subdivision(&mut dcel, shell); + } + + println!("exporting..."); + ObjExport::export( + &mut std::io::BufWriter::new(std::fs::File::create("bunny2.obj").unwrap()), + &dcel, + |&[x, y, z]| (x as _, y as _, z as _, None), + |_, _| None, + |_, _| None, + ) + .unwrap(); + }); +} -- cgit v1.2.3