hyperboloid/src/mesh.rs

65 lines
1.8 KiB
Rust

use std::f32::consts::PI;
use glam::{Mat2, Vec3, vec2, vec3};
pub struct Mesh {
pub vertices: Vec<Vec3>,
pub faces: Vec<[usize; 3]>,
}
pub fn shell(shape: &crate::ShapeArgs) -> Mesh {
let mut vertices = Vec::<Vec3>::new();
let mut faces = Vec::<[usize; 3]>::new();
let sides = shape.sides as usize;
let layers = (shape.layers_up + shape.layers_down) as usize;
let base_layer = shape.layers_down;
let diameter = shape.base_diameter;
let radius = diameter / 2.;
let height = shape.height;
let bottom_angle = (PI / sides as f32) * -(base_layer as f32);
let top_angle = (PI / sides as f32) * (layers as f32 - base_layer as f32);
let bottom_y = radius * bottom_angle.tan();
let top_y = radius * top_angle.tan();
let incline = height / (top_y - bottom_y);
let elevation = -height / 2. - incline * bottom_y;
for layer in 0..=layers {
let angle = (PI / sides as f32) * (layer as f32 - base_layer as f32);
let x = radius;
let y = angle.tan() * x;
let z = elevation + incline * y;
for side in 0..sides {
let angle = (2. * PI / sides as f32) * side as f32;
let rot = Mat2::from_angle(angle);
let xy = rot * vec2(x, y);
let v = vec3(xy.x, xy.y, z);
vertices.push(v);
}
}
for layer in 0..layers {
let base = sides * layer;
for side in 0..sides {
let index = |layer, offset| base + sides * layer + (side + offset) % sides;
faces.push([index(0, 0), index(0, 1), index(1, 0)]);
faces.push([index(0, 1), index(1, 1), index(1, 0)]);
}
}
Mesh { vertices, faces }
}
pub fn solid(shape: &crate::ShapeArgs) -> Mesh {
let mut mesh = shell(shape);
let sides = shape.sides as usize;
for side in 0..(sides - 2) {
mesh.faces.push([sides - 1, side + 1, side]);
}
let base = mesh.vertices.len() - sides;
for side in 0..(sides - 2) {
mesh.faces
.push([base + sides - 1, base + side, base + side + 1]);
}
mesh
}