Initialize repository.

This commit is contained in:
yukirij 2024-06-09 17:16:50 -07:00
commit 1f3b920570
7 changed files with 856 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
Cargo.lock
*.obj

11
Cargo.toml Normal file
View 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
View 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
View 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
View File

@ -0,0 +1,4 @@
fn main()
{
}

1
src/lib.rs Normal file
View File

@ -0,0 +1 @@
pub mod utility;

4
src/utility.rs Normal file
View File

@ -0,0 +1,4 @@
pub fn f32_sign(value:f32) -> f32
{
((value > 0.) as i32 - (value < 0.) as i32) as f32
}