Initialize repository.
This commit is contained in:
commit
1f3b920570
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
|
*.obj
|
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "terrain"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
glam = "0.27.0"
|
||||||
|
noise = "0.9.0"
|
||||||
|
|
||||||
|
pool = { git = "https://git.tsukiyo.org/Utility/pool" }
|
||||||
|
sparse = { git = "https://git.tsukiyo.org/Utility/sparse" }
|
77
src/bin/icosphere.rs
Normal file
77
src/bin/icosphere.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use glam::{DVec3, IVec3};
|
||||||
|
|
||||||
|
struct Icosphere {
|
||||||
|
vertices:Vec<DVec3>,
|
||||||
|
faces:Vec<IVec3>,
|
||||||
|
}
|
||||||
|
impl Icosphere {
|
||||||
|
pub fn new(depth:usize) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
vertices:Vec::<DVec3>::with_capacity(12),
|
||||||
|
faces:Vec::<IVec3>::with_capacity(20),
|
||||||
|
}.init(depth)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(mut self, depth:usize) -> Self
|
||||||
|
{
|
||||||
|
let phi = (1. + f64::sqrt(5.)) / 2.;
|
||||||
|
|
||||||
|
// Generate initial structure
|
||||||
|
self.vertices.append(&mut [
|
||||||
|
DVec3::new( -1., phi, 0.),
|
||||||
|
DVec3::new( 1., phi, 0.),
|
||||||
|
DVec3::new( -1., -phi, 0.),
|
||||||
|
DVec3::new( 1., -phi, 0.),
|
||||||
|
DVec3::new( 0., -1., phi),
|
||||||
|
DVec3::new( 0., 1., phi),
|
||||||
|
DVec3::new( 0., -1., -phi),
|
||||||
|
DVec3::new( 0., 1., -phi),
|
||||||
|
DVec3::new( phi, 0., -1.),
|
||||||
|
DVec3::new( phi, 0., 1.),
|
||||||
|
DVec3::new(-phi, 0., -1.),
|
||||||
|
DVec3::new(-phi, 0., 1.),
|
||||||
|
].to_vec());
|
||||||
|
|
||||||
|
self.faces.append(&mut [
|
||||||
|
IVec3::new(0, 11, 5),
|
||||||
|
IVec3::new(0, 5, 1),
|
||||||
|
IVec3::new(0, 1, 7),
|
||||||
|
IVec3::new(0, 7, 10),
|
||||||
|
IVec3::new(0, 10, 11),
|
||||||
|
IVec3::new(1, 5, 9),
|
||||||
|
IVec3::new(5, 11, 4),
|
||||||
|
IVec3::new(11, 10, 2),
|
||||||
|
IVec3::new(10, 7, 6),
|
||||||
|
IVec3::new(7, 1, 8),
|
||||||
|
IVec3::new(3, 9, 4),
|
||||||
|
IVec3::new(3, 4, 2),
|
||||||
|
IVec3::new(3, 2, 6),
|
||||||
|
IVec3::new(3, 6, 8),
|
||||||
|
IVec3::new(3, 8, 9),
|
||||||
|
IVec3::new(4, 9, 5),
|
||||||
|
IVec3::new(2, 4, 11),
|
||||||
|
IVec3::new(6, 2, 10),
|
||||||
|
IVec3::new(8, 6, 7),
|
||||||
|
IVec3::new(9, 8, 1),
|
||||||
|
].to_vec());
|
||||||
|
|
||||||
|
// Subdivide until depth
|
||||||
|
for _ in 0..depth {
|
||||||
|
self.subdivide();
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subdivide(&mut self)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
756
src/bin/mesh.rs
Normal file
756
src/bin/mesh.rs
Normal file
@ -0,0 +1,756 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::{f32::consts::PI, io::Write};
|
||||||
|
use glam::{IVec3, Vec3};
|
||||||
|
use noise::NoiseFn;
|
||||||
|
use pool::Pool;
|
||||||
|
use sparse::Sparse;
|
||||||
|
|
||||||
|
const DEBUG_PRINTS :bool = false;
|
||||||
|
|
||||||
|
const DEGREES :f32 = PI / 180.;
|
||||||
|
|
||||||
|
const SEED :u32 = 69;
|
||||||
|
const DELTA_THRESHOLD :f32 = 1. * DEGREES;
|
||||||
|
const MAX_DEPTH :u8 = 16;
|
||||||
|
const GRID_SIZE :usize = 23;
|
||||||
|
const GRID_SCALE :f32 = 20.;
|
||||||
|
const MESH_SCALE :f32 = 0.25;
|
||||||
|
|
||||||
|
const SQRT_3 :f32 = 1.7320508075;
|
||||||
|
const TR_EDGE :f32 = 0.5;
|
||||||
|
const TR_VERT :f32 = 2. * TR_EDGE;
|
||||||
|
const TR_SIDH :f32 = SQRT_3 * TR_EDGE;
|
||||||
|
const TR_SIDE :f32 = 2. * TR_SIDH;
|
||||||
|
const TR_CROS :f32 = TR_EDGE + TR_VERT;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum Action {
|
||||||
|
Check(/*Id*/usize, /*Caller*/usize),
|
||||||
|
Subdivide(/*Id*/usize, /*Caller*/usize),
|
||||||
|
Split(/*Id*/usize, /*Caller*/usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Cell {
|
||||||
|
pub depth:u8,
|
||||||
|
pub direction:u8,
|
||||||
|
pub sibling:u8,
|
||||||
|
pub neighbors:[usize;3],
|
||||||
|
pub vertices:[usize;3],
|
||||||
|
}
|
||||||
|
impl Cell {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
depth:0,
|
||||||
|
direction:3,
|
||||||
|
sibling:3,
|
||||||
|
neighbors:[0; 3],
|
||||||
|
vertices:[0; 3],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Grid {
|
||||||
|
radius:usize,
|
||||||
|
vertices:Pool<Vec3>,
|
||||||
|
cells:Pool<Cell>,
|
||||||
|
|
||||||
|
generator:noise::Perlin,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grid {
|
||||||
|
pub fn new(radius:usize) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
radius:radius,
|
||||||
|
vertices:Pool::<Vec3>::new(),
|
||||||
|
cells:Pool::<Cell>::new(),
|
||||||
|
|
||||||
|
generator:noise::Perlin::new(SEED),
|
||||||
|
}.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(mut self) -> Self
|
||||||
|
{
|
||||||
|
// Create vertices
|
||||||
|
let size = self.radius + 1;
|
||||||
|
|
||||||
|
let z_offset = -GRID_SCALE * TR_CROS * (size as f32 / 2.);
|
||||||
|
for row in 0..=size {
|
||||||
|
let basis :f32 = -GRID_SCALE * TR_SIDH * row as f32;
|
||||||
|
|
||||||
|
for col in 0..=row {
|
||||||
|
let x = basis + (GRID_SCALE * TR_SIDE * col as f32);
|
||||||
|
let z = z_offset + (GRID_SCALE * TR_CROS * row as f32);
|
||||||
|
self.add_vertex(Vec3::new(x, 0., z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create cells and assign vertices
|
||||||
|
|
||||||
|
let mut v_index = 0;
|
||||||
|
let mut c_index = 0;
|
||||||
|
for row in 0..size {
|
||||||
|
for col in 0..((2 * row) + 1) {
|
||||||
|
self.cells.add({
|
||||||
|
let mut cell = Cell::new();
|
||||||
|
let index = c_index + col;
|
||||||
|
|
||||||
|
cell.vertices = if col & 1 == 0 {[
|
||||||
|
1 + v_index + row + (col / 2) + 2,
|
||||||
|
1 + v_index + row + (col / 2) + 1,
|
||||||
|
1 + v_index + (col / 2),
|
||||||
|
]} else {[
|
||||||
|
1 + v_index + (col / 2),
|
||||||
|
1 + v_index + (col / 2) + 1,
|
||||||
|
1 + v_index + row + (col / 2) + 2,
|
||||||
|
]};
|
||||||
|
|
||||||
|
cell.neighbors = if col & 1 == 0 {[
|
||||||
|
if col > 0 { 1 + index - 1 } else { 0 },
|
||||||
|
if col < (2 * row) { 1 + index + 1 } else { 0 },
|
||||||
|
if row < self.radius { 1 + index + (2 * (row + 1)) } else { 0 },
|
||||||
|
]} else {[
|
||||||
|
1 + index + 1,
|
||||||
|
1 + index - 1,
|
||||||
|
if row > 0 { 1 + index - (2 * row) } else { 0 },
|
||||||
|
]};
|
||||||
|
|
||||||
|
cell
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
v_index += row + 1;
|
||||||
|
c_index += (2 * row) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepare_nodes(&mut self)
|
||||||
|
{
|
||||||
|
let mut data = self.cells.list();
|
||||||
|
let mut data_len = data.len();
|
||||||
|
|
||||||
|
let mut passes = 0;
|
||||||
|
while data.len() > 0 {
|
||||||
|
let pass = data.clone();
|
||||||
|
data.clear();
|
||||||
|
|
||||||
|
for id in pass {
|
||||||
|
if self.node_prepare(id) {
|
||||||
|
data.push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_data = self.cells.list();
|
||||||
|
if new_data.len() > data_len {
|
||||||
|
data.append(&mut new_data[data_len..].to_vec());
|
||||||
|
data_len = new_data.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
passes += 1;
|
||||||
|
if passes % 10 == 0 {
|
||||||
|
println!("Pass {}", passes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_prepare(&mut self, id:usize) -> bool
|
||||||
|
// Test the height change of the node to determine if it should be subdivided.
|
||||||
|
//
|
||||||
|
{
|
||||||
|
let cell = if let Some(data) = self.cells.get(id) {
|
||||||
|
*data
|
||||||
|
} else { return false; };
|
||||||
|
|
||||||
|
// Determine if cell should be subdivided.
|
||||||
|
let v = [
|
||||||
|
*self.vertices.get(cell.vertices[0]).unwrap(),
|
||||||
|
*self.vertices.get(cell.vertices[1]).unwrap(),
|
||||||
|
*self.vertices.get(cell.vertices[2]).unwrap(),
|
||||||
|
];
|
||||||
|
let normal = (v[1] - v[0]).cross(v[2] - v[0]).normalize();
|
||||||
|
|
||||||
|
let mut neighbor_normal = Vec3::ZERO;
|
||||||
|
let mut count = 0.;
|
||||||
|
|
||||||
|
for n in 0..3 {
|
||||||
|
let neighbor_id = cell.neighbors[n];
|
||||||
|
if neighbor_id != 0 {
|
||||||
|
if let Some(neighbor) = self.cells.get(neighbor_id) {
|
||||||
|
let v = [
|
||||||
|
*self.vertices.get(neighbor.vertices[0]).unwrap(),
|
||||||
|
*self.vertices.get(neighbor.vertices[1]).unwrap(),
|
||||||
|
*self.vertices.get(neighbor.vertices[2]).unwrap(),
|
||||||
|
];
|
||||||
|
|
||||||
|
neighbor_normal += (v[1] - v[0]).cross(v[2] - v[0]).normalize();
|
||||||
|
count += 1.;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
neighbor_normal /= count;
|
||||||
|
|
||||||
|
let delta = normal.angle_between(neighbor_normal);
|
||||||
|
let threshold = DELTA_THRESHOLD * (cell.depth + 1) as f32;
|
||||||
|
//println!("{:8} {} <> {}", delta > threshold, delta, threshold);
|
||||||
|
if delta > threshold {
|
||||||
|
//println!("subdiv");
|
||||||
|
self.node_update(&vec![Action::Subdivide(id, 0)]);
|
||||||
|
|
||||||
|
let new_cell = if let Some(data) = self.cells.get(id) {
|
||||||
|
*data
|
||||||
|
} else { return false; };
|
||||||
|
|
||||||
|
new_cell.depth != cell.depth
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_update(&mut self, actions:&Vec<Action>)
|
||||||
|
{
|
||||||
|
let mut actions = actions.clone();
|
||||||
|
while let Some(action) = actions.pop() {
|
||||||
|
actions.append(&mut match action {
|
||||||
|
Action::Check(id, caller) => self.node_check(id, caller),
|
||||||
|
Action::Subdivide(id, caller) => self.node_subdivide(id, caller),
|
||||||
|
Action::Split(id, caller) => self.node_split(id, caller),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_check(&mut self, id:usize, caller:usize) -> Vec<Action>
|
||||||
|
// Determine if node needs to be subdivided or split.
|
||||||
|
//
|
||||||
|
{
|
||||||
|
let cell = if let Some(data) = self.cells.get(id) {
|
||||||
|
*data
|
||||||
|
} else { return vec![]; };
|
||||||
|
|
||||||
|
//println!("caller {}", caller);
|
||||||
|
self.print_cell("UPDATE", id, &cell);
|
||||||
|
|
||||||
|
// Determine if relation with neighbors is stable.
|
||||||
|
// - Regular cell is stable if neighbors are same depth or depth +/- 1.
|
||||||
|
// - Split cell is stable if exactly 1 neighbor is depth +1 and rest are same or -1.
|
||||||
|
// Count number of regular neighbors of greater depth.
|
||||||
|
let mut diff_direction :usize = 0;
|
||||||
|
let mut diff_count :usize = 0;
|
||||||
|
for n in 0..cell.neighbors.len() {
|
||||||
|
let neighbor_id = cell.neighbors[n];
|
||||||
|
|
||||||
|
if neighbor_id != 0 {
|
||||||
|
let neighbor = self.cells.get(neighbor_id).unwrap().clone();
|
||||||
|
if neighbor.depth >= (cell.depth & !1) + 2 {
|
||||||
|
diff_count += 1;
|
||||||
|
diff_direction = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine how cell should be handled.
|
||||||
|
if cell.depth & 1 == 0 {
|
||||||
|
match diff_count {
|
||||||
|
0 => { vec![] }
|
||||||
|
1 => { vec![Action::Split(id, diff_direction)] }
|
||||||
|
2|3 => { vec![Action::Subdivide(id, caller)] }
|
||||||
|
_ => { panic!("invalid diff count") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
match diff_count {
|
||||||
|
0 => { vec![] }
|
||||||
|
1 => {
|
||||||
|
if cell.direction as usize != diff_direction {
|
||||||
|
vec![Action::Subdivide(id, caller)]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2|3 => { vec![Action::Subdivide(id, caller)] }
|
||||||
|
_ => { panic!("invalid diff count") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if neighbors need to be updated.
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn node_subdivide(&mut self, id:usize, _caller:usize) -> Vec<Action>
|
||||||
|
{
|
||||||
|
let mut cell = if let Some(data) = self.cells.get(id) {
|
||||||
|
*data
|
||||||
|
} else { return vec![]; };
|
||||||
|
if cell.depth >= MAX_DEPTH { return vec![]; }
|
||||||
|
|
||||||
|
let mut actions = Vec::<Action>::new();
|
||||||
|
|
||||||
|
//println!("caller {}", caller);
|
||||||
|
self.print_cell("BEGDIV", id, &cell);
|
||||||
|
|
||||||
|
// If half-depth, get twin information.
|
||||||
|
// If sibling 1, forward call to sibling 0.
|
||||||
|
//
|
||||||
|
let twin_dir = if cell.depth & 1 == 0 { 3 } else { Self::twin_neighbor(cell.direction, cell.sibling) };
|
||||||
|
|
||||||
|
let mut twin_id = 0;
|
||||||
|
let mut twin :Option<Cell> = None;
|
||||||
|
|
||||||
|
let direction = cell.direction as usize;
|
||||||
|
let d_offset_0 = (direction + 1) % 3;
|
||||||
|
let d_offset_1 = (direction + 2) % 3;
|
||||||
|
|
||||||
|
if cell.depth & 1 == 1 {
|
||||||
|
twin_id = cell.neighbors[twin_dir];
|
||||||
|
|
||||||
|
if cell.sibling == 1 {
|
||||||
|
return vec![Action::Subdivide(twin_id, id)];
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
let (neighbors, vertices) = match twin {
|
||||||
|
Some(twin) => {
|
||||||
|
let mut neighbors = cell.neighbors;
|
||||||
|
let mut vertices = cell.vertices;
|
||||||
|
|
||||||
|
neighbors[twin_dir] = twin.neighbors[twin_dir];
|
||||||
|
vertices[d_offset_0] = twin.vertices[d_offset_0];
|
||||||
|
|
||||||
|
(neighbors, vertices)
|
||||||
|
}
|
||||||
|
|
||||||
|
None => {
|
||||||
|
(cell.neighbors, cell.vertices)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut updates = Vec::<usize>::new();
|
||||||
|
for n in 0..neighbors.len() {
|
||||||
|
let neighbor_id = neighbors[n];
|
||||||
|
if let Some(neighbor) = self.cells.get(neighbor_id) {
|
||||||
|
if neighbor.neighbors[n] == id || (twin_id != 0 && neighbor.neighbors[n] == twin_id) {
|
||||||
|
updates.push(neighbor_id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let nd_offset_0 = (n + 2) % 3;
|
||||||
|
let nd_offset_1 = (n + 1) % 3;
|
||||||
|
|
||||||
|
updates.push(neighbor.neighbors[nd_offset_0]);
|
||||||
|
updates.push(neighbor.neighbors[nd_offset_1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(twin) = &twin {
|
||||||
|
let neighbor_id = twin.neighbors[direction];
|
||||||
|
if let Some(neighbor) = self.cells.get(neighbor_id) {
|
||||||
|
if neighbor.neighbors[direction] == id || neighbor.neighbors[direction] == twin_id {
|
||||||
|
updates.push(neighbor_id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
updates.push(neighbor.neighbors[d_offset_0]);
|
||||||
|
updates.push(neighbor.neighbors[d_offset_1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a neighbor is of lesser depth, that node needs to be subdivided
|
||||||
|
// before subdividing the current node.
|
||||||
|
// If node is subdivided as a result, no work to do.
|
||||||
|
//
|
||||||
|
let initial_depth = cell.depth;
|
||||||
|
for n in 0..neighbors.len() {
|
||||||
|
let neighbor_id = neighbors[n];
|
||||||
|
if neighbor_id != 0 {
|
||||||
|
let neighbor = *self.cells.get(neighbor_id).unwrap();
|
||||||
|
if neighbor.depth < initial_depth && neighbor.depth & 1 == 1 {
|
||||||
|
actions.push(Action::Subdivide(neighbor_id, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh cell data incase changed.
|
||||||
|
cell = if let Some(data) = self.cells.get(id) {
|
||||||
|
*data
|
||||||
|
} else { return vec![]; };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !actions.is_empty() {
|
||||||
|
return [vec![Action::Subdivide(id, id)], actions].concat();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get vector values of outer vertices.
|
||||||
|
let vertex_values = [
|
||||||
|
*self.vertices.get(vertices[0]).unwrap(),
|
||||||
|
*self.vertices.get(vertices[1]).unwrap(),
|
||||||
|
*self.vertices.get(vertices[2]).unwrap(),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// Get midpoints from adjacent nodes.
|
||||||
|
let mut midpoints = [0; 3];
|
||||||
|
for n in 0..neighbors.len() {
|
||||||
|
let neighbor_id = neighbors[n];
|
||||||
|
if neighbor_id != 0 {
|
||||||
|
let neighbor = *self.cells.get(neighbor_id).unwrap();
|
||||||
|
|
||||||
|
if (neighbor.depth > cell.depth && neighbor.depth & 1 == 0) || (neighbor.depth > cell.depth && neighbor.direction == n as u8) {
|
||||||
|
midpoints[n] = neighbor.vertices[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match twin {
|
||||||
|
Some(_) => {
|
||||||
|
midpoints[direction] = cell.vertices[d_offset_0];
|
||||||
|
}
|
||||||
|
None => { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill missing midpoint vertices.
|
||||||
|
let subvertices = [
|
||||||
|
if midpoints[0] != 0 { midpoints[0] } else { self.add_vertex(((vertex_values[2] - vertex_values[1]) / 2.) + vertex_values[1]) },
|
||||||
|
if midpoints[1] != 0 { midpoints[1] } else { self.add_vertex(((vertex_values[0] - vertex_values[2]) / 2.) + vertex_values[2]) },
|
||||||
|
if midpoints[2] != 0 { midpoints[2] } else { self.add_vertex(((vertex_values[1] - vertex_values[0]) / 2.) + vertex_values[0]) },
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// Prepare child cells.
|
||||||
|
let mut children = [
|
||||||
|
Cell::new(),
|
||||||
|
Cell::new(),
|
||||||
|
Cell::new(),
|
||||||
|
Cell::new(),
|
||||||
|
];
|
||||||
|
let child_ids = [
|
||||||
|
self.cells.add(Cell::new()),
|
||||||
|
self.cells.add(Cell::new()),
|
||||||
|
if twin.is_some() { twin_id } else { self.cells.add(Cell::new()) },
|
||||||
|
id,
|
||||||
|
];
|
||||||
|
|
||||||
|
cell.depth = (cell.depth + 2) & !1;
|
||||||
|
for c in 0..children.len() {
|
||||||
|
children[c].depth = cell.depth;
|
||||||
|
children[c].sibling = c as u8;
|
||||||
|
}
|
||||||
|
for c in 0..3 {
|
||||||
|
children[3].neighbors[c] = child_ids[c];
|
||||||
|
children[c].neighbors[c] = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set new cell vertices.
|
||||||
|
children[0].vertices = [ vertices[0], subvertices[2], subvertices[1] ];
|
||||||
|
children[1].vertices = [ subvertices[2], vertices[1], subvertices[0] ];
|
||||||
|
children[2].vertices = [ subvertices[1], subvertices[0], vertices[2] ];
|
||||||
|
children[3].vertices = [ subvertices[0], subvertices[1], subvertices[2] ];
|
||||||
|
|
||||||
|
|
||||||
|
// Link twin neighbor to center cell.
|
||||||
|
if twin.is_some() {
|
||||||
|
if let Some(neighbor) = self.cells.get_mut(neighbors[twin_dir]) {
|
||||||
|
if neighbor.neighbors[twin_dir] == twin_id {
|
||||||
|
neighbor.neighbors[twin_dir] = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trade neighbor links with neighboring cells.
|
||||||
|
for n in 0..neighbors.len() {
|
||||||
|
let neighbor_id = neighbors[n];
|
||||||
|
|
||||||
|
let nd_offset_0 = (n + 2) % 3;
|
||||||
|
let nd_offset_1 = (n + 1) % 3;
|
||||||
|
|
||||||
|
//println!("neighbor {} {}", n, neighbor_id);
|
||||||
|
|
||||||
|
let mut processed = false;
|
||||||
|
if n == direction {
|
||||||
|
if let Some(twin) = &twin {
|
||||||
|
// Update both children that have edges in direction.
|
||||||
|
|
||||||
|
let n0 = cell.neighbors[direction];
|
||||||
|
let n1 = twin.neighbors[direction];
|
||||||
|
|
||||||
|
children[nd_offset_0].neighbors[direction] = n0;
|
||||||
|
children[nd_offset_1].neighbors[direction] = n1;
|
||||||
|
|
||||||
|
//println!("d {} [{}] = {}, {} [{}] = {}", n0, n, child_ids[nd_offset_0], n1, n, child_ids[nd_offset_1]);
|
||||||
|
|
||||||
|
if let Some(neighbor) = self.cells.get_mut(n0) {
|
||||||
|
neighbor.neighbors[n] = child_ids[nd_offset_0];
|
||||||
|
}
|
||||||
|
if let Some(neighbor) = self.cells.get_mut(n1) {
|
||||||
|
neighbor.neighbors[n] = child_ids[nd_offset_1];
|
||||||
|
}
|
||||||
|
|
||||||
|
processed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !processed {
|
||||||
|
if neighbor_id != 0 {
|
||||||
|
let neighbor = self.cells.get(neighbor_id).unwrap().clone();
|
||||||
|
|
||||||
|
if neighbor.depth == cell.depth {
|
||||||
|
// Update both children that have edges in direction.
|
||||||
|
// Neighbor must be parent.
|
||||||
|
|
||||||
|
let n0 = neighbor.neighbors[nd_offset_1];
|
||||||
|
let n1 = neighbor.neighbors[nd_offset_0];
|
||||||
|
|
||||||
|
//println!("{} [{}] = {}, {} [{}] = {}", n0, n, child_ids[nd_offset_0], n1, n, child_ids[nd_offset_1]);
|
||||||
|
|
||||||
|
children[nd_offset_0].neighbors[n] = n0;
|
||||||
|
children[nd_offset_1].neighbors[n] = n1;
|
||||||
|
|
||||||
|
if let Some(neighbor) = self.cells.get_mut(n0) {
|
||||||
|
neighbor.neighbors[n] = child_ids[nd_offset_0];
|
||||||
|
}
|
||||||
|
if let Some(neighbor) = self.cells.get_mut(n1) {
|
||||||
|
neighbor.neighbors[n] = child_ids[nd_offset_1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update cells.
|
||||||
|
for i in 0..children.len() {
|
||||||
|
self.print_cell("SUBDIV", child_ids[i], &children[i]);
|
||||||
|
|
||||||
|
self.cells.update(child_ids[i], children[i]).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update neighbor cells
|
||||||
|
for update in updates {
|
||||||
|
if update != 0 {
|
||||||
|
actions.push(Action::Check(update, id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
actions
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_split(&mut self, id:usize, direction:usize) -> Vec<Action>
|
||||||
|
{
|
||||||
|
let mut cell = if let Some(data) = self.cells.get(id) {
|
||||||
|
*data
|
||||||
|
} else { return vec![]; };
|
||||||
|
if cell.direction as usize == direction { return vec![]; }
|
||||||
|
|
||||||
|
let actions = Vec::<Action>::new();
|
||||||
|
|
||||||
|
self.print_cell("SPLIT", id, &cell);
|
||||||
|
|
||||||
|
let neighbors = cell.neighbors;
|
||||||
|
|
||||||
|
if cell.depth & 1 == 0 {
|
||||||
|
let mut twin = Cell::new();
|
||||||
|
|
||||||
|
// Set cell and twin properties.
|
||||||
|
cell.depth += 1;
|
||||||
|
twin.depth = cell.depth;
|
||||||
|
|
||||||
|
cell.direction = direction as u8;
|
||||||
|
twin.direction = direction as u8;
|
||||||
|
|
||||||
|
cell.sibling = 0;
|
||||||
|
twin.sibling = 1;
|
||||||
|
|
||||||
|
let neighbor_id = cell.neighbors[direction];
|
||||||
|
let neighbor = self.cells.get(neighbor_id).unwrap().clone();
|
||||||
|
let midpoint = neighbor.vertices[direction];
|
||||||
|
|
||||||
|
let d_offset_0 = (direction + 1) % 3;
|
||||||
|
let d_offset_1 = (direction + 2) % 3;
|
||||||
|
|
||||||
|
// Set cell and twin vertices.
|
||||||
|
twin.vertices = cell.vertices;
|
||||||
|
twin.vertices[d_offset_1] = midpoint;
|
||||||
|
cell.vertices[d_offset_0] = midpoint;
|
||||||
|
|
||||||
|
// Set cell and twin neighbors.
|
||||||
|
let n0 = neighbor.neighbors[d_offset_0];
|
||||||
|
let n1 = neighbor.neighbors[d_offset_1];
|
||||||
|
|
||||||
|
twin.neighbors = cell.neighbors;
|
||||||
|
twin.neighbors[direction] = n1;
|
||||||
|
twin.neighbors[Self::twin_neighbor(direction as u8, 1)] = id;
|
||||||
|
|
||||||
|
let twin_id = self.cells.add(twin);
|
||||||
|
cell.neighbors[direction] = n0;
|
||||||
|
cell.neighbors[Self::twin_neighbor(direction as u8, 0)] = twin_id;
|
||||||
|
|
||||||
|
// Update links for outer neighbors
|
||||||
|
if let Some(neighbor) = self.cells.get_mut(n0) {
|
||||||
|
neighbor.neighbors[direction] = id;
|
||||||
|
}
|
||||||
|
if let Some(neighbor) = self.cells.get_mut(n1) {
|
||||||
|
neighbor.neighbors[direction] = twin_id;
|
||||||
|
}
|
||||||
|
if let Some(neighbor) = self.cells.get_mut(neighbors[d_offset_1]) {
|
||||||
|
neighbor.neighbors[d_offset_1] = twin_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.print_cell("SUBHAV", id, &cell);
|
||||||
|
self.print_cell("SUBHAV", twin_id, &twin);
|
||||||
|
|
||||||
|
// Push updated data
|
||||||
|
self.cells.update(id, cell).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node is already split, so cells only need to be rotated.
|
||||||
|
// This probably cannot happen, as it would require a neighbor to disappear
|
||||||
|
// and another to form before updating of this triangle.
|
||||||
|
else {
|
||||||
|
panic!("split node needs to be rotated");
|
||||||
|
}
|
||||||
|
|
||||||
|
actions
|
||||||
|
}
|
||||||
|
|
||||||
|
fn twin_neighbor(direction:u8, sibling:u8) -> usize
|
||||||
|
{
|
||||||
|
((direction + 2 - sibling) % 3) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_vertex(&mut self, vertex:Vec3) -> usize
|
||||||
|
{
|
||||||
|
self.vertices.add(Vec3::new(vertex.x, self.vertex_height(vertex.x, vertex.z), vertex.z))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_cell(&self, text:&str, id:usize, cell:&Cell)
|
||||||
|
{
|
||||||
|
if DEBUG_PRINTS {
|
||||||
|
println!("{:8} {:3} ( {:2} ) [{:3} {:3} {:3}] [{:3} {:3} {:3}]",
|
||||||
|
text,
|
||||||
|
id,
|
||||||
|
cell.depth,
|
||||||
|
cell.vertices[0],
|
||||||
|
cell.vertices[1],
|
||||||
|
cell.vertices[2],
|
||||||
|
cell.neighbors[0],
|
||||||
|
cell.neighbors[1],
|
||||||
|
cell.neighbors[2],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_mesh(&self) -> Mesh
|
||||||
|
{
|
||||||
|
let mut mesh = Mesh::new();
|
||||||
|
let mut conversion = Sparse::<usize>::new();
|
||||||
|
|
||||||
|
// Add vertices
|
||||||
|
for index in self.vertices.list() {
|
||||||
|
if let Some(vertex) = self.vertices.get(index) {
|
||||||
|
conversion.set(index, mesh.vertices.len());
|
||||||
|
mesh.vertices.push(*vertex * MESH_SCALE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add faces
|
||||||
|
for index in self.cells.list() {
|
||||||
|
if let Some(cell) = self.cells.get(index) {
|
||||||
|
self.print_cell("FINAL", index, &cell);
|
||||||
|
|
||||||
|
let a = *conversion.get(cell.vertices[0]).unwrap() as i32;
|
||||||
|
let b = *conversion.get(cell.vertices[1]).unwrap() as i32;
|
||||||
|
let c = *conversion.get(cell.vertices[2]).unwrap() as i32;
|
||||||
|
|
||||||
|
mesh.faces.push(IVec3::new(a, c, b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vertex_height(&self, x:f32, y:f32) -> f32
|
||||||
|
{
|
||||||
|
let mut value :f64 = 0.;
|
||||||
|
let mut scale = 1. / 8.;
|
||||||
|
let mut weight = 1.;
|
||||||
|
let mut result :f64;
|
||||||
|
|
||||||
|
for _ in 0..6 {
|
||||||
|
result = self.generator.get([scale * (x as f64), scale * (y as f64)]);
|
||||||
|
value += result * result * weight;
|
||||||
|
scale *= 1. / 8.;
|
||||||
|
weight *= 4.;
|
||||||
|
}
|
||||||
|
value as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Mesh {
|
||||||
|
pub vertices:Vec<Vec3>,
|
||||||
|
pub faces:Vec<IVec3>,
|
||||||
|
}
|
||||||
|
impl Mesh {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
vertices:Vec::<Vec3>::new(),
|
||||||
|
faces:Vec::<IVec3>::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let size = GRID_SIZE;
|
||||||
|
let mut grid = Grid::new(size);
|
||||||
|
grid.prepare_nodes();
|
||||||
|
|
||||||
|
let mesh = grid.to_mesh();
|
||||||
|
generate_obj("test.obj", &mesh).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_obj(path:&str, mesh:&Mesh) -> Result<(),()>
|
||||||
|
{
|
||||||
|
match std::fs::File::create(path) {
|
||||||
|
Ok(mut file) => {
|
||||||
|
let mut min = Vec3::ZERO;
|
||||||
|
let mut max = Vec3::ZERO;
|
||||||
|
|
||||||
|
for v in &mesh.vertices {
|
||||||
|
if v.x < min.x { min.x = v.x } else if v.x > max.x { max.x = v.x };
|
||||||
|
if v.z < min.z { min.z = v.z } else if v.z > max.z { max.z = v.z };
|
||||||
|
|
||||||
|
let v = *v * 20.;
|
||||||
|
file.write_all(format!("v {:.6} {:.6} {:.6}\n", v.x, v.y, v.z).as_bytes()).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
file.write_all("\n".as_bytes()).ok();
|
||||||
|
|
||||||
|
let rx = max.x - min.x;
|
||||||
|
let rz = max.z - min.z;
|
||||||
|
|
||||||
|
for v in &mesh.vertices {
|
||||||
|
let ux = ((v.x / rx) + 0.5).clamp(0., 1.);
|
||||||
|
let uz = ((v.z / rz) + 0.5).clamp(0., 1.);
|
||||||
|
|
||||||
|
file.write_all(format!("vt {:.6} {:.6}\n", ux, uz).as_bytes()).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
file.write_all("\n".as_bytes()).ok();
|
||||||
|
|
||||||
|
for f in &mesh.faces {
|
||||||
|
file.write_all(format!("f {}/{} {}/{} {}/{}\n",
|
||||||
|
f.x + 1, f.x + 1,
|
||||||
|
f.y + 1, f.y + 1,
|
||||||
|
f.z + 1, f.z + 1,
|
||||||
|
).as_bytes()).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(_) => Err(()),
|
||||||
|
}
|
||||||
|
}
|
4
src/bin/skybox.rs
Normal file
4
src/bin/skybox.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
fn main()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
1
src/lib.rs
Normal file
1
src/lib.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod utility;
|
4
src/utility.rs
Normal file
4
src/utility.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub fn f32_sign(value:f32) -> f32
|
||||||
|
{
|
||||||
|
((value > 0.) as i32 - (value < 0.) as i32) as f32
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user