Adjust to be sandbox wrapper friendly.
This commit is contained in:
1 parent
3c21e59afe
commit
e45e8eb21f
3 files changed
+295
-294
No files matched your search
@@ -1,2 +1,3 @@
|
||||
/target
|
||||
mesh.stl
|
||||
.bash_history
|
||||
+13
-13
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "mushroom_generator"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
approx = "0.5.1"
|
||||
cached = "0.51.4"
|
||||
clap = { version = "4.5.4", features = ["derive"] }
|
||||
rocket = "0.5.1"
|
||||
serde = "1.0.203"
|
||||
serde_derive = "1.0.203"
|
||||
stl_io = "0.8.5"
|
||||
[package]
|
||||
name = "mushroom_generator"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
approx = "0.5.1"
|
||||
cached = "0.51.4"
|
||||
clap = { version = "4.5.4", features = ["derive"] }
|
||||
rocket = "0.5.1"
|
||||
serde = "1.0.203"
|
||||
serde_derive = "1.0.203"
|
||||
stl_io = "0.8.5"
|
||||
+281
-281
@@ -1,281 +1,281 @@
|
||||
use cached::proc_macro::cached;
|
||||
use stl_io::{self, Normal, Triangle, Vertex};
|
||||
|
||||
use crate::layers::{Layer, Layers};
|
||||
|
||||
fn new_triangle(p1: &Vertex, p2: &Vertex, p3: &Vertex) -> stl_io::Triangle {
|
||||
// Set Vector U to (Triangle.p2 minus Triangle.p1)
|
||||
// Set Vector V to (Triangle.p3 minus Triangle.p1)
|
||||
|
||||
// Set Normal.x to (multiply U.y by V.z) minus (multiply U.z by V.y)
|
||||
// Set Normal.y to (multiply U.z by V.x) minus (multiply U.x by V.z)
|
||||
// Set Normal.z to (multiply U.x by V.y) minus (multiply U.y by V.x)
|
||||
|
||||
let u = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
|
||||
let v = [p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]];
|
||||
|
||||
let n_x = (u[1] * v[2]) - (u[2] * v[1]);
|
||||
let n_y = (u[2] * v[0]) - (u[0] * v[2]);
|
||||
let n_z = (u[0] * v[1]) - (u[1] * v[0]);
|
||||
|
||||
stl_io::Triangle {
|
||||
normal: Normal::new([n_x, n_y, n_z]),
|
||||
vertices: [*p1, *p2, *p3],
|
||||
}
|
||||
}
|
||||
|
||||
/// Find a point on the cirle at a given angle (in radians).
|
||||
fn vertex_on_circle(center: &Vertex, radius: f32, angle: f32) -> Vertex {
|
||||
let x = center[0] + (radius * angle.cos());
|
||||
let y = center[1] + (radius * angle.sin());
|
||||
let z = center[2];
|
||||
|
||||
Vertex::new([x, y, z])
|
||||
}
|
||||
|
||||
fn vertexes_on_circle(layer: &Layer, steps: u32) -> Vec<Vertex> {
|
||||
let mut result = Vec::with_capacity(steps as usize);
|
||||
let stepsize = std::f64::consts::TAU / steps as f64;
|
||||
|
||||
for i in 0..steps {
|
||||
let angle = (i as f64 * stepsize) as f32;
|
||||
result.push(vertex_on_circle(&layer.center, layer.radius, angle));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn tube_base(center: &Vertex, edge: &[Vertex]) -> Vec<Triangle> {
|
||||
let mut result = Vec::with_capacity(edge.len());
|
||||
|
||||
for i in 0..edge.len() {
|
||||
result.push(new_triangle(center, &edge[(i + 1) % edge.len()], &edge[i]));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn tube_sides(botoom_edge: &[Vertex], top_edge: &[Vertex]) -> Vec<Triangle> {
|
||||
assert_eq!(botoom_edge.len(), top_edge.len());
|
||||
|
||||
let mut result = Vec::with_capacity(2 * botoom_edge.len());
|
||||
|
||||
for i in 0..botoom_edge.len() {
|
||||
let j = (i + 1) % botoom_edge.len();
|
||||
|
||||
result.push(new_triangle(&botoom_edge[i], &top_edge[j], &top_edge[i]));
|
||||
result.push(new_triangle(&botoom_edge[i], &botoom_edge[j], &top_edge[j]));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn tube_top(center: &Vertex, edge: &[Vertex]) -> Vec<Triangle> {
|
||||
// The top is the same, except the normals are reversed. We can do that by reversing the order of the vertexes.
|
||||
let mut edge = edge.to_owned();
|
||||
edge.reverse();
|
||||
|
||||
tube_base(center, &edge)
|
||||
}
|
||||
|
||||
#[cached(key = "String", convert = r#"{ format!("{:?}_{}", layers, resolution) }"#)]
|
||||
pub fn render(layers: &Layers, resolution: f32) -> Vec<Triangle> {
|
||||
// Top and Bottom must be a single point, and must be at least one middle layer.
|
||||
assert!(!layers.layers.is_empty());
|
||||
|
||||
// How many vertexes per circle. IE: the resolution of the circle.
|
||||
let circle_steps =
|
||||
((layers.max_radius() * std::f32::consts::TAU) / resolution).max(64.0) as u32;
|
||||
|
||||
let mut layer_vertexes: Vec<Vec<Vertex>> = Vec::with_capacity(layers.layers.len());
|
||||
|
||||
for layer in &layers.layers {
|
||||
layer_vertexes.push(vertexes_on_circle(layer, circle_steps));
|
||||
}
|
||||
|
||||
// Estimate triangle count: base + sides + top
|
||||
let estimated_triangles = layers.layers.len() * circle_steps as usize * 2;
|
||||
let mut result: Vec<Triangle> = Vec::with_capacity(estimated_triangles);
|
||||
|
||||
result.append(&mut tube_base(&layers.base, &layer_vertexes[0]));
|
||||
for i in 0..layer_vertexes.len() - 1 {
|
||||
result.append(&mut tube_sides(&layer_vertexes[i], &layer_vertexes[i + 1]));
|
||||
}
|
||||
result.append(&mut tube_top(&layers.top, layer_vertexes.last().unwrap()));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use approx::relative_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn new_triangle_normal() {
|
||||
// Simple triangle
|
||||
let a = Vertex::new([1.0, 0.0, 0.0]);
|
||||
let b = Vertex::new([0.0, 1.0, 0.0]);
|
||||
let c = Vertex::new([-1.0, 0.0, 0.0]);
|
||||
|
||||
let tri = new_triangle(&a, &b, &c);
|
||||
|
||||
assert_eq!(tri.normal, Normal::new([0.0, 0.0, 2.0]));
|
||||
|
||||
// Same triangle, reverse order.
|
||||
let tri = new_triangle(&c, &b, &a);
|
||||
|
||||
assert_eq!(tri.normal, Normal::new([0.0, 0.0, -2.0]));
|
||||
|
||||
// Uneven numbers.
|
||||
let a = Vertex::new([2.0, 0.0, 0.0]);
|
||||
let b = Vertex::new([0.0, 3.0, 0.0]);
|
||||
let c = Vertex::new([-4.0, 0.0, 0.0]);
|
||||
|
||||
let tri_big = new_triangle(&a, &b, &c);
|
||||
|
||||
assert_eq!(tri_big.normal, Normal::new([0.0, 0.0, 18.0]));
|
||||
}
|
||||
|
||||
fn validate_vec_vertex_relative_eq(val: &Vec<Vertex>, expected: &Vec<Vertex>) {
|
||||
let mut pass = true;
|
||||
|
||||
if val.len() != expected.len() {
|
||||
pass = false;
|
||||
}
|
||||
|
||||
for i in 0..val.len() {
|
||||
for j in 0..3 {
|
||||
if !relative_eq!(val[i][j], expected[i][j]) {
|
||||
pass = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !pass {
|
||||
// We re-compare here (which will always fail) to get the friendly error message,
|
||||
// which I can't figure out how to generate directly.
|
||||
assert_eq!(val, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vertexes_on_circle_basic() {
|
||||
let val = vertexes_on_circle(
|
||||
&Layer {
|
||||
center: Vertex::new([0.0, 0.0, 0.0]),
|
||||
radius: 1.0,
|
||||
},
|
||||
4,
|
||||
);
|
||||
|
||||
let expected = [
|
||||
Vertex::new([1.0, 0.0, 0.0]),
|
||||
Vertex::new([0.0, 1.0, 0.0]),
|
||||
Vertex::new([-1.0, 0.0, 0.0]),
|
||||
Vertex::new([0.0, -1.0, 0.0]),
|
||||
]
|
||||
.to_vec();
|
||||
|
||||
validate_vec_vertex_relative_eq(&val, &expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vertexes_on_circle_complex() {
|
||||
let val = vertexes_on_circle(
|
||||
&Layer {
|
||||
center: Vertex::new([4.0, 5.0, 6.0]),
|
||||
radius: 3.0,
|
||||
},
|
||||
4,
|
||||
);
|
||||
|
||||
let expected = [
|
||||
Vertex::new([7.0, 5.0, 6.0]),
|
||||
Vertex::new([4.0, 8.0, 6.0]),
|
||||
Vertex::new([1.0, 5.0, 6.0]),
|
||||
Vertex::new([4.0, 2.0, 6.0]),
|
||||
]
|
||||
.to_vec();
|
||||
|
||||
validate_vec_vertex_relative_eq(&val, &expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tube_base_test() {
|
||||
// fn tube_base(center: &Vertex, edge: &Vec<Vertex>) -> Vec<Triangle> {
|
||||
|
||||
let center = Vertex::new([0.0, 0.0, 0.0]);
|
||||
let edge = vertexes_on_circle(
|
||||
&Layer {
|
||||
center: center.clone(),
|
||||
radius: 1.0,
|
||||
},
|
||||
4,
|
||||
);
|
||||
|
||||
let triangles = tube_base(¢er, &edge);
|
||||
|
||||
assert_eq!(triangles.len(), edge.len());
|
||||
|
||||
for t in triangles {
|
||||
// All of these triangles should have the same normal (down).
|
||||
assert_eq!(t.normal, Vertex::new([0.0, 0.0, -1.0]));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tube_top_test() {
|
||||
let center = Vertex::new([0.0, 0.0, 0.0]);
|
||||
let edge = vertexes_on_circle(
|
||||
&Layer {
|
||||
center: center.clone(),
|
||||
radius: 1.0,
|
||||
},
|
||||
4,
|
||||
);
|
||||
|
||||
let triangles = tube_top(¢er, &edge);
|
||||
|
||||
assert_eq!(triangles.len(), edge.len());
|
||||
|
||||
for t in triangles {
|
||||
// All of these triangles should have the same normal (up).
|
||||
assert_eq!(t.normal, Vertex::new([0.0, 0.0, 1.0]));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_test() {
|
||||
let layers = Layers {
|
||||
base: Vertex::new([0.0, 0.0, 0.0]),
|
||||
layers: [
|
||||
Layer {
|
||||
center: Vertex::new([0.0, 0.0, 1.0]),
|
||||
radius: 1.0,
|
||||
},
|
||||
Layer {
|
||||
center: Vertex::new([0.0, 0.0, 2.0]),
|
||||
radius: 1.0,
|
||||
},
|
||||
]
|
||||
.to_vec(),
|
||||
top: Vertex::new([0.0, 0.0, 3.0]),
|
||||
};
|
||||
|
||||
let mesh = render(&layers, 10.0); // Large resolution ensures minimum steps of 64.
|
||||
|
||||
// 64 triangles for top, 128 for sides, 64 for bottom.
|
||||
assert_eq!(mesh.len(), 64 + 128 + 64);
|
||||
|
||||
for i in 0..mesh.len() {
|
||||
if i < 64 {
|
||||
assert!(mesh[i].normal[2] < 0.0) // Bottom triangles point down.
|
||||
} else if i < (64 + 128) {
|
||||
assert!(mesh[i].normal[2] == 0.0) // side triangles point out.
|
||||
} else {
|
||||
assert!(mesh[i].normal[2] > 0.0) // top triangles point up.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
use cached::proc_macro::cached;
|
||||
use stl_io::{self, Normal, Triangle, Vertex};
|
||||
|
||||
use crate::layers::{Layer, Layers};
|
||||
|
||||
fn new_triangle(p1: &Vertex, p2: &Vertex, p3: &Vertex) -> stl_io::Triangle {
|
||||
// Set Vector U to (Triangle.p2 minus Triangle.p1)
|
||||
// Set Vector V to (Triangle.p3 minus Triangle.p1)
|
||||
|
||||
// Set Normal.x to (multiply U.y by V.z) minus (multiply U.z by V.y)
|
||||
// Set Normal.y to (multiply U.z by V.x) minus (multiply U.x by V.z)
|
||||
// Set Normal.z to (multiply U.x by V.y) minus (multiply U.y by V.x)
|
||||
|
||||
let u = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
|
||||
let v = [p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]];
|
||||
|
||||
let n_x = (u[1] * v[2]) - (u[2] * v[1]);
|
||||
let n_y = (u[2] * v[0]) - (u[0] * v[2]);
|
||||
let n_z = (u[0] * v[1]) - (u[1] * v[0]);
|
||||
|
||||
stl_io::Triangle {
|
||||
normal: Normal::new([n_x, n_y, n_z]),
|
||||
vertices: [*p1, *p2, *p3],
|
||||
}
|
||||
}
|
||||
|
||||
/// Find a point on the cirle at a given angle (in radians).
|
||||
fn vertex_on_circle(center: &Vertex, radius: f32, angle: f32) -> Vertex {
|
||||
let x = center[0] + (radius * angle.cos());
|
||||
let y = center[1] + (radius * angle.sin());
|
||||
let z = center[2];
|
||||
|
||||
Vertex::new([x, y, z])
|
||||
}
|
||||
|
||||
fn vertexes_on_circle(layer: &Layer, steps: u32) -> Vec<Vertex> {
|
||||
let mut result = Vec::with_capacity(steps as usize);
|
||||
let stepsize = std::f64::consts::TAU / steps as f64;
|
||||
|
||||
for i in 0..steps {
|
||||
let angle = (i as f64 * stepsize) as f32;
|
||||
result.push(vertex_on_circle(&layer.center, layer.radius, angle));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn tube_base(center: &Vertex, edge: &[Vertex]) -> Vec<Triangle> {
|
||||
let mut result = Vec::with_capacity(edge.len());
|
||||
|
||||
for i in 0..edge.len() {
|
||||
result.push(new_triangle(center, &edge[(i + 1) % edge.len()], &edge[i]));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn tube_sides(botoom_edge: &[Vertex], top_edge: &[Vertex]) -> Vec<Triangle> {
|
||||
assert_eq!(botoom_edge.len(), top_edge.len());
|
||||
|
||||
let mut result = Vec::with_capacity(2 * botoom_edge.len());
|
||||
|
||||
for i in 0..botoom_edge.len() {
|
||||
let j = (i + 1) % botoom_edge.len();
|
||||
|
||||
result.push(new_triangle(&botoom_edge[i], &top_edge[j], &top_edge[i]));
|
||||
result.push(new_triangle(&botoom_edge[i], &botoom_edge[j], &top_edge[j]));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn tube_top(center: &Vertex, edge: &[Vertex]) -> Vec<Triangle> {
|
||||
// The top is the same, except the normals are reversed. We can do that by reversing the order of the vertexes.
|
||||
let mut edge = edge.to_owned();
|
||||
edge.reverse();
|
||||
|
||||
tube_base(center, &edge)
|
||||
}
|
||||
|
||||
#[cached(key = "String", convert = r#"{ format!("{:?}_{}", layers, resolution) }"#)]
|
||||
pub fn render(layers: &Layers, resolution: f32) -> Vec<Triangle> {
|
||||
// Top and Bottom must be a single point, and must be at least one middle layer.
|
||||
assert!(!layers.layers.is_empty());
|
||||
|
||||
// How many vertexes per circle. IE: the resolution of the circle.
|
||||
let circle_steps =
|
||||
((layers.max_radius() * std::f32::consts::TAU) / resolution).max(64.0) as u32;
|
||||
|
||||
let mut layer_vertexes: Vec<Vec<Vertex>> = Vec::with_capacity(layers.layers.len());
|
||||
|
||||
for layer in &layers.layers {
|
||||
layer_vertexes.push(vertexes_on_circle(layer, circle_steps));
|
||||
}
|
||||
|
||||
// Estimate triangle count: base + sides + top
|
||||
let estimated_triangles = layers.layers.len() * circle_steps as usize * 2;
|
||||
let mut result: Vec<Triangle> = Vec::with_capacity(estimated_triangles);
|
||||
|
||||
result.append(&mut tube_base(&layers.base, &layer_vertexes[0]));
|
||||
for i in 0..layer_vertexes.len() - 1 {
|
||||
result.append(&mut tube_sides(&layer_vertexes[i], &layer_vertexes[i + 1]));
|
||||
}
|
||||
result.append(&mut tube_top(&layers.top, layer_vertexes.last().unwrap()));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use approx::relative_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn new_triangle_normal() {
|
||||
// Simple triangle
|
||||
let a = Vertex::new([1.0, 0.0, 0.0]);
|
||||
let b = Vertex::new([0.0, 1.0, 0.0]);
|
||||
let c = Vertex::new([-1.0, 0.0, 0.0]);
|
||||
|
||||
let tri = new_triangle(&a, &b, &c);
|
||||
|
||||
assert_eq!(tri.normal, Normal::new([0.0, 0.0, 2.0]));
|
||||
|
||||
// Same triangle, reverse order.
|
||||
let tri = new_triangle(&c, &b, &a);
|
||||
|
||||
assert_eq!(tri.normal, Normal::new([0.0, 0.0, -2.0]));
|
||||
|
||||
// Uneven numbers.
|
||||
let a = Vertex::new([2.0, 0.0, 0.0]);
|
||||
let b = Vertex::new([0.0, 3.0, 0.0]);
|
||||
let c = Vertex::new([-4.0, 0.0, 0.0]);
|
||||
|
||||
let tri_big = new_triangle(&a, &b, &c);
|
||||
|
||||
assert_eq!(tri_big.normal, Normal::new([0.0, 0.0, 18.0]));
|
||||
}
|
||||
|
||||
fn validate_vec_vertex_relative_eq(val: &Vec<Vertex>, expected: &Vec<Vertex>) {
|
||||
let mut pass = true;
|
||||
|
||||
if val.len() != expected.len() {
|
||||
pass = false;
|
||||
}
|
||||
|
||||
for i in 0..val.len() {
|
||||
for j in 0..3 {
|
||||
if !relative_eq!(val[i][j], expected[i][j]) {
|
||||
pass = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !pass {
|
||||
// We re-compare here (which will always fail) to get the friendly error message,
|
||||
// which I can't figure out how to generate directly.
|
||||
assert_eq!(val, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vertexes_on_circle_basic() {
|
||||
let val = vertexes_on_circle(
|
||||
&Layer {
|
||||
center: Vertex::new([0.0, 0.0, 0.0]),
|
||||
radius: 1.0,
|
||||
},
|
||||
4,
|
||||
);
|
||||
|
||||
let expected = [
|
||||
Vertex::new([1.0, 0.0, 0.0]),
|
||||
Vertex::new([0.0, 1.0, 0.0]),
|
||||
Vertex::new([-1.0, 0.0, 0.0]),
|
||||
Vertex::new([0.0, -1.0, 0.0]),
|
||||
]
|
||||
.to_vec();
|
||||
|
||||
validate_vec_vertex_relative_eq(&val, &expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vertexes_on_circle_complex() {
|
||||
let val = vertexes_on_circle(
|
||||
&Layer {
|
||||
center: Vertex::new([4.0, 5.0, 6.0]),
|
||||
radius: 3.0,
|
||||
},
|
||||
4,
|
||||
);
|
||||
|
||||
let expected = [
|
||||
Vertex::new([7.0, 5.0, 6.0]),
|
||||
Vertex::new([4.0, 8.0, 6.0]),
|
||||
Vertex::new([1.0, 5.0, 6.0]),
|
||||
Vertex::new([4.0, 2.0, 6.0]),
|
||||
]
|
||||
.to_vec();
|
||||
|
||||
validate_vec_vertex_relative_eq(&val, &expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tube_base_test() {
|
||||
// fn tube_base(center: &Vertex, edge: &Vec<Vertex>) -> Vec<Triangle> {
|
||||
|
||||
let center = Vertex::new([0.0, 0.0, 0.0]);
|
||||
let edge = vertexes_on_circle(
|
||||
&Layer {
|
||||
center: center.clone(),
|
||||
radius: 1.0,
|
||||
},
|
||||
4,
|
||||
);
|
||||
|
||||
let triangles = tube_base(¢er, &edge);
|
||||
|
||||
assert_eq!(triangles.len(), edge.len());
|
||||
|
||||
for t in triangles {
|
||||
// All of these triangles should have the same normal (down).
|
||||
assert_eq!(t.normal, Vertex::new([0.0, 0.0, -1.0]));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tube_top_test() {
|
||||
let center = Vertex::new([0.0, 0.0, 0.0]);
|
||||
let edge = vertexes_on_circle(
|
||||
&Layer {
|
||||
center: center.clone(),
|
||||
radius: 1.0,
|
||||
},
|
||||
4,
|
||||
);
|
||||
|
||||
let triangles = tube_top(¢er, &edge);
|
||||
|
||||
assert_eq!(triangles.len(), edge.len());
|
||||
|
||||
for t in triangles {
|
||||
// All of these triangles should have the same normal (up).
|
||||
assert_eq!(t.normal, Vertex::new([0.0, 0.0, 1.0]));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_test() {
|
||||
let layers = Layers {
|
||||
base: Vertex::new([0.0, 0.0, 0.0]),
|
||||
layers: [
|
||||
Layer {
|
||||
center: Vertex::new([0.0, 0.0, 1.0]),
|
||||
radius: 1.0,
|
||||
},
|
||||
Layer {
|
||||
center: Vertex::new([0.0, 0.0, 2.0]),
|
||||
radius: 1.0,
|
||||
},
|
||||
]
|
||||
.to_vec(),
|
||||
top: Vertex::new([0.0, 0.0, 3.0]),
|
||||
};
|
||||
|
||||
let mesh = render(&layers, 10.0); // Large resolution ensures minimum steps of 64.
|
||||
|
||||
// 64 triangles for top, 128 for sides, 64 for bottom.
|
||||
assert_eq!(mesh.len(), 64 + 128 + 64);
|
||||
|
||||
for i in 0..mesh.len() {
|
||||
if i < 64 {
|
||||
assert!(mesh[i].normal[2] < 0.0) // Bottom triangles point down.
|
||||
} else if i < (64 + 128) {
|
||||
assert!(mesh[i].normal[2] == 0.0) // side triangles point out.
|
||||
} else {
|
||||
assert!(mesh[i].normal[2] > 0.0) // top triangles point up.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user