Correct global/local coordinate handling; add basic mesh stitching.

This commit is contained in:
yukirij 2024-06-15 12:24:06 -07:00
parent f2bea2ebbe
commit 9623bbd3e4
5 changed files with 222 additions and 143 deletions

View File

@ -1,4 +1,8 @@
use glam::{DMat3, DVec3}; use glam::{DMat3, DVec3};
use crate::{
terrain::Terrain,
generator::Generator,
};
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Neighbor { pub struct Neighbor {
@ -19,25 +23,25 @@ impl Neighbor {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Octave { pub struct Octave {
pub scale:f64, pub frequency:f64,
pub weight:f64, pub amplitude:f64,
} }
impl Octave { impl Octave {
pub fn new() -> Self pub fn new() -> Self
{ {
Self { Self {
scale:1., frequency:1.,
weight:1., amplitude:1.,
} }
} }
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Terrain { pub struct Geography {
pub elevation:f64, pub elevation:f64,
pub octaves:[Octave; 4], pub octaves:[Octave; 4],
} }
impl Terrain { impl Geography {
pub fn new() -> Self pub fn new() -> Self
{ {
Self { Self {
@ -47,7 +51,7 @@ impl Terrain {
} }
} }
#[derive(Clone, Copy)] #[derive(Clone)]
pub struct Anchor { pub struct Anchor {
pub position:DVec3, pub position:DVec3,
pub centroid:DVec3, pub centroid:DVec3,
@ -56,6 +60,8 @@ pub struct Anchor {
pub neighbors:[Neighbor; 3], pub neighbors:[Neighbor; 3],
pub terrain:Terrain, pub terrain:Terrain,
pub geography:Geography,
} }
impl Anchor { impl Anchor {
pub fn new() -> Self pub fn new() -> Self
@ -67,7 +73,8 @@ impl Anchor {
ibasis:DMat3::IDENTITY, ibasis:DMat3::IDENTITY,
neighbors:[Neighbor::new(); 3], neighbors:[Neighbor::new(); 3],
terrain:Terrain::new(), terrain:Terrain::new(Generator::new()),
geography:Geography::new(),
} }
} }
} }

View File

@ -1,4 +1,5 @@
use glam::{DMat3, DVec3, Vec3}; use glam::{DMat3, DVec3, Vec3};
use noise::NoiseFn;
use rand::prelude::*; use rand::prelude::*;
use sparse::Sparse; use sparse::Sparse;
use terrain::{ use terrain::{
@ -6,6 +7,10 @@ use terrain::{
}; };
fn get_subdivisions(radius_km:f64) -> usize fn get_subdivisions(radius_km:f64) -> usize
// Determines the number of subdivisions required for an icosphere,
// given a world radius, such that the distance between triangle
// centers is approximately 1-2 kilometers (assuming units of meters).
//
{ {
let edge_length = 4. * radius_km / (10. + (2. * f64::sqrt(5.))).sqrt(); let edge_length = 4. * radius_km / (10. + (2. * f64::sqrt(5.))).sqrt();
let cell_radius = edge_length / f64::sqrt(3.); let cell_radius = edge_length / f64::sqrt(3.);
@ -16,7 +21,10 @@ fn get_subdivisions(radius_km:f64) -> usize
count count
} }
fn get_neighbors(ico:&Icosphere<Anchor>, origin:usize, distance:usize) -> Vec<(usize, usize)> fn get_neighbors(ico:&Icosphere, origin:usize, distance:usize) -> Vec<(usize, usize)>
// (Id, Distance)
// Gets a unique list of icosphere cells up to a specified distance from a origin cell.
//
{ {
let mut search = Vec::<(usize, usize)>::new(); let mut search = Vec::<(usize, usize)>::new();
let mut found = Sparse::<()>::new(); let mut found = Sparse::<()>::new();
@ -44,21 +52,33 @@ fn get_neighbors(ico:&Icosphere<Anchor>, origin:usize, distance:usize) -> Vec<(u
} }
fn main() { fn main() {
let radius_km = 1.; let radius_km = 100.;
let terrain_radius = 1; let terrain_radius = 3;
let mut ico = Icosphere::<Anchor>::new(); let mut ico = Icosphere::new();
for _ in 0..get_subdivisions(radius_km) { ico.subdivide(); } let mut anchors = Sparse::<Anchor>::new();
let subdivisions = get_subdivisions(radius_km);
for _ in 0..subdivisions { ico.subdivide(); }
println!("Subdivisions: {}", subdivisions);
let world_scale = radius_km * 1000.; let world_scale = radius_km * 1000.;
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let perlin = noise::Perlin::new(12);
// Generate an anchor for each cell in the isosphere.
//
let cells_list = ico.cells.list();
let mut anchor_counter = 0;
let anchor_counter_total = cells_list.len();
for id in cells_list {
if anchor_counter % 10000 == 0 {
println!("Generating anchor block #{}/{}", anchor_counter, anchor_counter_total);
} anchor_counter += 1;
// Set anchor properties. let cell = ico.cells.get_mut(id).unwrap().clone();
for id in ico.cells.list() {
let mut cell = ico.cells.get_mut(id).unwrap().clone();
// Calculate cell space and transformations.
let vertices = [ let vertices = [
*ico.vertices.get(cell.vertices[0]).unwrap(), *ico.vertices.get(cell.vertices[0]).unwrap(),
*ico.vertices.get(cell.vertices[1]).unwrap(), *ico.vertices.get(cell.vertices[1]).unwrap(),
@ -74,27 +94,30 @@ fn main() {
let basis_inverse = DMat3::from_cols(basis_i, basis_j, basis_k); let basis_inverse = DMat3::from_cols(basis_i, basis_j, basis_k);
let basis = basis_inverse.inverse(); let basis = basis_inverse.inverse();
cell.data = Some({ // Define anchor properties.
anchors.set(id as isize, {
let mut anchor = Anchor::new(); let mut anchor = Anchor::new();
anchor.terrain.elevation = (rng.gen::<f64>() * 50.) - 10.; anchor.centroid = centroid;
anchor.position = centroid.normalize();
let mut scale = (rng.gen::<f64>() / 32.) + (1. / 256.);
let mut weight = (rng.gen::<f64>() * 2.) + 0.25;
let octaves = (rng.gen::<f64>() * anchor.terrain.octaves.len() as f64) as usize + 1;
for oct in 0..octaves {
anchor.terrain.octaves[oct].scale = scale;
anchor.terrain.octaves[oct].weight = weight;
scale *= (rng.gen::<f64>() / 2.) + (1. / 32.);
weight *= (rng.gen::<f64>() * 16.) + 1.;
}
anchor.position = centroid.normalize() * world_scale;
anchor.centroid = centroid * world_scale;
anchor.basis = basis; anchor.basis = basis;
anchor.ibasis = basis_inverse; anchor.ibasis = basis_inverse;
let mut elevation_frequency = 10000000. / 1.;// / world_scale;
for _ in 0..4 {
anchor.geography.elevation += (100. * rng.gen::<f64>() / elevation_frequency) * perlin.get([elevation_frequency * anchor.position.x, elevation_frequency * anchor.position.y, elevation_frequency * anchor.position.z]);
elevation_frequency *= 25.;
}
let mut frequency = 32.;
let _octaves = (rng.gen::<f64>() * anchor.geography.octaves.len() as f64) as usize + 1;
for oct in 0..1 {
anchor.geography.octaves[oct].frequency = frequency;
anchor.geography.octaves[oct].amplitude = 100.; //rng.gen::<f64>();
frequency *= 1. / 4.;
}
anchor anchor
}); });
@ -104,97 +127,164 @@ fn main() {
// Set anchor neighbor properties. // Set anchor neighbor properties.
for id in ico.cells.list() { for id in ico.cells.list() {
let mut cell = ico.cells.get(id).unwrap().clone(); let cell = ico.cells.get(id).unwrap();
let mut anchor = anchors.get(id as isize).unwrap().clone();
match &mut cell.data {
Some(anchor) => {
for n in 0..cell.neighbors.len() { for n in 0..cell.neighbors.len() {
let neighbor = ico.cells.get(id).unwrap().clone(); let neighbor_id = cell.neighbors[n];
let neighbor_anchor = anchors.get(neighbor_id as isize).unwrap();
match &neighbor.data {
Some(neighbor_anchor) => {
anchor.neighbors[n].distance = anchor.position.angle_between(neighbor_anchor.position) * world_scale; anchor.neighbors[n].distance = anchor.position.angle_between(neighbor_anchor.position) * world_scale;
anchor.neighbors[n].position = anchor.basis * (neighbor_anchor.position - anchor.position); anchor.neighbors[n].position = (anchor.basis * (neighbor_anchor.position - anchor.position)) * world_scale;
anchor.neighbors[n].transform = anchor.ibasis * neighbor_anchor.basis; anchor.neighbors[n].transform = anchor.ibasis * neighbor_anchor.basis;
} }
None => { }
}
}
}
None => { }
}
ico.cells.update(id, cell).ok(); anchors.set(id as isize, anchor);
} }
// Generate terrain. // Generate terrain.
let mut gen = Generator::new();
let mut terrain_mesh: Mesh = Mesh::new(); let mut terrain_mesh: Mesh = Mesh::new();
let mut mesh_count = 0; let mut mesh_count = 0;
if let Some(origin_cell) = ico.cells.get(1) { let origin_id = 1;
let origin_anchor = &origin_cell.data.unwrap();
let world_origin = -(origin_anchor.basis * origin_anchor.position); let origin_anchor = anchors.get(origin_id as isize).unwrap().clone();
let world_origin = DVec3::NEG_Y * world_scale;
// Generate zone meshes. // Generate zone meshes.
let tiles = get_neighbors(&ico, 1, terrain_radius); let tiles = get_neighbors(&ico, 1, terrain_radius);
let total_tiles = tiles.len(); let total_tiles = tiles.len();
for (tile_id, depth) in tiles { for (tile_id, depth) in &tiles {
let mut gen = Generator::new();
mesh_count += 1; mesh_count += 1;
println!("Generating {} [{} / {}]", tile_id, mesh_count, total_tiles); println!("Generating {} [{} / {}]", tile_id, mesh_count, total_tiles);
if let Some(zone) = ico.cells.get(tile_id) { let terrain = if let Some(zone) = ico.cells.get(*tile_id) {
let mut zone_vertices = [DVec3::ZERO; 3];
// Prepare generator with parameters of neighboring tiles. // Prepare generator with parameters of neighboring tiles.
let nearby = get_neighbors(&ico, tile_id, 3); let nearby = get_neighbors(&ico, *tile_id, 3);
for vindex in 0..zone.vertices.len() { for vindex in 0..zone.vertices.len() {
let mut influence_count = 0; let mut influence_count = 0;
let extent = zone.vertices[vindex]; let extent = zone.vertices[vindex];
gen.sources[vindex] = terrain::generator::Source::new(); gen.sources[vindex] = terrain::generator::Source::new();
zone_vertices[vindex] = (*ico.vertices.get(extent).unwrap()) * world_scale; gen.sources[vindex].position = *ico.vertices.get(extent).unwrap();
gen.sources[vindex].position = zone_vertices[vindex];
// Average geography of nearby anchors for each tile vertex.
for n in 0..nearby.len() { for n in 0..nearby.len() {
let (nearby_id, _depth) = nearby[n]; let (nearby_id, _depth) = nearby[n];
if let Some(tile) = ico.cells.get(nearby_id) { if let Some(tile) = ico.cells.get(nearby_id) {
if let Some(tile_anchor) = &tile.data { let tile_anchor = anchors.get(nearby_id as isize).unwrap();
for nvid in tile.vertices { for nvid in tile.vertices {
if nvid == extent { if nvid == extent {
gen.sources[vindex].elevation += tile_anchor.terrain.elevation; gen.sources[vindex].elevation += tile_anchor.geography.elevation;
gen.sources[vindex].octaves.append(&mut tile_anchor.terrain.octaves.to_vec()); gen.sources[vindex].octaves.append(&mut tile_anchor.geography.octaves.to_vec());
influence_count += 1; influence_count += 1;
break; break;
} }
} }
} }
} }
}
gen.sources[vindex].elevation /= influence_count as f64; gen.sources[vindex].elevation /= influence_count as f64;
} }
let mut terrain = Terrain::triangle((zone_vertices[0], zone_vertices[1], zone_vertices[2]), gen.clone()); let mut terrain = Terrain::triangle((gen.sources[0].position, gen.sources[1].position, gen.sources[2].position), gen);
for _ in 0..(4 - depth.min(3)) { terrain.subdivide(); } for _ in 0..(4 - (*depth).min(3)) { terrain.subdivide(); }
terrain.tessellate(); terrain.tessellate();
for vid in terrain.vertices.list() { terrain
if let Some(vertex) = terrain.vertices.get_mut(vid) { } else { break; };
let sv = vertex.position.normalize() * (world_scale + vertex.height);
vertex.position = (origin_anchor.basis * sv) + world_origin; anchors.get_mut(*tile_id as isize).unwrap().terrain = terrain;
}
// Modify anchor terrain to match neighbor edge subdivisons.
let mut apply_count = 1;
while apply_count > 0 {
apply_count = 0;
let mut tile_count = 0;
for (tile_id, _depth) in &tiles {
let cell = ico.cells.get(*tile_id).unwrap().clone();
let anchor = anchors.get(*tile_id as isize).unwrap().clone();
tile_count += 1;
println!("Stitching {} [{} / {}]", *tile_id, tile_count, tiles.len());
for side_id in 0..cell.neighbors.len() {
let neighbor_id = cell.neighbors[side_id];
let neighbor_cell = ico.cells.get(neighbor_id).unwrap();
let neighbor_anchor = anchors.get_mut(neighbor_id as isize).unwrap();
// Determine rotation of neighboring tile.
let side_vertices = [(side_id + 1) % 3, (side_id + 2) % 3];
let mut neighbor_vertex_side = [0, 0];
for s in 0..side_vertices.len() {
let vid = cell.vertices[side_vertices[s]];
for ns in 0..neighbor_cell.vertices.len() {
if neighbor_cell.vertices[ns] == vid {
neighbor_vertex_side[s] = ns;
break;
}
}
}
let neighbor_side = 3 - (neighbor_vertex_side[0] + neighbor_vertex_side[1]);
// Get maximum depth on edge of current cell.
let mut max_depth = 0;
for cell_id in anchor.terrain.cells.list() {
let tcell = anchor.terrain.cells.get(cell_id).unwrap();
let side_counts = (tcell.neighbors[0] == 0) as usize
+ (tcell.neighbors[1] == 0) as usize
+ (tcell.neighbors[2] == 0) as usize;
if side_counts == 1 && tcell.neighbors[side_id] == 0 {
max_depth = max_depth.max(tcell.depth);
}
}
// Subdivide neighbor edges.
let mut subdivide_count = 1;
while subdivide_count > 0 {
subdivide_count = 0;
let cell_list = neighbor_anchor.terrain.cells.list();
for cell_id in cell_list {
let tcell = neighbor_anchor.terrain.cells.get(cell_id).unwrap().clone();
if tcell.neighbors[neighbor_side] == 0 {
if tcell.depth < max_depth {
neighbor_anchor.terrain.subdivide_cell(cell_id);
subdivide_count += 1;
}
}
}
}
}
}
}
// Write anchors to mesh.
for (tile_id, _depth) in &tiles {
let anchor = anchors.get_mut(*tile_id as isize).unwrap();
for vid in anchor.terrain.vertices.list() {
if let Some(vertex) = anchor.terrain.vertices.get_mut(vid) {
let norm = vertex.position.normalize() * (world_scale + vertex.height);
vertex.position = (origin_anchor.basis * norm) + world_origin;
vertex.height = 0.; vertex.height = 0.;
} }
} }
terrain_mesh.merge(&terrain.to_mesh(), Vec3::ZERO);
} terrain_mesh.merge(&anchor.terrain.to_mesh(), Vec3::ZERO);
}
} }
terrain::obj::save("icosphere.obj", &ico.to_mesh(), 50.).ok(); //terrain::obj::save("icosphere.obj", &ico.to_mesh(), 20.).ok();
terrain::obj::save("test.obj", &terrain_mesh, 0.1).ok(); terrain::obj::save("test.obj", &terrain_mesh, 0.01).ok();
} }

View File

@ -42,7 +42,7 @@ impl Generator {
heights[src] = self.sources[src].elevation; heights[src] = self.sources[src].elevation;
for octave in &self.sources[src].octaves { for octave in &self.sources[src].octaves {
heights[src] += octave.weight * self.generator.get([octave.scale * position.x, octave.scale * position.y, octave.scale * position.z]); heights[src] += 10. * octave.amplitude * self.generator.get([octave.frequency * position.x, octave.frequency * position.y, octave.frequency * position.z]);
} }
heights[src] /= self.sources[src].octaves.len().max(1) as f64; heights[src] /= self.sources[src].octaves.len().max(1) as f64;
} }

View File

@ -12,17 +12,17 @@ const FLIPPED :u32 = 1 << 31;
const NFLIPPED :u32 = !FLIPPED; const NFLIPPED :u32 = !FLIPPED;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Cell<T> where T: Clone { pub struct Cell {
pub data:Option<T>, pub data:usize,
depth:u32, depth:u32,
pub neighbors:[usize;3], pub neighbors:[usize;3],
pub vertices:[usize;3], pub vertices:[usize;3],
} }
impl<T: Clone> Cell<T> { impl Cell {
pub fn new() -> Self pub fn new() -> Self
{ {
Self { Self {
data:None, data:0,
depth:0, depth:0,
neighbors:[0; 3], neighbors:[0; 3],
vertices:[0; 3], vertices:[0; 3],
@ -30,16 +30,16 @@ impl<T: Clone> Cell<T> {
} }
} }
pub struct Icosphere<T> where T: Clone { pub struct Icosphere {
pub vertices:Pool<DVec3>, pub vertices:Pool<DVec3>,
pub cells:Pool<Cell<T>>, pub cells:Pool<Cell>,
} }
impl<T: Clone> Icosphere<T> { impl Icosphere {
pub fn new() -> Self pub fn new() -> Self
{ {
Self { Self {
vertices:Pool::<DVec3>::new(), vertices:Pool::<DVec3>::new(),
cells:Pool::<Cell<T>>::new(), cells:Pool::<Cell>::new(),
}.init() }.init()
} }
@ -72,7 +72,7 @@ impl<T: Clone> Icosphere<T> {
// Top row cells // Top row cells
for i in 0..5 { for i in 0..5 {
self.cells.add({ self.cells.add({
let mut cell = Cell::<T>::new(); let mut cell = Cell::new();
cell.vertices = [ cell.vertices = [
2 + ((i + 1) % 5), 2 + ((i + 1) % 5),
@ -297,7 +297,7 @@ impl<T: Clone> Icosphere<T> {
for i in 0..children.len() { for i in 0..children.len() {
self.print_cell("SUBDIV", child_ids[i], &children[i]); self.print_cell("SUBDIV", child_ids[i], &children[i]);
let mut child = Cell::<T>::new(); let mut child = Cell::new();
std::mem::swap(&mut children[i], &mut child); std::mem::swap(&mut children[i], &mut child);
self.cells.update(child_ids[i], child).ok(); self.cells.update(child_ids[i], child).ok();
} }
@ -308,7 +308,7 @@ impl<T: Clone> Icosphere<T> {
self.vertices.add(vertex.normalize()) self.vertices.add(vertex.normalize())
} }
fn print_cell(&self, text:&str, id:usize, cell:&Cell<T>) fn print_cell(&self, text:&str, id:usize, cell:&Cell)
{ {
if DEBUG_PRINTS { if DEBUG_PRINTS {
println!("{:8} {:3} ( {}, {:2} ) [{:3} {:3} {:3}] [{:3} {:3} {:3}]", println!("{:8} {:3} ( {}, {:2} ) [{:3} {:3} {:3}] [{:3} {:3} {:3}]",

View File

@ -11,11 +11,10 @@ const DEBUG_PRINTS :bool = false;
const DEGREES :f64 = PI / 180.; const DEGREES :f64 = PI / 180.;
const DELTA_THRESHOLD :f64 = (1. / 24.) * DEGREES; const DELTA_THRESHOLD :f64 = (1. / 48.) * DEGREES;
const MAX_SUBDIVISIONS :u16 = 14; const MAX_SUBDIVISIONS :u16 = 4;
const MAX_DEPTH :u16 = 2 * MAX_SUBDIVISIONS; const MAX_DEPTH :u16 = 2 * MAX_SUBDIVISIONS;
const RADIAL_FALLOFF :f64 = 0.7; const RADIAL_FALLOFF :f64 = 2.;
const RADIAL_FALLOFF_INV :f64 = 1. / RADIAL_FALLOFF;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum Action { enum Action {
@ -68,23 +67,22 @@ impl Cell {
} }
} }
#[derive(Clone)]
pub struct Terrain { pub struct Terrain {
pub vertices:Pool<Vertex>, pub vertices:Pool<Vertex>,
pub cells:Pool<Cell>, pub cells:Pool<Cell>,
pub extent:[DVec3; 3], pub extent:[DVec3; 3],
pub normal:DVec3, pub normal:DVec3,
pub scale:f64,
generator:Generator, generator:Generator,
} }
impl Terrain { impl Terrain {
fn new(generator:Generator) -> Self pub fn new(generator:Generator) -> Self
{ {
Self { Self {
vertices:Pool::<Vertex>::new(), vertices:Pool::<Vertex>::new(),
cells:Pool::<Cell>::new(), cells:Pool::<Cell>::new(),
extent:[DVec3::ZERO; 3], extent:[DVec3::ZERO; 3],
normal:DVec3::Y, normal:DVec3::Y,
scale:1.,
generator:generator, generator:generator,
} }
} }
@ -96,38 +94,22 @@ impl Terrain {
let cross = (c - a).cross(b - a); let cross = (c - a).cross(b - a);
grid.normal = cross.normalize(); grid.normal = cross.normalize();
grid.scale = ((b - a).length() + (c - a).length()) / (1000. * f64::sqrt(3.));
grid.extent = [a, b, c]; grid.extent = [a, b, c];
let vertices = [ grid.add_vertex(a);
grid.add_vertex(a), grid.add_vertex(b);
grid.add_vertex(b), grid.add_vertex(c);
grid.add_vertex(c),
];
grid.cells.add({ grid.cells.add({
let mut cell = Cell::new(); let mut cell = Cell::new();
cell.vertices = [1, 2, 3];
cell.vertices = vertices;
cell cell
}); });
grid grid
} }
fn init_hexagon(&mut self, _radius:usize)
{
let triangle_edge = 0.5;
let triangle_vertex = 2. * triangle_edge;
let triangle_halfside = f64::sqrt(3.) * triangle_edge;
let _triangle_side = 2. * triangle_halfside;
let _triangle_cross = triangle_edge + triangle_vertex;
// Implementation Here
}
pub fn subdivide(&mut self) pub fn subdivide(&mut self)
{ {
for id in self.cells.list() { for id in self.cells.list() {
@ -135,6 +117,11 @@ impl Terrain {
} }
} }
pub fn subdivide_cell(&mut self, id:usize)
{
self.node_update(&vec![Action::Subdivide(id, 0)]);
}
pub fn tessellate(&mut self) pub fn tessellate(&mut self)
{ {
let mut data = self.cells.list(); let mut data = self.cells.list();
@ -157,7 +144,6 @@ impl Terrain {
data_len = new_data.len(); data_len = new_data.len();
} }
if passes % 10 == 0 { if passes % 10 == 0 {
println!("Pass {}", passes); println!("Pass {}", passes);
} }
@ -216,11 +202,11 @@ impl Terrain {
} }
} }
neighbor_normal /= count; neighbor_normal /= count;
let centroid = (vp[0] + vp[1] + vp[2]) / 3.;
let min_dist = vp[0].length().min(vp[1].length()).min(vp[2].length()).max(1.); let min_dist = centroid.length_squared().max(1.);
let delta = normal.angle_between(neighbor_normal); let delta = normal.angle_between(neighbor_normal);
let max_depth = MAX_DEPTH - (f64::log2(min_dist) * RADIAL_FALLOFF_INV).min((MAX_DEPTH - 2) as f64) as u16; let max_depth = MAX_DEPTH - 2 * (f64::log2(min_dist) / f64::log2(RADIAL_FALLOFF)).min((MAX_SUBDIVISIONS - 1) as f64) as u16;
let threshold = DELTA_THRESHOLD * f64::log2(cell.depth as f64 + 16.) * 4.; let threshold = DELTA_THRESHOLD * f64::log2(cell.depth as f64 + 16.) * 4.;
if delta > threshold && cell.depth < max_depth { if delta > threshold && cell.depth < max_depth {
self.node_update(&vec![Action::Subdivide(id, 0)]); self.node_update(&vec![Action::Subdivide(id, 0)]);
@ -339,10 +325,6 @@ impl Terrain {
} }
twin = Some(self.cells.get(twin_id).unwrap().clone()); twin = Some(self.cells.get(twin_id).unwrap().clone());
//match &twin {
// Some(twin) => { self.print_cell("TWIN", twin_id, twin); }
// None => { }
//}
} }
// Get outer neighbors and vertices. // Get outer neighbors and vertices.
@ -647,7 +629,7 @@ impl Terrain {
fn add_vertex(&mut self, vertex:DVec3) -> usize fn add_vertex(&mut self, vertex:DVec3) -> usize
{ {
self.vertices.add(Vertex::with(vertex, self.scale * self.generator.generate(vertex))) self.vertices.add(Vertex::with(vertex, self.generator.generate(vertex)))
} }
fn print_cell(&self, text:&str, id:usize, cell:&Cell) fn print_cell(&self, text:&str, id:usize, cell:&Cell)