Correct global/local coordinate handling; add basic mesh stitching.
This commit is contained in:
parent
f2bea2ebbe
commit
9623bbd3e4
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
264
src/bin/world.rs
264
src/bin/world.rs
@ -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 {
|
for n in 0..cell.neighbors.len() {
|
||||||
Some(anchor) => {
|
let neighbor_id = cell.neighbors[n];
|
||||||
for n in 0..cell.neighbors.len() {
|
let neighbor_anchor = anchors.get(neighbor_id as isize).unwrap();
|
||||||
let neighbor = ico.cells.get(id).unwrap().clone();
|
|
||||||
|
|
||||||
match &neighbor.data {
|
anchor.neighbors[n].distance = anchor.position.angle_between(neighbor_anchor.position) * world_scale;
|
||||||
Some(neighbor_anchor) => {
|
anchor.neighbors[n].position = (anchor.basis * (neighbor_anchor.position - anchor.position)) * world_scale;
|
||||||
anchor.neighbors[n].distance = anchor.position.angle_between(neighbor_anchor.position) * world_scale;
|
anchor.neighbors[n].transform = anchor.ibasis * neighbor_anchor.basis;
|
||||||
anchor.neighbors[n].position = anchor.basis * (neighbor_anchor.position - anchor.position);
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Generate zone meshes.
|
let origin_anchor = anchors.get(origin_id as isize).unwrap().clone();
|
||||||
let tiles = get_neighbors(&ico, 1, terrain_radius);
|
let world_origin = DVec3::NEG_Y * world_scale;
|
||||||
let total_tiles = tiles.len();
|
|
||||||
for (tile_id, depth) in tiles {
|
|
||||||
mesh_count += 1;
|
|
||||||
println!("Generating {} [{} / {}]", tile_id, mesh_count, total_tiles);
|
|
||||||
|
|
||||||
if let Some(zone) = ico.cells.get(tile_id) {
|
// Generate zone meshes.
|
||||||
|
let tiles = get_neighbors(&ico, 1, terrain_radius);
|
||||||
|
let total_tiles = tiles.len();
|
||||||
|
for (tile_id, depth) in &tiles {
|
||||||
|
|
||||||
let mut zone_vertices = [DVec3::ZERO; 3];
|
let mut gen = Generator::new();
|
||||||
|
|
||||||
// Prepare generator with parameters of neighboring tiles.
|
mesh_count += 1;
|
||||||
let nearby = get_neighbors(&ico, tile_id, 3);
|
println!("Generating {} [{} / {}]", tile_id, mesh_count, total_tiles);
|
||||||
for vindex in 0..zone.vertices.len() {
|
|
||||||
let mut influence_count = 0;
|
|
||||||
|
|
||||||
let extent = zone.vertices[vindex];
|
let terrain = if let Some(zone) = ico.cells.get(*tile_id) {
|
||||||
gen.sources[vindex] = terrain::generator::Source::new();
|
// Prepare generator with parameters of neighboring tiles.
|
||||||
zone_vertices[vindex] = (*ico.vertices.get(extent).unwrap()) * world_scale;
|
let nearby = get_neighbors(&ico, *tile_id, 3);
|
||||||
gen.sources[vindex].position = zone_vertices[vindex];
|
for vindex in 0..zone.vertices.len() {
|
||||||
|
let mut influence_count = 0;
|
||||||
|
|
||||||
for n in 0..nearby.len() {
|
let extent = zone.vertices[vindex];
|
||||||
let (nearby_id, _depth) = nearby[n];
|
gen.sources[vindex] = terrain::generator::Source::new();
|
||||||
|
gen.sources[vindex].position = *ico.vertices.get(extent).unwrap();
|
||||||
|
|
||||||
if let Some(tile) = ico.cells.get(nearby_id) {
|
// Average geography of nearby anchors for each tile vertex.
|
||||||
if let Some(tile_anchor) = &tile.data {
|
for n in 0..nearby.len() {
|
||||||
for nvid in tile.vertices {
|
let (nearby_id, _depth) = nearby[n];
|
||||||
if nvid == extent {
|
|
||||||
gen.sources[vindex].elevation += tile_anchor.terrain.elevation;
|
if let Some(tile) = ico.cells.get(nearby_id) {
|
||||||
gen.sources[vindex].octaves.append(&mut tile_anchor.terrain.octaves.to_vec());
|
let tile_anchor = anchors.get(nearby_id as isize).unwrap();
|
||||||
influence_count += 1;
|
for nvid in tile.vertices {
|
||||||
break;
|
if nvid == extent {
|
||||||
}
|
gen.sources[vindex].elevation += tile_anchor.geography.elevation;
|
||||||
}
|
gen.sources[vindex].octaves.append(&mut tile_anchor.geography.octaves.to_vec());
|
||||||
|
influence_count += 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gen.sources[vindex].elevation /= influence_count as f64;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut terrain = Terrain::triangle((zone_vertices[0], zone_vertices[1], zone_vertices[2]), gen.clone());
|
gen.sources[vindex].elevation /= influence_count as f64;
|
||||||
for _ in 0..(4 - depth.min(3)) { terrain.subdivide(); }
|
}
|
||||||
terrain.tessellate();
|
|
||||||
|
|
||||||
for vid in terrain.vertices.list() {
|
let mut terrain = Terrain::triangle((gen.sources[0].position, gen.sources[1].position, gen.sources[2].position), gen);
|
||||||
if let Some(vertex) = terrain.vertices.get_mut(vid) {
|
for _ in 0..(4 - (*depth).min(3)) { terrain.subdivide(); }
|
||||||
let sv = vertex.position.normalize() * (world_scale + vertex.height);
|
terrain.tessellate();
|
||||||
vertex.position = (origin_anchor.basis * sv) + world_origin;
|
|
||||||
vertex.height = 0.;
|
terrain
|
||||||
|
} else { break; };
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
terrain_mesh.merge(&terrain.to_mesh(), Vec3::ZERO);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
terrain::obj::save("icosphere.obj", &ico.to_mesh(), 50.).ok();
|
// Write anchors to mesh.
|
||||||
terrain::obj::save("test.obj", &terrain_mesh, 0.1).ok();
|
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.;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
terrain_mesh.merge(&anchor.terrain.to_mesh(), Vec3::ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
//terrain::obj::save("icosphere.obj", &ico.to_mesh(), 20.).ok();
|
||||||
|
terrain::obj::save("test.obj", &terrain_mesh, 0.01).ok();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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}]",
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user