From 216d7d24c681721ee395d4b3b4b2a641f7d6b6a1 Mon Sep 17 00:00:00 2001 From: Riley Trautman Date: Sat, 18 Nov 2017 18:52:42 -0600 Subject: [PATCH] Don't use nearly as much ram lmao Parallelize with Rayon --- Cargo.toml | 1 + data/test.obj | 20 ---- src/main.rs | 254 +++++++++++++++++++++++++++----------------------- 3 files changed, 137 insertions(+), 138 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2de496..25eac57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ license = "MIT" obj = "0.8" noise = "0.4" cgmath = "0.15.0" +rayon = "0.9.0" diff --git a/data/test.obj b/data/test.obj index 383939a..60b824a 100644 --- a/data/test.obj +++ b/data/test.obj @@ -12,14 +12,6 @@ v 1 0 3 v 1 1 3 v 1 1 0 v 1 0 0 -v 2 0 0 -v 2 1 3 -v 2 1 0 -v 2 0 3 -v 3 0 3 -v 3 1 3 -v 3 1 0 -v 3 0 0 # 0 UV coordinates @@ -46,16 +38,4 @@ f 1//5 7//5 8//5 f 7//5 1//5 3//5 f 1//6 5//6 4//6 f 5//6 1//6 8//6 -f 9//1 10//1 11//1 -f 10//1 9//1 12//1 -f 10//2 13//2 14//2 -f 13//2 10//2 12//2 -f 13//3 15//3 14//3 -f 15//3 13//3 16//3 -f 15//4 10//4 14//4 -f 10//4 15//4 11//4 -f 9//5 15//5 16//5 -f 15//5 9//5 11//5 -f 9//6 13//6 12//6 -f 13//6 9//6 16//6 diff --git a/src/main.rs b/src/main.rs index dd4c5c3..ab03654 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,19 +4,20 @@ extern crate obj; extern crate noise; extern crate cgmath; +extern crate rayon; -use std::io::Result; +use std::sync::{Arc, Mutex}; use std::path::Path; -use std::f32::consts::PI; use std::fs::File; -use std::io::Write; +use std::io::{BufWriter, Cursor, Write}; use obj::{Obj, SimplePolygon, IndexTuple}; use noise::Fbm; //use noise::Seedable; -//use noise::MultiFractal; +use noise::MultiFractal; use noise::NoiseModule; use cgmath::Vector3; use cgmath::ElementWise; +use rayon::prelude::*; // A function called test that takes in 1 32-bit integer // and returns a 32-bit integer. @@ -45,12 +46,11 @@ fn distance_a_to_b(ax: f32, ay: f32, bx: f32, by: f32) -> f32 { } fn return_at(x: f32, y: f32, fbmnoise: &Fbm) -> f32 { - let n = 20.0 * fbmnoise.get([x, y]); - let n = n - n.floor(); + let zero_to_one_noise = (1.0 + fbmnoise.get([x, y])) * 0.5; + let z = 0.0f32; + let m = z.max(1.0 - 1.0 * distance_a_to_b(x, y, 0.5, 0.5)); - let m = distance_a_to_b(x, y, 0.5, 0.5); - - return (m * 0.15) + (n * 0.85); + return (zero_to_one_noise * 0.90) + (m * 0.10); } fn find_l_w(obj: &Obj) -> (f32, f32) { @@ -85,151 +85,169 @@ fn find_l_w(obj: &Obj) -> (f32, f32) { * to the initial input obj's position. */ -fn calculate_angle(current_duplicate: i32, current_layer: i32) -> f32 { - (current_duplicate / (2 * current_layer)) as f32 * (0.5 * PI) -} - -fn calculate_translation(length: f32, width: f32, angle: f32) -> Vector3 { - Vector3::new(length * angle.cos(), width * angle.sin(), 0.0) -} - -fn duplicate( - positions: Vec>, +fn duplicate( + positions: &[Vector3], translation: Vector3, height_scalar: f32, -) -> Vec> { - positions - .iter() - .map(|point| { - Vector3::new( - point.x + translation.x, - point.y + translation.y, - point.z * height_scalar, - ) - }) - .collect() + file: Arc>>, +) where + T: Write, +{ + let v = Vec::new(); + let c = Cursor::new(v); + let mut b = BufWriter::new(c); + + for point in positions { + write!( + b, + "v {} {} {}\n", + point.x + translation.x, + point.y + translation.y, + point.z * height_scalar * 2.0 + ).unwrap(); + } + + file.lock() + .unwrap() + .write(b.into_inner().unwrap().into_inner().as_ref()) + .unwrap(); } -fn generate_city( - positions: Vec>, +fn write_positions( + positions: &[Vector3], layers: i32, spacing: f32, length: f32, width: f32, -) -> Vec> { + file: Arc>>, +) where + T: Write + Send, +{ let length = length + spacing; let width = width + spacing; - let mut temp = Vector3::new(0.0, 0.0, 0.0); + let fbm: Fbm = Fbm::new() + .set_octaves(1) + .set_frequency(6.0) + .set_persistence(3.0) + .set_lacunarity(30.0); - let mut coord = Vector3::new(0.5, 0.5, 0.0); + duplicate( + positions, + Vector3::new(0.0, 0.0, 0.0), + return_at(0.5, 0.5, &fbm), + file.clone(), + ); - let fbm: Fbm = Fbm::new(); + (0..((layers * (layers - 1)) * 4)) + .into_par_iter() + .for_each(move |current_duplicate| { + let current_layer = (0.5 * (((current_duplicate + 1) as f32).sqrt() - 1.0)) as i32 + 1; + let current_duplicate = current_duplicate - 4 * current_layer * (current_layer - 1); - (1..layers).fold(positions.clone(), |acc_positions, current_layer| { - temp.x = -length * (current_layer as f32); - temp.y = -width * (current_layer as f32); + let current_ratio = current_duplicate as f32 / (current_layer as f32 * 8.0); - (0..(current_layer * 8)).fold(acc_positions, |mut acc_positions, current_duplicate| { + let unit_translation = if current_ratio <= 1.0 / 4.0 { + Vector3::new(1.0, -1.0 + (current_ratio * 8.0), 0.0) + } else if current_ratio <= 2.0 / 4.0 { + Vector3::new(1.0 - ((current_ratio) - 1.0 / 4.0) * 8.0, 1.0, 0.0) + } else if current_ratio <= 3.0 / 4.0 { + Vector3::new(-1.0, 1.0 - ((current_ratio) - 2.0 / 4.0) * 8.0, 0.0) + } else { + Vector3::new(-1.0 + ((current_ratio) - 3.0 / 4.0) * 8.0, -1.0, 0.0) + }; - let angle = calculate_angle(current_duplicate, current_layer); + let translation = current_layer as f32 * + Vector3::new(length * unit_translation.x, width * unit_translation.y, 0.0); - let translation = calculate_translation(length, width, angle); - temp += translation; + // gets into range -1 to +1 + let coord = + 1.0 / 5.0 * + translation.mul_element_wise( + Vector3::new(1.0 / length as f32, 1.0 / width as f32, 0.0), + ); - coord += translation.mul_element_wise(Vector3::new( - (2.0 / (layers as f32 * 2.0 - 1.0)), - (2.0 / (layers as f32 * 2.0 - 1.0)), - 0.0, - )); + // gets into range -0.4 to +0.4 + let coord = 0.4 * coord; + + // gets into range 0.1 to 0.9 + let coord = coord + Vector3::new(0.5, 0.5, 0.0); let height_scalar = return_at(coord.x, coord.y, &fbm); - acc_positions.extend(duplicate(positions.clone(), temp, height_scalar)); - - acc_positions + duplicate(&positions, translation, height_scalar, file.clone()) }) - }) } -fn copy_faces( - faces: Vec>, +fn write_faces( + faces: &[Vec], n_positions: usize, layers: usize, -) -> Vec> { - (0..(2 * layers - 1).pow(2)).fold(Vec::new(), |mut acc_faces, current_value| { - let offset = n_positions * current_value + 1; + file: Arc>>, +) where + T: Write + Send, +{ + (0..(2 * layers - 1).pow(2)).into_par_iter().for_each( + move |current_value| { + let v = Vec::new(); + let c = Cursor::new(v); + let mut b = BufWriter::new(c); + let offset = n_positions * current_value + 1; - acc_faces.extend(faces.iter().map(|current_face| { - current_face - .iter() - .map(|index_tuple| { - IndexTuple( - index_tuple.0 + offset, - index_tuple.1.map(|i| i + offset), - index_tuple.2.map(|j| j + offset), - ) - }) - .collect() - })); - - acc_faces - }) -} - -fn save(filename: &Path, positions: Vec>, faces: Vec>) { - let mut file = File::create(filename).unwrap(); - - for pos in positions { - write!(file, "v {} {} {}\n", pos[0], pos[1], pos[2]).unwrap(); - } - - for face in faces { - write!(file, "f").unwrap(); - for value in face { - write!(file, " {}/", value.0).unwrap(); - if let Some(i) = value.1 { - write!(file, "{}", i).unwrap(); + for current_face in faces { + write!(b, "f").unwrap(); + for value in current_face { + write!(b, " {}/", value.0 + offset).unwrap(); + if let Some(i) = value.1 { + write!(b, "{}", i + offset).unwrap(); + } + write!(b, "/").unwrap(); + if let Some(j) = value.2 { + write!(b, "{}", j + offset).unwrap(); + } + } + write!(b, "\n").unwrap(); } - write!(file, "/").unwrap(); - if let Some(j) = value.2 { - write!(file, "{}", j).unwrap(); - } - } - write!(file, "\n").unwrap(); - } + + file.lock() + .unwrap() + .write(b.into_inner().unwrap().into_inner().as_ref()) + .unwrap(); + }, + ); } fn main() { - let path = Path::new("data/test.obj"); - let maybe_obj: Result> = Obj::load(&path); + let obj: Obj = Obj::load(&path).expect("Failed to load input obj"); - if let Ok(obj) = maybe_obj { - println!("Position: {:?}", obj.position); + let layers = 80; + let spacing = 1.0; - let layers = 10; - let spacing = 1.0; + let (length, width) = find_l_w(&obj); - let (length, width) = find_l_w(&obj); + let input_positions: Vec<_> = obj.position + .iter() + .map(|point| Vector3::new(point[0], point[1], point[2])) + .collect(); - println!("Length: {} Width: {}", length, width); - let input_positions = obj.position - .iter() - .map(|point| Vector3::new(point[0], point[1], point[2])) - .collect(); + let filename = Path::new("target/noice.obj"); + let file_buf_writer = BufWriter::new(File::create(filename).unwrap()); + let file = Arc::new(Mutex::new(file_buf_writer)); - let output_positions = generate_city(input_positions, layers, spacing, length, width); - - println!("Objects: {:?}", obj.objects[0].groups[0].polys[0]); - - let output_faces = copy_faces( - obj.objects[0].groups[0].polys.clone(), - obj.position.len(), - layers as usize, - ); - - save(Path::new("build/noice.obj"), output_positions, output_faces); - } + write_positions( + &input_positions, + layers, + spacing, + length, + width, + file.clone(), + ); + write_faces( + &obj.objects[0].groups[0].polys, + obj.position.len(), + layers as usize, + file, + ); }