Compare commits
1 commit
master
...
lower-ram-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
216d7d24c6 |
3 changed files with 137 additions and 138 deletions
|
@ -10,3 +10,4 @@ license = "MIT"
|
||||||
obj = "0.8"
|
obj = "0.8"
|
||||||
noise = "0.4"
|
noise = "0.4"
|
||||||
cgmath = "0.15.0"
|
cgmath = "0.15.0"
|
||||||
|
rayon = "0.9.0"
|
||||||
|
|
|
@ -12,14 +12,6 @@ v 1 0 3
|
||||||
v 1 1 3
|
v 1 1 3
|
||||||
v 1 1 0
|
v 1 1 0
|
||||||
v 1 0 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
|
# 0 UV coordinates
|
||||||
|
|
||||||
|
@ -46,16 +38,4 @@ f 1//5 7//5 8//5
|
||||||
f 7//5 1//5 3//5
|
f 7//5 1//5 3//5
|
||||||
f 1//6 5//6 4//6
|
f 1//6 5//6 4//6
|
||||||
f 5//6 1//6 8//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
|
|
||||||
|
|
||||||
|
|
254
src/main.rs
254
src/main.rs
|
@ -4,19 +4,20 @@
|
||||||
extern crate obj;
|
extern crate obj;
|
||||||
extern crate noise;
|
extern crate noise;
|
||||||
extern crate cgmath;
|
extern crate cgmath;
|
||||||
|
extern crate rayon;
|
||||||
|
|
||||||
use std::io::Result;
|
use std::sync::{Arc, Mutex};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::f32::consts::PI;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::{BufWriter, Cursor, Write};
|
||||||
use obj::{Obj, SimplePolygon, IndexTuple};
|
use obj::{Obj, SimplePolygon, IndexTuple};
|
||||||
use noise::Fbm;
|
use noise::Fbm;
|
||||||
//use noise::Seedable;
|
//use noise::Seedable;
|
||||||
//use noise::MultiFractal;
|
use noise::MultiFractal;
|
||||||
use noise::NoiseModule;
|
use noise::NoiseModule;
|
||||||
use cgmath::Vector3;
|
use cgmath::Vector3;
|
||||||
use cgmath::ElementWise;
|
use cgmath::ElementWise;
|
||||||
|
use rayon::prelude::*;
|
||||||
|
|
||||||
// A function called test that takes in 1 32-bit integer
|
// A function called test that takes in 1 32-bit integer
|
||||||
// and returns a 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>) -> f32 {
|
fn return_at(x: f32, y: f32, fbmnoise: &Fbm<f32>) -> f32 {
|
||||||
let n = 20.0 * fbmnoise.get([x, y]);
|
let zero_to_one_noise = (1.0 + fbmnoise.get([x, y])) * 0.5;
|
||||||
let n = n - n.floor();
|
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 (zero_to_one_noise * 0.90) + (m * 0.10);
|
||||||
|
|
||||||
return (m * 0.15) + (n * 0.85);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_l_w(obj: &Obj<SimplePolygon>) -> (f32, f32) {
|
fn find_l_w(obj: &Obj<SimplePolygon>) -> (f32, f32) {
|
||||||
|
@ -85,151 +85,169 @@ fn find_l_w(obj: &Obj<SimplePolygon>) -> (f32, f32) {
|
||||||
* to the initial input obj's position.
|
* to the initial input obj's position.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn calculate_angle(current_duplicate: i32, current_layer: i32) -> f32 {
|
fn duplicate<T>(
|
||||||
(current_duplicate / (2 * current_layer)) as f32 * (0.5 * PI)
|
positions: &[Vector3<f32>],
|
||||||
}
|
|
||||||
|
|
||||||
fn calculate_translation(length: f32, width: f32, angle: f32) -> Vector3<f32> {
|
|
||||||
Vector3::new(length * angle.cos(), width * angle.sin(), 0.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn duplicate(
|
|
||||||
positions: Vec<Vector3<f32>>,
|
|
||||||
translation: Vector3<f32>,
|
translation: Vector3<f32>,
|
||||||
height_scalar: f32,
|
height_scalar: f32,
|
||||||
) -> Vec<Vector3<f32>> {
|
file: Arc<Mutex<BufWriter<T>>>,
|
||||||
positions
|
) where
|
||||||
.iter()
|
T: Write,
|
||||||
.map(|point| {
|
{
|
||||||
Vector3::new(
|
let v = Vec::new();
|
||||||
point.x + translation.x,
|
let c = Cursor::new(v);
|
||||||
point.y + translation.y,
|
let mut b = BufWriter::new(c);
|
||||||
point.z * height_scalar,
|
|
||||||
)
|
for point in positions {
|
||||||
})
|
write!(
|
||||||
.collect()
|
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(
|
fn write_positions<T>(
|
||||||
positions: Vec<Vector3<f32>>,
|
positions: &[Vector3<f32>],
|
||||||
layers: i32,
|
layers: i32,
|
||||||
spacing: f32,
|
spacing: f32,
|
||||||
length: f32,
|
length: f32,
|
||||||
width: f32,
|
width: f32,
|
||||||
) -> Vec<Vector3<f32>> {
|
file: Arc<Mutex<BufWriter<T>>>,
|
||||||
|
) where
|
||||||
|
T: Write + Send,
|
||||||
|
{
|
||||||
let length = length + spacing;
|
let length = length + spacing;
|
||||||
let width = width + spacing;
|
let width = width + spacing;
|
||||||
|
|
||||||
let mut temp = Vector3::new(0.0, 0.0, 0.0);
|
let fbm: Fbm<f32> = 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<f32> = 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| {
|
let current_ratio = current_duplicate as f32 / (current_layer as f32 * 8.0);
|
||||||
temp.x = -length * (current_layer as f32);
|
|
||||||
temp.y = -width * (current_layer as f32);
|
|
||||||
|
|
||||||
(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);
|
// gets into range -1 to +1
|
||||||
temp += translation;
|
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(
|
// gets into range -0.4 to +0.4
|
||||||
(2.0 / (layers as f32 * 2.0 - 1.0)),
|
let coord = 0.4 * coord;
|
||||||
(2.0 / (layers as f32 * 2.0 - 1.0)),
|
|
||||||
0.0,
|
// 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);
|
let height_scalar = return_at(coord.x, coord.y, &fbm);
|
||||||
|
|
||||||
acc_positions.extend(duplicate(positions.clone(), temp, height_scalar));
|
duplicate(&positions, translation, height_scalar, file.clone())
|
||||||
|
|
||||||
acc_positions
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_faces(
|
fn write_faces<T>(
|
||||||
faces: Vec<Vec<IndexTuple>>,
|
faces: &[Vec<IndexTuple>],
|
||||||
n_positions: usize,
|
n_positions: usize,
|
||||||
layers: usize,
|
layers: usize,
|
||||||
) -> Vec<Vec<IndexTuple>> {
|
file: Arc<Mutex<BufWriter<T>>>,
|
||||||
(0..(2 * layers - 1).pow(2)).fold(Vec::new(), |mut acc_faces, current_value| {
|
) where
|
||||||
let offset = n_positions * current_value + 1;
|
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| {
|
for current_face in faces {
|
||||||
current_face
|
write!(b, "f").unwrap();
|
||||||
.iter()
|
for value in current_face {
|
||||||
.map(|index_tuple| {
|
write!(b, " {}/", value.0 + offset).unwrap();
|
||||||
IndexTuple(
|
if let Some(i) = value.1 {
|
||||||
index_tuple.0 + offset,
|
write!(b, "{}", i + offset).unwrap();
|
||||||
index_tuple.1.map(|i| i + offset),
|
}
|
||||||
index_tuple.2.map(|j| j + offset),
|
write!(b, "/").unwrap();
|
||||||
)
|
if let Some(j) = value.2 {
|
||||||
})
|
write!(b, "{}", j + offset).unwrap();
|
||||||
.collect()
|
}
|
||||||
}));
|
}
|
||||||
|
write!(b, "\n").unwrap();
|
||||||
acc_faces
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save(filename: &Path, positions: Vec<Vector3<f32>>, faces: Vec<Vec<IndexTuple>>) {
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
write!(file, "/").unwrap();
|
|
||||||
if let Some(j) = value.2 {
|
file.lock()
|
||||||
write!(file, "{}", j).unwrap();
|
.unwrap()
|
||||||
}
|
.write(b.into_inner().unwrap().into_inner().as_ref())
|
||||||
}
|
.unwrap();
|
||||||
write!(file, "\n").unwrap();
|
},
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
let path = Path::new("data/test.obj");
|
let path = Path::new("data/test.obj");
|
||||||
let maybe_obj: Result<Obj<SimplePolygon>> = Obj::load(&path);
|
let obj: Obj<SimplePolygon> = Obj::load(&path).expect("Failed to load input obj");
|
||||||
|
|
||||||
if let Ok(obj) = maybe_obj {
|
let layers = 80;
|
||||||
println!("Position: {:?}", obj.position);
|
let spacing = 1.0;
|
||||||
|
|
||||||
let layers = 10;
|
let (length, width) = find_l_w(&obj);
|
||||||
let spacing = 1.0;
|
|
||||||
|
|
||||||
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
|
let filename = Path::new("target/noice.obj");
|
||||||
.iter()
|
let file_buf_writer = BufWriter::new(File::create(filename).unwrap());
|
||||||
.map(|point| Vector3::new(point[0], point[1], point[2]))
|
let file = Arc::new(Mutex::new(file_buf_writer));
|
||||||
.collect();
|
|
||||||
|
|
||||||
let output_positions = generate_city(input_positions, layers, spacing, length, width);
|
write_positions(
|
||||||
|
&input_positions,
|
||||||
println!("Objects: {:?}", obj.objects[0].groups[0].polys[0]);
|
layers,
|
||||||
|
spacing,
|
||||||
let output_faces = copy_faces(
|
length,
|
||||||
obj.objects[0].groups[0].polys.clone(),
|
width,
|
||||||
obj.position.len(),
|
file.clone(),
|
||||||
layers as usize,
|
);
|
||||||
);
|
write_faces(
|
||||||
|
&obj.objects[0].groups[0].polys,
|
||||||
save(Path::new("build/noice.obj"), output_positions, output_faces);
|
obj.position.len(),
|
||||||
}
|
layers as usize,
|
||||||
|
file,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue