Skip to content

Instantly share code, notes, and snippets.

@intendednull
Created November 23, 2021 21:49
Show Gist options
  • Save intendednull/40cd183ec0808da8e405a40037760434 to your computer and use it in GitHub Desktop.
Save intendednull/40cd183ec0808da8e405a40037760434 to your computer and use it in GitHub Desktop.
/// Build a mesh for given polygon.
pub fn build_poly(poly: &Poly) -> Mesh {
let count = poly.count();
let mut indices = {
// Collect all vertices
let mut data = poly
.iter()
.map(|v| std::array::IntoIter::new([v.x as f64, v.z as f64]))
.flatten()
.collect::<Vec<_>>();
// Add holes
let mut hole_indicies = Vec::new();
for hole in &poly.holes {
hole_indicies.push(data.len() / 2);
data.extend(
hole.iter()
.map(|v| std::array::IntoIter::new([v.x as f64, v.z as f64]))
.flatten(),
)
}
// Triangulate with earcutr
let mut out = earcut(&data, &hole_indicies, 2)
.into_iter()
// Adjust output for bevy
.map(|i| i as u32)
.rev()
.collect::<Vec<_>>();
// Add indicies for drawing bottom
let mut bottom = out
.iter()
.map(|i| i + count as u32)
.rev()
.collect::<Vec<_>>();
out.append(&mut bottom);
out
};
let mut vertices = {
let vs = poly
.iter()
.chain(poly.holes.iter().flat_map(|hole| hole.iter()));
// Top vertices
let mut data = vs
.clone()
.map(|v| [v.x, v.y + poly.height, v.z])
.collect::<Vec<_>>();
// Bottom vertices
data.extend(vs.map(|v| [v.x, v.y, v.z]));
data
};
let mut normals = {
// Normals for top
let mut data = vec![[0., 1., 0.]; count];
// Normals for bottom
data.extend(std::iter::repeat([0., -1., 0.]).take(count));
data
};
// TODO: What should these be?
let mut uvs = vec![[0., 0.]; count * 2];
// Draw the sides
let mut draw_side = |(v1, v2): (Vec3, Vec3), hole: bool| {
let pos = vertices.len() as u32;
// Add vertices
// IMPORTANT: Order matters! Don't rearrange without updating how they're drawn with
// indices below.
vertices.push([v1.x, v1.y + poly.height, v1.z]); // Top
vertices.push([v1.x, v1.y, v1.z]); // Bottom
vertices.push([v2.x, v2.y + poly.height, v2.z]); // Top
vertices.push([v2.x, v2.y, v2.z]); // Bottom
// Add indices
//
// If sides are inside a hole, they should face inwards.
if hole {
indices.push(pos + 3); // v2 bottom
indices.push(pos + 1); // v1 bottom
indices.push(pos); // v1 top
indices.push(pos); // v1 top
indices.push(pos + 2); // v2 top
indices.push(pos + 3); // v2 bottom
normals.extend({
let normal: [f32; 3] = (-(v2 - v1).as_2d().perp().normalize().as_3d()).into();
std::iter::repeat(normal).take(4)
});
// Otherwise they should face outwards.
} else {
indices.push(pos); // v1 top
indices.push(pos + 1); // v1 bottom
indices.push(pos + 3); // v2 bottom
indices.push(pos + 3); // v2 bottom
indices.push(pos + 2); // v2 top
indices.push(pos); // v1 top
normals.extend({
let normal: [f32; 3] = (v2 - v1).as_2d().perp().normalize().as_3d().into();
std::iter::repeat(normal).take(4)
});
}
// Add uvs
uvs.extend(std::iter::repeat([0., 0.]).take(4));
};
for side in poly.borders() {
draw_side(side, false);
}
for hole in poly.holes.iter() {
for side in hole.borders() {
draw_side(side, true);
}
}
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
mesh.set_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
mesh.set_attribute(Mesh::ATTRIBUTE_POSITION, vertices);
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
mesh.set_indices(Some(Indices::U32(indices)));
mesh
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment