1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
use crate::*;
/// # Mesh Buffer (GPU/realtime) Helpers
impl Polyhedron {
/// Returns a flat [`u32`] triangle index buffer and two matching point and
/// normal buffers.
///
/// This is mostly useful for realtime rendering, e.g. sending data to a
/// GPU.
///
/// All the faces are disconnected. I.e. positions & normals are duplicated
/// for each shared vertex.
pub fn to_triangle_mesh_buffers(&self) -> (Vec<u32>, Points, Normals) {
let (positions, normals): (Vec<_>, Vec<_>) = self
.face_index
.par_iter()
.flat_map(|face| {
face.iter()
// Cycle forever.
.cycle()
// Start at 3-tuple belonging to the
// face's last vertex.
.skip(face.len() - 1)
// Grab the next three vertex index
// entries.
.tuple_windows::<(_, _, _)>()
.take(face.len())
.map(|t| {
// The middle point of out tuple
let point = self.positions[*t.1 as usize];
// Create a normal from that
let normal = -orthogonal(
&self.positions[*t.0 as usize],
&point,
&self.positions[*t.2 as usize],
);
let mag_sq = normal.mag_sq();
(
point,
// Check for collinearity:
if mag_sq < EPSILON as _ {
average_normal_ref(&index_as_positions(
face,
self.positions(),
))
.unwrap()
} else {
normal / mag_sq.sqrt()
},
)
})
// For each vertex of the face.
.collect::<Vec<_>>()
})
.unzip();
// Build a new face index. Same topology as the old one, only with new
// keys.
let triangle_face_index = self
.face_index
.iter()
// Build a new index where each face has the original arity and the
// new numbering.
.scan(0.., |counter, face| {
Some(counter.take(face.len()).collect::<Vec<u32>>())
})
// Now split each of these faces into triangles.
.flat_map(|face| match face.len() {
// Filter out degenerate faces.
1 | 2 => vec![],
// Bitriangulate quadrilateral faces use shortest diagonal so
// triangles are most nearly equilateral.
4 => {
let p = index_as_positions(face.as_slice(), &positions);
if (*p[0] - *p[2]).mag_sq() < (*p[1] - *p[3]).mag_sq() {
vec![
face[0], face[1], face[2], face[0], face[2],
face[3],
]
} else {
vec![
face[1], face[2], face[3], face[1], face[3],
face[0],
]
}
}
5 => vec![
face[0], face[1], face[4], face[1], face[2], face[4],
face[4], face[2], face[3],
],
// FIXME: a nicer way to triangulate n-gons.
_ => {
let a = face[0];
let mut bb = face[1];
face.iter()
.skip(2)
.flat_map(|c| {
let b = bb;
bb = *c;
vec![a, b, *c]
})
.collect()
}
})
.collect();
(triangle_face_index, positions, normals)
}
}